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() */