1/* 2 Unix SMB/CIFS implementation. 3 4 thread model: standard (1 thread per client connection) 5 6 Copyright (C) Andrew Tridgell 2003-2005 7 Copyright (C) James J Myers 2003 <myersjj@samba.org> 8 Copyright (C) Stefan (metze) Metzmacher 2004 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program. If not, see <http://www.gnu.org/licenses/>. 22*/ 23 24#include "includes.h" 25#include "version.h" 26#include <pthread.h> 27#ifdef HAVE_BACKTRACE 28#include <execinfo.h> 29#endif 30#include "system/wait.h" 31#include "system/filesys.h" 32#include "lib/events/events.h" 33#include "lib/util/dlinklist.h" 34#include "lib/util/mutex.h" 35#include "smbd/process_model.h" 36 37static pthread_key_t title_key; 38 39struct new_conn_state { 40 struct tevent_context *ev; 41 struct socket_context *sock; 42 struct loadparm_context *lp_ctx; 43 void (*new_conn)(struct tevent_context *, struct loadparm_context *lp_ctx, struct socket_context *, uint32_t , void *); 44 void *private_data; 45}; 46 47static void *thread_connection_fn(void *thread_parm) 48{ 49 struct new_conn_state *new_conn = talloc_get_type(thread_parm, struct new_conn_state); 50 51 new_conn->new_conn(new_conn->ev, new_conn->lp_ctx, new_conn->sock, pthread_self(), new_conn->private_data); 52 53 /* run this connection from here */ 54 event_loop_wait(new_conn->ev); 55 56 talloc_free(new_conn); 57 58 return NULL; 59} 60 61/* 62 called when a listening socket becomes readable 63*/ 64static void thread_accept_connection(struct tevent_context *ev, 65 struct loadparm_context *lp_ctx, 66 struct socket_context *sock, 67 void (*new_conn)(struct tevent_context *, 68 struct loadparm_context *, 69 struct socket_context *, 70 uint32_t , void *), 71 void *private_data) 72{ 73 NTSTATUS status; 74 int rc; 75 pthread_t thread_id; 76 pthread_attr_t thread_attr; 77 struct new_conn_state *state; 78 struct tevent_context *ev2; 79 80 ev2 = s4_event_context_init(ev); 81 if (ev2 == NULL) return; 82 83 state = talloc(ev2, struct new_conn_state); 84 if (state == NULL) { 85 talloc_free(ev2); 86 return; 87 } 88 89 state->new_conn = new_conn; 90 state->private_data = private_data; 91 state->lp_ctx = lp_ctx; 92 state->ev = ev2; 93 94 /* accept an incoming connection. */ 95 status = socket_accept(sock, &state->sock); 96 if (!NT_STATUS_IS_OK(status)) { 97 talloc_free(ev2); 98 /* We need to throttle things until the system clears 99 enough resources to handle this new socket. If we 100 don't then we will spin filling the log and causing 101 more problems. We don't panic as this is probably a 102 temporary resource constraint */ 103 sleep(1); 104 return; 105 } 106 107 talloc_steal(state, state->sock); 108 109 pthread_attr_init(&thread_attr); 110 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); 111 rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, state); 112 pthread_attr_destroy(&thread_attr); 113 if (rc == 0) { 114 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", 115 (unsigned long int)thread_id, socket_get_fd(sock))); 116 } else { 117 DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", socket_get_fd(sock), rc)); 118 talloc_free(ev2); 119 } 120} 121 122 123struct new_task_state { 124 struct tevent_context *ev; 125 struct loadparm_context *lp_ctx; 126 void (*new_task)(struct tevent_context *, struct loadparm_context *, 127 uint32_t , void *); 128 void *private_data; 129}; 130 131static void *thread_task_fn(void *thread_parm) 132{ 133 struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state); 134 135 new_task->new_task(new_task->ev, new_task->lp_ctx, pthread_self(), 136 new_task->private_data); 137 138 /* run this connection from here */ 139 event_loop_wait(new_task->ev); 140 141 talloc_free(new_task); 142 143 return NULL; 144} 145 146/* 147 called when a new task is needed 148*/ 149static void thread_new_task(struct tevent_context *ev, 150 struct loadparm_context *lp_ctx, 151 const char *service_name, 152 void (*new_task)(struct tevent_context *, 153 struct loadparm_context *, 154 uint32_t , void *), 155 void *private_data) 156{ 157 int rc; 158 pthread_t thread_id; 159 pthread_attr_t thread_attr; 160 struct new_task_state *state; 161 struct tevent_context *ev2; 162 163 ev2 = s4_event_context_init(ev); 164 if (ev2 == NULL) return; 165 166 state = talloc(ev2, struct new_task_state); 167 if (state == NULL) { 168 talloc_free(ev2); 169 return; 170 } 171 172 state->new_task = new_task; 173 state->lp_ctx = lp_ctx; 174 state->private_data = private_data; 175 state->ev = ev2; 176 177 pthread_attr_init(&thread_attr); 178 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); 179 rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, state); 180 pthread_attr_destroy(&thread_attr); 181 if (rc == 0) { 182 DEBUG(4,("thread_new_task: created %s thread_id=%lu\n", 183 service_name, (unsigned long int)thread_id)); 184 } else { 185 DEBUG(0,("thread_new_task: thread create for %s failed rc=%d\n", service_name, rc)); 186 talloc_free(ev2); 187 } 188} 189 190/* called when a task goes down */ 191static void thread_terminate(struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, const char *reason) 192{ 193 DEBUG(10,("thread_terminate: reason[%s]\n",reason)); 194 195 talloc_free(event_ctx); 196 197 /* terminate this thread */ 198 pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ 199} 200 201/* called to set a title of a task or connection */ 202static void thread_set_title(struct tevent_context *ev, const char *title) 203{ 204 char *old_title; 205 char *new_title; 206 207 old_title = pthread_getspecific(title_key); 208 talloc_free(old_title); 209 210 new_title = talloc_strdup(ev, title); 211 pthread_setspecific(title_key, new_title); 212} 213 214/* 215 mutex init function for thread model 216*/ 217static int thread_mutex_init(smb_mutex_t *mutex, const char *name) 218{ 219 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; 220 mutex->mutex = memdup(&m, sizeof(m)); 221 if (! mutex->mutex) { 222 errno = ENOMEM; 223 return -1; 224 } 225 return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL); 226} 227 228/* 229 mutex destroy function for thread model 230*/ 231static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name) 232{ 233 return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex); 234} 235 236static void mutex_start_timer(struct timeval *tp1) 237{ 238 gettimeofday(tp1,NULL); 239} 240 241static double mutex_end_timer(struct timeval tp1) 242{ 243 struct timeval tp2; 244 gettimeofday(&tp2,NULL); 245 return((tp2.tv_sec - tp1.tv_sec) + 246 (tp2.tv_usec - tp1.tv_usec)*1.0e-6); 247} 248 249/* 250 mutex lock function for thread model 251*/ 252static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name) 253{ 254 pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex; 255 int rc; 256 double t; 257 struct timeval tp1; 258 /* Test below is ONLY for debugging */ 259 if ((rc = pthread_mutex_trylock(mutex))) { 260 if (rc == EBUSY) { 261 mutex_start_timer(&tp1); 262 printf("mutex lock: thread %d, lock %s not available\n", 263 (uint32_t)pthread_self(), name); 264 print_suspicious_usage("mutex_lock", name); 265 pthread_mutex_lock(mutex); 266 t = mutex_end_timer(tp1); 267 printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n", 268 (uint32_t)pthread_self(), name, t); 269 return 0; 270 } 271 printf("mutex lock: thread %d, lock %s failed rc=%d\n", 272 (uint32_t)pthread_self(), name, rc); 273 SMB_ASSERT(errno == 0); /* force error */ 274 } 275 return 0; 276} 277 278/* 279 mutex unlock for thread model 280*/ 281static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name) 282{ 283 return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex); 284} 285 286/***************************************************************** 287 Read/write lock routines. 288*****************************************************************/ 289/* 290 rwlock init function for thread model 291*/ 292static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name) 293{ 294 pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER; 295 rwlock->rwlock = memdup(&m, sizeof(m)); 296 if (! rwlock->rwlock) { 297 errno = ENOMEM; 298 return -1; 299 } 300 return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL); 301} 302 303/* 304 rwlock destroy function for thread model 305*/ 306static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name) 307{ 308 return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock); 309} 310 311/* 312 rwlock lock for read function for thread model 313*/ 314static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name) 315{ 316 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock; 317 int rc; 318 double t; 319 struct timeval tp1; 320 /* Test below is ONLY for debugging */ 321 if ((rc = pthread_rwlock_tryrdlock(rwlock))) { 322 if (rc == EBUSY) { 323 mutex_start_timer(&tp1); 324 printf("rwlock lock_read: thread %d, lock %s not available\n", 325 (uint32_t)pthread_self(), name); 326 print_suspicious_usage("rwlock_lock_read", name); 327 pthread_rwlock_rdlock(rwlock); 328 t = mutex_end_timer(tp1); 329 printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n", 330 (uint32_t)pthread_self(), name, t); 331 return 0; 332 } 333 printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n", 334 (uint32_t)pthread_self(), name, rc); 335 SMB_ASSERT(errno == 0); /* force error */ 336 } 337 return 0; 338} 339 340/* 341 rwlock lock for write function for thread model 342*/ 343static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name) 344{ 345 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock; 346 int rc; 347 double t; 348 struct timeval tp1; 349 /* Test below is ONLY for debugging */ 350 if ((rc = pthread_rwlock_trywrlock(rwlock))) { 351 if (rc == EBUSY) { 352 mutex_start_timer(&tp1); 353 printf("rwlock lock_write: thread %d, lock %s not available\n", 354 (uint32_t)pthread_self(), name); 355 print_suspicious_usage("rwlock_lock_write", name); 356 pthread_rwlock_wrlock(rwlock); 357 t = mutex_end_timer(tp1); 358 printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n", 359 (uint32_t)pthread_self(), name, t); 360 return 0; 361 } 362 printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n", 363 (uint32_t)pthread_self(), name, rc); 364 SMB_ASSERT(errno == 0); /* force error */ 365 } 366 return 0; 367} 368 369 370/* 371 rwlock unlock for thread model 372*/ 373static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name) 374{ 375 return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock); 376} 377 378/***************************************************************** 379 Log suspicious usage (primarily for possible thread-unsafe behavior). 380*****************************************************************/ 381static void thread_log_suspicious_usage(const char* from, const char* info) 382{ 383 DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info)); 384#ifdef HAVE_BACKTRACE 385 { 386 void *addresses[10]; 387 int num_addresses = backtrace(addresses, 8); 388 char **bt_symbols = backtrace_symbols(addresses, num_addresses); 389 int i; 390 391 if (bt_symbols) { 392 for (i=0; i<num_addresses; i++) { 393 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i])); 394 } 395 free(bt_symbols); 396 } 397 } 398#endif 399} 400 401/***************************************************************** 402 Log suspicious usage to stdout (primarily for possible thread-unsafe behavior. 403 Used in mutex code where DEBUG calls would cause recursion. 404*****************************************************************/ 405static void thread_print_suspicious_usage(const char* from, const char* info) 406{ 407 printf("log_suspicious_usage: from %s info='%s'\n", from, info); 408#ifdef HAVE_BACKTRACE 409 { 410 void *addresses[10]; 411 int num_addresses = backtrace(addresses, 8); 412 char **bt_symbols = backtrace_symbols(addresses, num_addresses); 413 int i; 414 415 if (bt_symbols) { 416 for (i=0; i<num_addresses; i++) { 417 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]); 418 } 419 free(bt_symbols); 420 } 421 } 422#endif 423} 424 425static uint32_t thread_get_task_id(void) 426{ 427 return (uint32_t)pthread_self(); 428} 429 430static void thread_log_task_id(int fd) 431{ 432 char *s= NULL; 433 434 asprintf(&s, "thread[%u][%s]:\n", 435 (uint32_t)pthread_self(), 436 (const char *)pthread_getspecific(title_key)); 437 if (!s) return; 438 write(fd, s, strlen(s)); 439 free(s); 440} 441 442/**************************************************************************** 443catch serious errors 444****************************************************************************/ 445static void thread_sig_fault(int sig) 446{ 447 DEBUG(0,("===============================================================\n")); 448 DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread [%u][%s] (%s)\n", 449 sig,(uint32_t)pthread_self(), 450 (const char *)pthread_getspecific(title_key), 451 SAMBA_VERSION_STRING)); 452 DEBUG(0,("===============================================================\n")); 453 exit(1); /* kill the whole server for now */ 454} 455 456/******************************************************************* 457setup our recursive fault handlers 458********************************************************************/ 459static void thread_fault_setup(void) 460{ 461#ifdef SIGSEGV 462 CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault); 463#endif 464#ifdef SIGBUS 465 CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault); 466#endif 467#ifdef SIGABRT 468 CatchSignal(SIGABRT,SIGNAL_CAST thread_sig_fault); 469#endif 470} 471 472/******************************************************************* 473report a fault in a thread 474********************************************************************/ 475static void thread_fault_handler(int sig) 476{ 477 static int counter; 478 479 /* try to catch recursive faults */ 480 thread_fault_setup(); 481 482 counter++; /* count number of faults that have occurred */ 483 484 DEBUG(0,("===============================================================\n")); 485 DEBUG(0,("INTERNAL ERROR: Signal %d in thread [%u] [%s] (%s)\n", 486 sig,(uint32_t)pthread_self(), 487 (const char *)pthread_getspecific(title_key), 488 SAMBA_VERSION_STRING)); 489 DEBUG(0,("Please read the file BUGS.txt in the distribution\n")); 490 DEBUG(0,("===============================================================\n")); 491#ifdef HAVE_BACKTRACE 492 { 493 void *addresses[10]; 494 int num_addresses = backtrace(addresses, 8); 495 char **bt_symbols = backtrace_symbols(addresses, num_addresses); 496 int i; 497 498 if (bt_symbols) { 499 for (i=0; i<num_addresses; i++) { 500 DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i])); 501 } 502 free(bt_symbols); 503 } 504 } 505#endif 506 pthread_exit(NULL); /* terminate failing thread only */ 507} 508 509/* 510 called when the process model is selected 511*/ 512static void thread_model_init(struct tevent_context *event_context) 513{ 514 struct mutex_ops m_ops; 515 struct debug_ops d_ops; 516 517 ZERO_STRUCT(m_ops); 518 ZERO_STRUCT(d_ops); 519 520 pthread_key_create(&title_key, NULL); 521 pthread_setspecific(title_key, talloc_strdup(event_context, "")); 522 523 /* register mutex/rwlock handlers */ 524 m_ops.mutex_init = thread_mutex_init; 525 m_ops.mutex_lock = thread_mutex_lock; 526 m_ops.mutex_unlock = thread_mutex_unlock; 527 m_ops.mutex_destroy = thread_mutex_destroy; 528 529 m_ops.rwlock_init = thread_rwlock_init; 530 m_ops.rwlock_lock_write = thread_rwlock_lock_write; 531 m_ops.rwlock_lock_read = thread_rwlock_lock_read; 532 m_ops.rwlock_unlock = thread_rwlock_unlock; 533 m_ops.rwlock_destroy = thread_rwlock_destroy; 534 535 register_mutex_handlers("thread", &m_ops); 536 537 register_fault_handler("thread", thread_fault_handler); 538 539 d_ops.log_suspicious_usage = thread_log_suspicious_usage; 540 d_ops.print_suspicious_usage = thread_print_suspicious_usage; 541 d_ops.get_task_id = thread_get_task_id; 542 d_ops.log_task_id = thread_log_task_id; 543 544 register_debug_handlers("thread", &d_ops); 545} 546 547 548static const struct model_ops thread_ops = { 549 .name = "thread", 550 .model_init = thread_model_init, 551 .accept_connection = thread_accept_connection, 552 .new_task = thread_new_task, 553 .terminate = thread_terminate, 554 .set_title = thread_set_title, 555}; 556 557/* 558 initialise the thread process model, registering ourselves with the model subsystem 559 */ 560NTSTATUS process_model_thread_init(void) 561{ 562 NTSTATUS ret; 563 564 /* register ourselves with the PROCESS_MODEL subsystem. */ 565 ret = register_process_model(&thread_ops); 566 if (!NT_STATUS_IS_OK(ret)) { 567 DEBUG(0,("Failed to register process_model 'thread'!\n")); 568 return ret; 569 } 570 571 return ret; 572} 573