root/source4/smbd/process_thread.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. thread_connection_fn
  2. thread_accept_connection
  3. thread_task_fn
  4. thread_new_task
  5. thread_terminate
  6. thread_set_title
  7. thread_mutex_init
  8. thread_mutex_destroy
  9. mutex_start_timer
  10. mutex_end_timer
  11. thread_mutex_lock
  12. thread_mutex_unlock
  13. thread_rwlock_init
  14. thread_rwlock_destroy
  15. thread_rwlock_lock_read
  16. thread_rwlock_lock_write
  17. thread_rwlock_unlock
  18. thread_log_suspicious_usage
  19. thread_print_suspicious_usage
  20. thread_get_task_id
  21. thread_log_task_id
  22. thread_sig_fault
  23. thread_fault_setup
  24. thread_fault_handler
  25. thread_model_init
  26. process_model_thread_init

   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 
  37 static pthread_key_t title_key;
  38 
  39 struct 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 
  47 static void *thread_connection_fn(void *thread_parm)
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
  64 static void thread_accept_connection(struct tevent_context *ev, 
     /* [<][>][^][v][top][bottom][index][help] */
  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 
 123 struct 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 
 131 static void *thread_task_fn(void *thread_parm)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 149 static void thread_new_task(struct tevent_context *ev, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 191 static void thread_terminate(struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, const char *reason) 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 202 static void thread_set_title(struct tevent_context *ev, const char *title) 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 217 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 231 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 232 {
 233         return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
 234 }
 235 
 236 static void mutex_start_timer(struct timeval *tp1)
     /* [<][>][^][v][top][bottom][index][help] */
 237 {
 238         gettimeofday(tp1,NULL);
 239 }
 240 
 241 static double mutex_end_timer(struct timeval tp1)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 252 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 281 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 292 static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 306 static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 307 {
 308         return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
 309 }
 310 
 311 /*
 312   rwlock lock for read function for thread model
 313 */
 314 static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 343 static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 373 static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 *****************************************************************/  
 381 static void thread_log_suspicious_usage(const char* from, const char* info)
     /* [<][>][^][v][top][bottom][index][help] */
 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 *****************************************************************/  
 405 static void thread_print_suspicious_usage(const char* from, const char* info)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 425 static uint32_t thread_get_task_id(void)
     /* [<][>][^][v][top][bottom][index][help] */
 426 {
 427         return (uint32_t)pthread_self();
 428 }
 429 
 430 static void thread_log_task_id(int fd)
     /* [<][>][^][v][top][bottom][index][help] */
 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 /****************************************************************************
 443 catch serious errors
 444 ****************************************************************************/
 445 static void thread_sig_fault(int sig)
     /* [<][>][^][v][top][bottom][index][help] */
 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 /*******************************************************************
 457 setup our recursive fault handlers
 458 ********************************************************************/
 459 static void thread_fault_setup(void)
     /* [<][>][^][v][top][bottom][index][help] */
 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 /*******************************************************************
 473 report a fault in a thread
 474 ********************************************************************/
 475 static void thread_fault_handler(int sig)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 512 static void thread_model_init(struct tevent_context *event_context)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 548 static 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  */
 560 NTSTATUS process_model_thread_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */