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