r22875: We want to skip this test, it will fail unless run against IPC$ (which the...
[Samba.git] / source / smbd / process_thread.c
blob6ee7b2b6717722cfa1fd07704e75987d9365819d
1 /*
2 Unix SMB/CIFS implementation.
4 thread model: standard (1 thread per client connection)
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) James J Myers 2003 <myersjj@samba.org>
8 Copyright (C) Stefan (metze) Metzmacher 2004
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 2 of the License, or
13 (at your option) any later version.
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.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "includes.h"
26 #include "version.h"
27 #include <pthread.h>
28 #ifdef HAVE_BACKTRACE
29 #include <execinfo.h>
30 #endif
31 #include "system/wait.h"
32 #include "system/filesys.h"
33 #include "lib/events/events.h"
34 #include "lib/util/dlinklist.h"
35 #include "lib/util/mutex.h"
36 #include "smbd/process_model.h"
38 static pthread_key_t title_key;
40 struct new_conn_state {
41 struct event_context *ev;
42 struct socket_context *sock;
43 void (*new_conn)(struct event_context *, struct socket_context *, uint32_t , void *);
44 void *private;
47 static void *thread_connection_fn(void *thread_parm)
49 struct new_conn_state *new_conn = talloc_get_type(thread_parm, struct new_conn_state);
51 new_conn->new_conn(new_conn->ev, new_conn->sock, pthread_self(), new_conn->private);
53 /* run this connection from here */
54 event_loop_wait(new_conn->ev);
56 talloc_free(new_conn);
58 return NULL;
62 called when a listening socket becomes readable
64 static void thread_accept_connection(struct event_context *ev,
65 struct socket_context *sock,
66 void (*new_conn)(struct event_context *, struct socket_context *,
67 uint32_t , void *),
68 void *private)
70 NTSTATUS status;
71 int rc;
72 pthread_t thread_id;
73 pthread_attr_t thread_attr;
74 struct new_conn_state *state;
75 struct event_context *ev2;
77 ev2 = event_context_init(ev);
78 if (ev2 == NULL) return;
80 state = talloc(ev2, struct new_conn_state);
81 if (state == NULL) {
82 talloc_free(ev2);
83 return;
86 state->new_conn = new_conn;
87 state->private = private;
88 state->ev = ev2;
90 /* accept an incoming connection. */
91 status = socket_accept(sock, &state->sock);
92 if (!NT_STATUS_IS_OK(status)) {
93 talloc_free(ev2);
94 /* We need to throttle things until the system clears
95 enough resources to handle this new socket. If we
96 don't then we will spin filling the log and causing
97 more problems. We don't panic as this is probably a
98 temporary resource constraint */
99 sleep(1);
100 return;
103 talloc_steal(state, state->sock);
105 pthread_attr_init(&thread_attr);
106 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
107 rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, state);
108 pthread_attr_destroy(&thread_attr);
109 if (rc == 0) {
110 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n",
111 (unsigned long int)thread_id, socket_get_fd(sock)));
112 } else {
113 DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", socket_get_fd(sock), rc));
114 talloc_free(ev2);
119 struct new_task_state {
120 struct event_context *ev;
121 void (*new_task)(struct event_context *, uint32_t , void *);
122 void *private;
125 static void *thread_task_fn(void *thread_parm)
127 struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state);
129 new_task->new_task(new_task->ev, pthread_self(), new_task->private);
131 /* run this connection from here */
132 event_loop_wait(new_task->ev);
134 talloc_free(new_task);
136 return NULL;
140 called when a new task is needed
142 static void thread_new_task(struct event_context *ev,
143 void (*new_task)(struct event_context *, uint32_t , void *),
144 void *private)
146 int rc;
147 pthread_t thread_id;
148 pthread_attr_t thread_attr;
149 struct new_task_state *state;
150 struct event_context *ev2;
152 ev2 = event_context_init(ev);
153 if (ev2 == NULL) return;
155 state = talloc(ev2, struct new_task_state);
156 if (state == NULL) {
157 talloc_free(ev2);
158 return;
161 state->new_task = new_task;
162 state->private = private;
163 state->ev = ev2;
165 pthread_attr_init(&thread_attr);
166 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
167 rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, state);
168 pthread_attr_destroy(&thread_attr);
169 if (rc == 0) {
170 DEBUG(4,("thread_new_task: created thread_id=%lu\n",
171 (unsigned long int)thread_id));
172 } else {
173 DEBUG(0,("thread_new_task: thread create failed rc=%d\n", rc));
174 talloc_free(ev2);
178 /* called when a task goes down */
179 static void thread_terminate(struct event_context *event_ctx, const char *reason)
181 DEBUG(10,("thread_terminate: reason[%s]\n",reason));
183 talloc_free(event_ctx);
185 /* terminate this thread */
186 pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
189 /* called to set a title of a task or connection */
190 static void thread_set_title(struct event_context *ev, const char *title)
192 char *old_title;
193 char *new_title;
195 old_title = pthread_getspecific(title_key);
196 talloc_free(old_title);
198 new_title = talloc_strdup(ev, title);
199 pthread_setspecific(title_key, new_title);
203 mutex init function for thread model
205 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
207 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
208 mutex->mutex = memdup(&m, sizeof(m));
209 if (! mutex->mutex) {
210 errno = ENOMEM;
211 return -1;
213 return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
217 mutex destroy function for thread model
219 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
221 return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
224 static void mutex_start_timer(struct timeval *tp1)
226 gettimeofday(tp1,NULL);
229 static double mutex_end_timer(struct timeval tp1)
231 struct timeval tp2;
232 gettimeofday(&tp2,NULL);
233 return((tp2.tv_sec - tp1.tv_sec) +
234 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
238 mutex lock function for thread model
240 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
242 pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
243 int rc;
244 double t;
245 struct timeval tp1;
246 /* Test below is ONLY for debugging */
247 if ((rc = pthread_mutex_trylock(mutex))) {
248 if (rc == EBUSY) {
249 mutex_start_timer(&tp1);
250 printf("mutex lock: thread %d, lock %s not available\n",
251 (uint32_t)pthread_self(), name);
252 print_suspicious_usage("mutex_lock", name);
253 pthread_mutex_lock(mutex);
254 t = mutex_end_timer(tp1);
255 printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n",
256 (uint32_t)pthread_self(), name, t);
257 return 0;
259 printf("mutex lock: thread %d, lock %s failed rc=%d\n",
260 (uint32_t)pthread_self(), name, rc);
261 SMB_ASSERT(errno == 0); /* force error */
263 return 0;
267 mutex unlock for thread model
269 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
271 return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
274 /*****************************************************************
275 Read/write lock routines.
276 *****************************************************************/
278 rwlock init function for thread model
280 static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
282 pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
283 rwlock->rwlock = memdup(&m, sizeof(m));
284 if (! rwlock->rwlock) {
285 errno = ENOMEM;
286 return -1;
288 return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
292 rwlock destroy function for thread model
294 static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
296 return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
300 rwlock lock for read function for thread model
302 static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
304 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
305 int rc;
306 double t;
307 struct timeval tp1;
308 /* Test below is ONLY for debugging */
309 if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
310 if (rc == EBUSY) {
311 mutex_start_timer(&tp1);
312 printf("rwlock lock_read: thread %d, lock %s not available\n",
313 (uint32_t)pthread_self(), name);
314 print_suspicious_usage("rwlock_lock_read", name);
315 pthread_rwlock_rdlock(rwlock);
316 t = mutex_end_timer(tp1);
317 printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n",
318 (uint32_t)pthread_self(), name, t);
319 return 0;
321 printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n",
322 (uint32_t)pthread_self(), name, rc);
323 SMB_ASSERT(errno == 0); /* force error */
325 return 0;
329 rwlock lock for write function for thread model
331 static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
333 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
334 int rc;
335 double t;
336 struct timeval tp1;
337 /* Test below is ONLY for debugging */
338 if ((rc = pthread_rwlock_trywrlock(rwlock))) {
339 if (rc == EBUSY) {
340 mutex_start_timer(&tp1);
341 printf("rwlock lock_write: thread %d, lock %s not available\n",
342 (uint32_t)pthread_self(), name);
343 print_suspicious_usage("rwlock_lock_write", name);
344 pthread_rwlock_wrlock(rwlock);
345 t = mutex_end_timer(tp1);
346 printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n",
347 (uint32_t)pthread_self(), name, t);
348 return 0;
350 printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n",
351 (uint32_t)pthread_self(), name, rc);
352 SMB_ASSERT(errno == 0); /* force error */
354 return 0;
359 rwlock unlock for thread model
361 static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
363 return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
366 /*****************************************************************
367 Log suspicious usage (primarily for possible thread-unsafe behavior).
368 *****************************************************************/
369 static void thread_log_suspicious_usage(const char* from, const char* info)
371 DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
372 #ifdef HAVE_BACKTRACE
374 void *addresses[10];
375 int num_addresses = backtrace(addresses, 8);
376 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
377 int i;
379 if (bt_symbols) {
380 for (i=0; i<num_addresses; i++) {
381 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
383 free(bt_symbols);
386 #endif
389 /*****************************************************************
390 Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
391 Used in mutex code where DEBUG calls would cause recursion.
392 *****************************************************************/
393 static void thread_print_suspicious_usage(const char* from, const char* info)
395 printf("log_suspicious_usage: from %s info='%s'\n", from, info);
396 #ifdef HAVE_BACKTRACE
398 void *addresses[10];
399 int num_addresses = backtrace(addresses, 8);
400 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
401 int i;
403 if (bt_symbols) {
404 for (i=0; i<num_addresses; i++) {
405 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
407 free(bt_symbols);
410 #endif
413 static uint32_t thread_get_task_id(void)
415 return (uint32_t)pthread_self();
418 static void thread_log_task_id(int fd)
420 char *s= NULL;
422 asprintf(&s, "thread[%u][%s]:\n",
423 (uint32_t)pthread_self(),
424 (const char *)pthread_getspecific(title_key));
425 if (!s) return;
426 write(fd, s, strlen(s));
427 free(s);
430 /****************************************************************************
431 catch serious errors
432 ****************************************************************************/
433 static void thread_sig_fault(int sig)
435 DEBUG(0,("===============================================================\n"));
436 DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread [%u][%s] (%s)\n",
437 sig,(uint32_t)pthread_self(),
438 (const char *)pthread_getspecific(title_key),
439 SAMBA_VERSION_STRING));
440 DEBUG(0,("===============================================================\n"));
441 exit(1); /* kill the whole server for now */
444 /*******************************************************************
445 setup our recursive fault handlers
446 ********************************************************************/
447 static void thread_fault_setup(void)
449 #ifdef SIGSEGV
450 CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault);
451 #endif
452 #ifdef SIGBUS
453 CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault);
454 #endif
455 #ifdef SIGABRT
456 CatchSignal(SIGABRT,SIGNAL_CAST thread_sig_fault);
457 #endif
460 /*******************************************************************
461 report a fault in a thread
462 ********************************************************************/
463 static void thread_fault_handler(int sig)
465 static int counter;
467 /* try to catch recursive faults */
468 thread_fault_setup();
470 counter++; /* count number of faults that have occurred */
472 DEBUG(0,("===============================================================\n"));
473 DEBUG(0,("INTERNAL ERROR: Signal %d in thread [%u] [%s] (%s)\n",
474 sig,(uint32_t)pthread_self(),
475 (const char *)pthread_getspecific(title_key),
476 SAMBA_VERSION_STRING));
477 DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
478 DEBUG(0,("===============================================================\n"));
479 #ifdef HAVE_BACKTRACE
481 void *addresses[10];
482 int num_addresses = backtrace(addresses, 8);
483 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
484 int i;
486 if (bt_symbols) {
487 for (i=0; i<num_addresses; i++) {
488 DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
490 free(bt_symbols);
493 #endif
494 pthread_exit(NULL); /* terminate failing thread only */
498 called when the process model is selected
500 static void thread_model_init(struct event_context *event_context)
502 struct mutex_ops m_ops;
503 struct debug_ops d_ops;
505 ZERO_STRUCT(m_ops);
506 ZERO_STRUCT(d_ops);
508 pthread_key_create(&title_key, NULL);
509 pthread_setspecific(title_key, talloc_strdup(event_context, ""));
511 /* register mutex/rwlock handlers */
512 m_ops.mutex_init = thread_mutex_init;
513 m_ops.mutex_lock = thread_mutex_lock;
514 m_ops.mutex_unlock = thread_mutex_unlock;
515 m_ops.mutex_destroy = thread_mutex_destroy;
517 m_ops.rwlock_init = thread_rwlock_init;
518 m_ops.rwlock_lock_write = thread_rwlock_lock_write;
519 m_ops.rwlock_lock_read = thread_rwlock_lock_read;
520 m_ops.rwlock_unlock = thread_rwlock_unlock;
521 m_ops.rwlock_destroy = thread_rwlock_destroy;
523 register_mutex_handlers("thread", &m_ops);
525 register_fault_handler("thread", thread_fault_handler);
527 d_ops.log_suspicious_usage = thread_log_suspicious_usage;
528 d_ops.print_suspicious_usage = thread_print_suspicious_usage;
529 d_ops.get_task_id = thread_get_task_id;
530 d_ops.log_task_id = thread_log_task_id;
532 register_debug_handlers("thread", &d_ops);
536 static const struct model_ops thread_ops = {
537 .name = "thread",
538 .model_init = thread_model_init,
539 .accept_connection = thread_accept_connection,
540 .new_task = thread_new_task,
541 .terminate = thread_terminate,
542 .set_title = thread_set_title,
546 initialise the thread process model, registering ourselves with the model subsystem
548 NTSTATUS process_model_thread_init(void)
550 NTSTATUS ret;
552 /* register ourselves with the PROCESS_MODEL subsystem. */
553 ret = register_process_model(&thread_ops);
554 if (!NT_STATUS_IS_OK(ret)) {
555 DEBUG(0,("Failed to register process_model 'thread'!\n"));
556 return ret;
559 return ret;