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