"Fossies" - the Fresh Open Source Software Archive

Member "ettercap-0.8.3.1/src/ec_threads.c" (1 Aug 2020, 10284 Bytes) of package /linux/privat/ettercap-0.8.3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ec_threads.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.8.3_vs_0.8.3.1.

    1 /*
    2     ettercap -- thread handling
    3 
    4     Copyright (C) ALoR & NaGA
    5 
    6     This program is free software; you can redistribute it and/or modify
    7     it under the terms of the GNU General Public License as published by
    8     the Free Software Foundation; either version 2 of the License, or
    9     (at your option) any later version.
   10 
   11     This program is distributed in the hope that it will be useful,
   12     but WITHOUT ANY WARRANTY; without even the implied warranty of
   13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14     GNU General Public License for more details.
   15 
   16     You should have received a copy of the GNU General Public License
   17     along with this program; if not, write to the Free Software
   18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   19 
   20 */
   21 
   22 #include <ec.h>
   23 #include <ec_threads.h>
   24 
   25 #include <pthread.h>
   26 #include <errno.h>
   27 
   28 struct thread_list {
   29    struct ec_thread t;
   30    LIST_ENTRY (thread_list) next;
   31 };
   32 
   33 
   34 /* global data */
   35 
   36 /* a value to be used to return errors in fuctcions using pthread_t values */
   37 static pthread_t EC_PTHREAD_NULL = 0;
   38 #define EC_PTHREAD_SELF EC_PTHREAD_NULL
   39 
   40 #define DETACHED_THREAD 1
   41 #define JOINABLE_THREAD 0
   42 
   43 static LIST_HEAD(, thread_list) thread_list_head;
   44 
   45 static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
   46 #define THREADS_LOCK     do{ pthread_mutex_lock(&threads_mutex); } while(0)
   47 #define THREADS_UNLOCK   do{ pthread_mutex_unlock(&threads_mutex); } while(0)
   48 
   49 static pthread_mutex_t init_mtx = PTHREAD_MUTEX_INITIALIZER;
   50 static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER;
   51 #define INIT_LOCK     do{ DEBUG_MSG("thread_init_lock"); pthread_mutex_lock(&init_mtx); } while(0)
   52 #define INIT_UNLOCK   do{ DEBUG_MSG("thread_init_unlock"); pthread_mutex_unlock(&init_mtx); } while(0)
   53 
   54 /* protos... */
   55 
   56 pthread_t ec_thread_detached(char *name, char *desc, void *(*function)(void *), void *args, int detached);
   57 
   58 /*******************************************/
   59 
   60 /* returns the name of a thread */
   61 
   62 char * ec_thread_getname(pthread_t id)
   63 {
   64    struct thread_list *current;
   65    char *name;
   66 
   67    if (pthread_equal(id, EC_PTHREAD_SELF))
   68       id = pthread_self();
   69 
   70    /* don't lock here to avoid deadlock in debug messages */
   71 #ifndef DEBUG   
   72    THREADS_LOCK;
   73 #endif
   74    
   75    LIST_FOREACH(current, &thread_list_head, next) {
   76       if (pthread_equal(current->t.id, id)) {
   77          name = current->t.name;
   78 #ifndef DEBUG
   79          THREADS_UNLOCK;
   80 #endif
   81          return name;
   82       }
   83    }
   84    
   85 #ifndef DEBUG
   86    THREADS_UNLOCK;
   87 #endif
   88 
   89    return "NR_THREAD";
   90 }
   91 
   92 /* 
   93  * returns the pid of a thread 
   94  * ZERO if not found !! (take care, not -E_NOTFOUND !)
   95  */
   96 
   97 pthread_t ec_thread_getpid(char *name)
   98 {
   99    struct thread_list *current;
  100    pthread_t pid;
  101 
  102    /*
  103     * if "name" is explicitely set up NULL, the top-level pthread_t 
  104     * is returned w/o iterating through the thread-list
  105     */
  106    if (name == NULL)
  107       return EC_PTHREAD_NULL;
  108    
  109    THREADS_LOCK;
  110 
  111    LIST_FOREACH(current, &thread_list_head, next) {
  112       if (!strcasecmp(current->t.name,name)) {
  113          pid = current->t.id;
  114          THREADS_UNLOCK;
  115          return pid;
  116       }
  117    }
  118 
  119    THREADS_UNLOCK;
  120   
  121    return EC_PTHREAD_NULL;
  122 }
  123 
  124 /* returns the description of a thread */
  125 
  126 char * ec_thread_getdesc(pthread_t id)
  127 {
  128    struct thread_list *current;
  129    char *desc;
  130 
  131    if (pthread_equal(id, EC_PTHREAD_SELF))
  132       id = pthread_self();
  133   
  134    THREADS_LOCK;
  135    
  136    LIST_FOREACH(current, &thread_list_head, next) {
  137       if (pthread_equal(current->t.id, id)) {
  138          desc = current->t.description;
  139          THREADS_UNLOCK;
  140          return desc;
  141       }
  142    }
  143    
  144    THREADS_UNLOCK;
  145    
  146    return "";
  147 }
  148 
  149 
  150 /* add a thread in the thread list */
  151 void ec_thread_register(pthread_t id, char *name, char *desc)
  152 {
  153    ec_thread_register_detached(id, name, desc, JOINABLE_THREAD);
  154 }
  155 
  156 void ec_thread_register_detached(pthread_t id, char *name, char *desc, int detached)
  157 {
  158    struct thread_list *current, *newelem;
  159 
  160    if (pthread_equal(id, EC_PTHREAD_SELF))
  161       id = pthread_self();
  162    
  163    DEBUG_MSG("ec_thread_register -- [%lu] %s", PTHREAD_ID(id), name);
  164 
  165    SAFE_CALLOC(newelem, 1, sizeof(struct thread_list));
  166               
  167    newelem->t.id = id;
  168    newelem->t.name = strdup(name);
  169    newelem->t.description = strdup(desc);
  170    newelem->t.detached = detached;
  171 
  172    THREADS_LOCK;
  173    
  174    LIST_FOREACH(current, &thread_list_head, next) {
  175       if (pthread_equal(current->t.id, id)) {
  176          SAFE_FREE(current->t.name);
  177          SAFE_FREE(current->t.description);
  178          LIST_REPLACE(current, newelem, next);
  179          SAFE_FREE(current);
  180          THREADS_UNLOCK;
  181          return;
  182       }
  183    }
  184 
  185    LIST_INSERT_HEAD(&thread_list_head, newelem, next);
  186    
  187    THREADS_UNLOCK;
  188    
  189 }
  190 
  191 /*
  192  * creates a new thread on the given function
  193  */
  194 
  195 pthread_t ec_thread_new(char *name, char *desc, void *(*function)(void *), void *args) {
  196    return ec_thread_new_detached(name, desc, function, args, JOINABLE_THREAD);
  197 }
  198 
  199 pthread_t ec_thread_new_detached(char *name, char *desc, void *(*function)(void *), void *args, int detached)
  200 {
  201    pthread_t id;
  202    int e;
  203 
  204    DEBUG_MSG("ec_thread_new -- %s detached %d", name, detached);
  205 
  206    /* 
  207     * lock the mutex to syncronize with the new thread.
  208     * the newly created thread will call ec_thread_init(),
  209     * so at the end of this function we are sure that the 
  210     * thread had be initialized
  211     */
  212    INIT_LOCK; 
  213 
  214    if (detached == DETACHED_THREAD) {
  215       pthread_attr_t attr;
  216       pthread_attr_init(&attr);
  217       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  218       if ((e = pthread_create(&id, &attr, function, args)) != 0)
  219          ERROR_MSG("not enough resources to create a new thread in this process: %s", strerror(e));
  220    }else {
  221       if ((e = pthread_create(&id, NULL, function, args)) != 0)
  222          ERROR_MSG("not enough resources to create a new thread in this process: %s", strerror(e));
  223    }
  224 
  225    ec_thread_register_detached(id, name, desc, detached);
  226 
  227    DEBUG_MSG("ec_thread_new -- %lu created ", PTHREAD_ID(id));
  228 
  229    if ((e = pthread_cond_wait(&init_cond, &init_mtx)))
  230       ERROR_MSG("waiting on init_cond: %s", strerror(e));
  231    INIT_UNLOCK;
  232    
  233    return id;
  234 }
  235 
  236 /* 
  237  * set the state of a thread 
  238  * all the new thread MUST call this on startup
  239  */
  240 void ec_thread_init(void)
  241 {
  242    pthread_t id = pthread_self();
  243    int e;
  244    
  245    DEBUG_MSG("ec_thread_init -- %lu", PTHREAD_ID(id));
  246 
  247    INIT_LOCK;
  248    
  249    /* 
  250     * allow a thread to be cancelled as soon as the
  251     * cancellation  request  is received
  252     */
  253    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  254    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  255 
  256    /* sync with the creator */ 
  257    if ((e = pthread_cond_signal(&init_cond)))
  258       ERROR_MSG("raising init_cond: %s", strerror(e));
  259    INIT_UNLOCK;
  260    
  261    DEBUG_MSG("ec_thread_init -- (%lu) ready and syncronized",  PTHREAD_ID(id));
  262 }
  263 
  264 /*
  265  * destroy a thread in the list
  266  */
  267 void ec_thread_destroy(pthread_t id)
  268 {
  269    struct thread_list *current;
  270 
  271    if (pthread_equal(id, EC_PTHREAD_SELF))
  272       id = pthread_self();
  273    
  274    DEBUG_MSG("ec_thread_destroy -- terminating %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
  275 
  276 
  277    /* send the cancel signal to the thread */
  278    pthread_cancel((pthread_t)id);
  279 
  280 
  281    DEBUG_MSG("ec_thread_destroy -- [%s] terminated", ec_thread_getname(id));
  282    
  283    THREADS_LOCK;
  284    
  285    LIST_FOREACH(current, &thread_list_head, next) {
  286       if (pthread_equal(current->t.id, id)) {
  287 #ifndef BROKEN_PTHREAD_JOIN
  288          if (!current->t.detached) {
  289             DEBUG_MSG("ec_thread_destroy: pthread_join");
  290             /* wait until it has finished */
  291             pthread_join((pthread_t)id, NULL);
  292          }
  293 #endif         
  294          SAFE_FREE(current->t.name);
  295          SAFE_FREE(current->t.description);
  296          LIST_REMOVE(current, next);
  297          SAFE_FREE(current);
  298          THREADS_UNLOCK;
  299          return;
  300       }
  301    }
  302 
  303    THREADS_UNLOCK;
  304 
  305 }
  306 
  307 
  308 /*
  309  * kill all the registerd thread but
  310  * the calling one
  311  */
  312 
  313 void ec_thread_kill_all(void)
  314 {
  315    struct thread_list *current, *old;
  316    pthread_t id = pthread_self();
  317 
  318    DEBUG_MSG("ec_thread_kill_all -- caller %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
  319 
  320    THREADS_LOCK;
  321 
  322 #ifdef OS_WINDOWS
  323    /* prevent hanging UI. Not sure how this works, but it does... */
  324    if (EC_GBL_IFACE->pcap)
  325       ec_win_pcap_stop(EC_GBL_IFACE->pcap);
  326 #endif
  327    
  328    LIST_FOREACH_SAFE(current, &thread_list_head, next, old) {
  329       /* skip ourself */
  330       if (!pthread_equal(current->t.id, id)) {
  331          DEBUG_MSG("ec_thread_kill_all -- terminating %lu [%s]", PTHREAD_ID(current->t.id), current->t.name);
  332 
  333          /* send the cancel signal to the thread */
  334          pthread_cancel((pthread_t)current->t.id);
  335          
  336 #ifndef BROKEN_PTHREAD_JOIN
  337          if (!current->t.detached) {
  338             DEBUG_MSG("ec_thread_destroy: pthread_join");
  339             /* wait until it has finished */
  340             pthread_join(current->t.id, NULL);
  341          }
  342 #endif         
  343 
  344          DEBUG_MSG("ec_thread_kill_all -- [%s] terminated", current->t.name);
  345       
  346          SAFE_FREE(current->t.name);
  347          SAFE_FREE(current->t.description);
  348          LIST_REMOVE(current, next);
  349          SAFE_FREE(current);
  350       }
  351    }
  352    
  353    THREADS_UNLOCK;
  354 }
  355 
  356 /*
  357  * used by a thread that wants to terminate itself
  358  */
  359 void ec_thread_exit(void)
  360 {
  361    struct thread_list *current, *old;
  362    pthread_t id = pthread_self();
  363 
  364    DEBUG_MSG("ec_thread_exit -- caller %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
  365 
  366    THREADS_LOCK;
  367    
  368    LIST_FOREACH_SAFE(current, &thread_list_head, next, old) {
  369       /* delete our entry */
  370       if (pthread_equal(current->t.id, id)) {
  371 
  372       /* thread is attempting to shut down on its own, check and see if the thread is detached,
  373          if not set is as a detached thread since when a thread calls this method, there is no thread
  374          that will do the pthread_join to force it to release all of its resources */
  375          if (!current->t.detached) {
  376             pthread_detach(id);
  377          }
  378 
  379          SAFE_FREE(current->t.name);
  380          SAFE_FREE(current->t.description);
  381          LIST_REMOVE(current, next);
  382          SAFE_FREE(current);
  383       }
  384    }
  385 
  386    THREADS_UNLOCK;
  387 
  388    /* perform a clean exit of the thread */
  389    pthread_exit(0);
  390    
  391 }
  392 
  393 /* EOF */
  394 
  395 // vim:ts=3:expandtab
  396