Source File modules/th/thread.c

    1    | /***************************************
    2    |   $Revision: 1.8 $
    3    |
    4    |   Example code: A thread.
    5    |
    6    |   Status: NOT REVUED, NOT TESTED
    7    |
    8    |  Authors:       Chris Ottrey
    9    | 		Joao Damas
    10   |
    11   |   +html+ <DL COMPACT>
    12   |   +html+ <DT>Online References:
    13   |   +html+ <DD><UL>
    14   |   +html+ </UL>
    15   |   +html+ </DL>
    16   |
    17   |   ******************/ /******************
    18   |   Modification History:
    19   |         ottrey (02/03/1999) Created.
    20   |         ottrey (08/03/1999) Modified.
    21   |         ottrey (17/06/1999) Stripped down.
    22   |         joao   (22/06/1999) Redid thread startup
    23   |   ******************/ /******************
    24   |   Copyright (c) 1999                              RIPE NCC
    25   |
    26   |   All Rights Reserved
    27   |
    28   |   Permission to use, copy, modify, and distribute this software and its
    29   |   documentation for any purpose and without fee is hereby granted,
    30   |   provided that the above copyright notice appear in all copies and that
    31   |   both that copyright notice and this permission notice appear in
    32   |   supporting documentation, and that the name of the author not be
    33   |   used in advertising or publicity pertaining to distribution of the
    34   |   software without specific, written prior permission.
    35   |
    36   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    37   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    38   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    39   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    40   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    41   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    42   |   ***************************************/
    43   | #include "thread.h"
    44   | #include <stdio.h>
    45   | #include "protocol_config.h"
    46   | #include "constants.h"
    47   |
    48   | /*+ String sizes +*/
    49   | #define STR_S   63
    50   | #define STR_M   255
    51   | #define STR_L   1023
    52   | #define STR_XL  4095
    53   | #define STR_XXL 16383
    54   |
    55   | /*+ Mutex lock.  Used for synchronizing changes. +*/
    56   | pthread_mutex_t   Whois_thread_count_lock;
    57   | pthread_mutex_t   Config_thread_count_lock;
    58   | pthread_mutex_t   Mirror_thread_count_lock;
    59   |
    60   | /*+ The number of threads. +*/
    61   | int       Whois_thread_count;
    62   | int       Config_thread_count;
    63   | int       Mirror_thread_count;
    64   |
    65   | typedef struct th_args {
    66   | 	void * function;
    67   | 	int sock;
    68   | } th_args;
    69   |
    70   | static void log_print(const char *arg) {
    71   |   FILE *logf;
    72   |   char *str;
    73   |
    74   |   if (CO_get_thread_logging() == 1) {
    75   |     if (strcmp(CO_get_thread_logfile(), "stdout") == 0) {
    76   |       printf(arg);
    77   |     }
    78   |     else {
    79   |       logf = fopen(CO_get_thread_logfile(), "a");
    80   |       fprintf(logf, arg);
    81   |       fclose(logf);
    82   |     }
    83   |   }
    84   |
    85   | } /* log_print() */
    86   |
    87   | /* TH_acquire_read_lock() */
    88   | /*++++++++++++++++++++++++++++++++++++++
    89   |
    90   |   Aquire a readers lock.
    91   |
    92   |   rw_lock_t *prw_lock Readers writers lock.
    93   |
    94   |   Reference: "Multithreaded Programming Techniques - Prasad p.192"
    95   |   More:
    96   |   +html+ <PRE>
    97   |   Author:
    98   |         ottrey
    99   |   +html+ </PRE>
    100  |   ++++++++++++++++++++++++++++++++++++++*/
    101  | void TH_acquire_read_lock(rw_lock_t *prw_lock) {
    102  |   pthread_mutex_lock(&prw_lock->rw_mutex);
    103  |
    104  |   while (prw_lock->rw_count < 0) {
    105  |     pthread_cond_wait(&prw_lock->rw_cond, &prw_lock->rw_mutex);
    106  |   }
    107  |
    108  |   ++prw_lock->rw_count;
    109  |   pthread_mutex_unlock(&prw_lock->rw_mutex);
    110  |
    111  | } /* TH_acquire_read_lock() */
    112  |
    113  | /* TH_release_read_lock() */
    114  | /*++++++++++++++++++++++++++++++++++++++
    115  |
    116  |   Release a readers lock.
    117  |
    118  |   rw_lock_t *prw_lock Readers writers lock.
    119  |
    120  |   Reference: "Multithreaded Programming Techniques - Prasad p.192"
    121  |   More:
    122  |   +html+ <PRE>
    123  |   Author:
    124  |         ottrey
    125  |   +html+ </PRE>
    126  |   ++++++++++++++++++++++++++++++++++++++*/
    127  | void TH_release_read_lock(rw_lock_t *prw_lock) {
    128  |   pthread_mutex_lock(&prw_lock->rw_mutex);
    129  |
    130  |   --prw_lock->rw_count;
    131  |
    132  |   if (!prw_lock->rw_count) {
    133  |     pthread_cond_signal(&prw_lock->rw_cond);
    134  |   }
    135  |
    136  |   pthread_mutex_unlock(&prw_lock->rw_mutex);
    137  |
    138  | } /* TH_release_read_lock() */
    139  |
    140  | /* TH_acquire_write_lock() */
    141  | /*++++++++++++++++++++++++++++++++++++++
    142  |
    143  |   Aquire a writers lock.
    144  |
    145  |   rw_lock_t *prw_lock Readers writers lock.
    146  |
    147  |   Reference: "Multithreaded Programming Techniques - Prasad p.192"
    148  |   More:
    149  |   +html+ <PRE>
    150  |   Author:
    151  |         ottrey
    152  |   +html+ </PRE>
    153  |   ++++++++++++++++++++++++++++++++++++++*/
    154  | void TH_acquire_write_lock(rw_lock_t *prw_lock) {
    155  |   pthread_mutex_lock(&prw_lock->rw_mutex);
    156  |
    157  |   while (prw_lock->rw_count != 0) {
    158  |     pthread_cond_wait(&prw_lock->rw_cond, &prw_lock->rw_mutex);
    159  |   }
    160  |
    161  |   prw_lock->rw_count = -1;
    162  |   pthread_mutex_unlock(&prw_lock->rw_mutex);
    163  |
    164  | } /* TH_acquire_write_lock() */
    165  |
    166  | /* TH_release_write_lock() */
    167  | /*++++++++++++++++++++++++++++++++++++++
    168  |
    169  |   Release a writers lock.
    170  |
    171  |   rw_lock_t *prw_lock Readers writers lock.
    172  |
    173  |   Reference: "Multithreaded Programming Techniques - Prasad p.192"
    174  |   More:
    175  |   +html+ <PRE>
    176  |   Author:
    177  |         ottrey
    178  |   +html+ </PRE>
    179  |   ++++++++++++++++++++++++++++++++++++++*/
    180  | void TH_release_write_lock(rw_lock_t *prw_lock) {
    181  |   pthread_mutex_lock(&prw_lock->rw_mutex);
    182  |   prw_lock->rw_count = 0;
    183  |   pthread_mutex_unlock(&prw_lock->rw_mutex);
    184  |   pthread_cond_broadcast(&prw_lock->rw_cond);
    185  |
    186  | } /* TH_release_write_lock() */
    187  |
    188  | /* TH_init_read_write_lock() */
    189  | /*++++++++++++++++++++++++++++++++++++++
    190  |
    191  |   Initialize a readers/writers lock.
    192  |
    193  |   rw_lock_t *prw_lock Readers writers lock.
    194  |
    195  |   Side effect: the lock is set to open(?)
    196  |
    197  |   Reference: "Multithreaded Programming Techniques - Prasad p.192"
    198  |   More:
    199  |   +html+ <PRE>
    200  |   Author:
    201  |         ottrey
    202  |   +html+ </PRE>
    203  |   ++++++++++++++++++++++++++++++++++++++*/
    204  | void TH_init_read_write_lock(rw_lock_t *prw_lock) {
    205  |   mutex_init(&prw_lock->rw_mutex, NULL);
    206  |   cond_init(&prw_lock->rw_cond, NULL);
    207  |   prw_lock->rw_count = 0;
    208  |
    209  | } /* TH_init_read_write_lock() */
    210  |
    211  | int TH_get_id(void) {
    212  |
    213  |   return (int)pthread_self();
    214  |
    215  | } /* TH_get_id() */
    216  |
    217  | /* TH_to_string() */
    218  | char *TH_to_string(void) {
    219  |   char *thread_info;
    220  |   char tmp[STR_L];
    221  |   char thread_info_buffer[STR_XL];
    222  |   char *thread_name;
    223  |
    224  |   strcpy(thread_info_buffer, "Thread = { ");
    225  |
    226  |   sprintf(tmp, "[pthread_self] = \"%d\" ", pthread_self());
    227  |   strcat(thread_info_buffer, tmp);
    228  |
    229  |   /*
    230  |   thread_name = (char *)pthread_getspecific(Name);
    231  |
    232  |   if (thread_name == NULL ) {
    233  |     sprintf(tmp, "[Name] = \"%s\" ", "didn't work!");
    234  |   }
    235  |   else {
    236  |     sprintf(tmp, "[Name] = \"%s\" ", thread_name);
    237  |   }
    238  |   strcat(thread_info_buffer, tmp);
    239  |   */
    240  |
    241  |   strcat(thread_info_buffer, "}");
    242  |
    243  |   thread_info = (char *)calloc(1, strlen(thread_info_buffer)+1);
    244  |   strcpy(thread_info, thread_info_buffer);
    245  |
    246  |   return thread_info;
    247  | } /* TH_to_string() */
    248  |
    249  | /* TH_do_whois() */
    250  | /*++++++++++++++++++++++++++++++++++++++
    251  |
    252  |   Handle whois connections.
    253  |
    254  |   void *arg The socket to connect to. (It has to be passed in this way for this thread routine.)
    255  |
    256  |   More:
    257  |   +html+ <PRE>
    258  |   Author:
    259  |         joao
    260  |   +html+ </PRE>
    261  |   ++++++++++++++++++++++++++++++++++++++*/
    262  | void TH_do_whois(void *arg) {
    263  |   int sock = (int)arg;
    264  |   char print_buf[STR_M];
    265  |
    266  |   sprintf(print_buf, "Whois: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, "");
    267  |
    268  |   /* Use a mutex to update the global whois thread counter. */
    269  |   pthread_mutex_lock(&Whois_thread_count_lock);
    270  |   Whois_thread_count++;
    271  |   sprintf(print_buf, "Whois_thread_count++=%d\n", Whois_thread_count); log_print(print_buf); strcpy(print_buf, "");
    272  |   pthread_mutex_unlock(&Whois_thread_count_lock);
    273  |
    274  |   PW_interact(sock);
    275  |
    276  |   /* Use a mutex to update the global whois thread counter. */
    277  |   pthread_mutex_lock(&Whois_thread_count_lock);
    278  |   Whois_thread_count--;
    279  |   sprintf(print_buf, "Whois_thread_count--=%d\n", Whois_thread_count); log_print(print_buf); strcpy(print_buf, "");
    280  |   pthread_mutex_unlock(&Whois_thread_count_lock);
    281  |
    282  |   pthread_exit((void *)0);
    283  |
    284  | } /* TH_do_whois() */
    285  |
    286  | /* TH_do_config() */
    287  | /*++++++++++++++++++++++++++++++++++++++
    288  |
    289  |   Handle config connections.
    290  |
    291  |   void *arg The socket to connect to. (It has to be passed in this way for this
    292  | thread routine.)
    293  |
    294  |   More:
    295  |   +html+ <PRE>
    296  |   Author:
    297  |         joao
    298  |   +html+ </PRE>
    299  |   ++++++++++++++++++++++++++++++++++++++*/
    300  | void TH_do_config(void *arg) {
    301  |   int sock = (int)arg;
    302  |   char print_buf[STR_M];
    303  |
    304  |   sprintf(print_buf, "Config: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, "");
    305  |
    306  | /*
    307  |   printf("Hi there, there is nothing to configure yet\nBye..... :-)\n");
    308  |   fflush(NULL);
    309  |
    310  |   SK_close(sock);
    311  | */
    312  |   PC_interact(sock);
    313  |
    314  |   pthread_exit((void *)0);
    315  |
    316  | } /* TH_do_config() */
    317  |
    318  | /* main_thread() */
    319  | /*++++++++++++++++++++++++++++++++++++++
    320  |
    321  |   Waits for an incoming connection on the and spawns a new thread to handle it.
    322  |
    323  |   void *arg Pointer to a struct containing the socket to talk to the client and
    324  |             the function to call depending on the incoming connection.
    325  |
    326  |   More:
    327  |   +html+ <PRE>
    328  |   Author:
    329  |         ottrey
    330  | 	joao
    331  |   +html+ </PRE>
    332  |   ++++++++++++++++++++++++++++++++++++++*/
    333  | static void  *main_thread(void *arg) {
    334  |   th_args *args = (th_args *)arg;
    335  |   pthread_t tid;
    336  |   pthread_attr_t attr;
    337  |   int connected_socket;
    338  |
    339  |   while(1) {
    340  |
    341  |     connected_socket = SK_accept_connection(args->sock);
    342  |
    343  |     /* Start a new thread. */
    344  |
    345  |     pthread_attr_init(&attr);    /* initialize attr with default attributes */
    346  |     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    347  |     pthread_create(&tid, &attr, (void *(*)(void *))(args->function), (void *)connected_socket);
    348  |   }
    349  |
    350  | } /* main_thread() */
    351  |
    352  | /* TH_run() */
    353  | /*++++++++++++++++++++++++++++++++++++++
    354  |
    355  |   This is the routine that creates the main threads.
    356  |
    357  |   int     sock        The socket to connect to.
    358  |   void *  do_function The function to call for each type of service
    359  |
    360  |   More:
    361  |   +html+ <PRE>
    362  |   Author:
    363  |         ottrey
    364  | 	joao
    365  |   +html+ </PRE>
    366  |   ++++++++++++++++++++++++++++++++++++++*/
    367  | void TH_run(int sock, void *do_function) {
    368  |   th_args *args;
    369  |   pthread_t tid;
    370  |   pthread_attr_t attr;
    371  |   char print_buf[STR_M];
    372  |
    373  |   int connected_socket;
    374  |
    375  |   args = (th_args *)calloc(1,sizeof(th_args));
    376  |   args->function=do_function;
    377  |   args->sock=sock;
    378  |
    379  | /*  pthread_mutex_init(&Whois_thread_count_lock,NULL); */
    380  |
    381  |   if ( CO_get_max_threads() == 0 ) {
    382  |     sprintf(print_buf, "Running with no threads\n"); log_print(print_buf); strcpy(print_buf, "");
    383  |     connected_socket = SK_accept_connection(sock);
    384  |     PW_interact(connected_socket);
    385  |   }
    386  |   else {
    387  |     /* Start a new thread. */
    388  |     pthread_attr_init(&attr);     /* initialize attr with default attributes */
    389  |     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    390  |     pthread_create(&tid, &attr, main_thread, (void *)args);
    391  |   }
    392  |
    393  | } /* TH_run() */
    394  |
    395  | void TH_run2(void *function) {
    396  |   pthread_t tid;
    397  |   pthread_attr_t attr;
    398  |
    399  |   /* Start a new thread. */
    400  |   pthread_attr_init(&attr);     /* initialize attr with default attributes */
    401  |   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    402  |   pthread_create(&tid, &attr, function, (void *)0);
    403  |
    404  | } /* TH_run2() */