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 3 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, see <http://www.gnu.org/licenses/>.
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"
37 static pthread_key_t title_key;
39 struct new_conn_state {
40 struct event_context *ev;
41 struct socket_context *sock;
42 void (*new_conn)(struct event_context *, struct socket_context *, uint32_t , void *);
46 static void *thread_connection_fn(void *thread_parm)
48 struct new_conn_state *new_conn = talloc_get_type(thread_parm, struct new_conn_state);
50 new_conn->new_conn(new_conn->ev, new_conn->sock, pthread_self(), new_conn->private);
52 /* run this connection from here */
53 event_loop_wait(new_conn->ev);
55 talloc_free(new_conn);
61 called when a listening socket becomes readable
63 static void thread_accept_connection(struct event_context *ev,
64 struct socket_context *sock,
65 void (*new_conn)(struct event_context *, struct socket_context *,
72 pthread_attr_t thread_attr;
73 struct new_conn_state *state;
74 struct event_context *ev2;
76 ev2 = event_context_init(ev);
77 if (ev2 == NULL) return;
79 state = talloc(ev2, struct new_conn_state);
85 state->new_conn = new_conn;
86 state->private = private;
89 /* accept an incoming connection. */
90 status = socket_accept(sock, &state->sock);
91 if (!NT_STATUS_IS_OK(status)) {
93 /* We need to throttle things until the system clears
94 enough resources to handle this new socket. If we
95 don't then we will spin filling the log and causing
96 more problems. We don't panic as this is probably a
97 temporary resource constraint */
102 talloc_steal(state, state->sock);
104 pthread_attr_init(&thread_attr);
105 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
106 rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, state);
107 pthread_attr_destroy(&thread_attr);
109 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n",
110 (unsigned long int)thread_id, socket_get_fd(sock)));
112 DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", socket_get_fd(sock), rc));
118 struct new_task_state {
119 struct event_context *ev;
120 void (*new_task)(struct event_context *, uint32_t , void *);
124 static void *thread_task_fn(void *thread_parm)
126 struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state);
128 new_task->new_task(new_task->ev, pthread_self(), new_task->private);
130 /* run this connection from here */
131 event_loop_wait(new_task->ev);
133 talloc_free(new_task);
139 called when a new task is needed
141 static void thread_new_task(struct event_context *ev,
142 void (*new_task)(struct event_context *, uint32_t , void *),
147 pthread_attr_t thread_attr;
148 struct new_task_state *state;
149 struct event_context *ev2;
151 ev2 = event_context_init(ev);
152 if (ev2 == NULL) return;
154 state = talloc(ev2, struct new_task_state);
160 state->new_task = new_task;
161 state->private = private;
164 pthread_attr_init(&thread_attr);
165 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
166 rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, state);
167 pthread_attr_destroy(&thread_attr);
169 DEBUG(4,("thread_new_task: created thread_id=%lu\n",
170 (unsigned long int)thread_id));
172 DEBUG(0,("thread_new_task: thread create failed rc=%d\n", rc));
177 /* called when a task goes down */
178 static void thread_terminate(struct event_context *event_ctx, const char *reason)
180 DEBUG(10,("thread_terminate: reason[%s]\n",reason));
182 talloc_free(event_ctx);
184 /* terminate this thread */
185 pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
188 /* called to set a title of a task or connection */
189 static void thread_set_title(struct event_context *ev, const char *title)
194 old_title = pthread_getspecific(title_key);
195 talloc_free(old_title);
197 new_title = talloc_strdup(ev, title);
198 pthread_setspecific(title_key, new_title);
202 mutex init function for thread model
204 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
206 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
207 mutex->mutex = memdup(&m, sizeof(m));
208 if (! mutex->mutex) {
212 return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
216 mutex destroy function for thread model
218 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
220 return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
223 static void mutex_start_timer(struct timeval *tp1)
225 gettimeofday(tp1,NULL);
228 static double mutex_end_timer(struct timeval tp1)
231 gettimeofday(&tp2,NULL);
232 return((tp2.tv_sec - tp1.tv_sec) +
233 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
237 mutex lock function for thread model
239 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
241 pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
245 /* Test below is ONLY for debugging */
246 if ((rc = pthread_mutex_trylock(mutex))) {
248 mutex_start_timer(&tp1);
249 printf("mutex lock: thread %d, lock %s not available\n",
250 (uint32_t)pthread_self(), name);
251 print_suspicious_usage("mutex_lock", name);
252 pthread_mutex_lock(mutex);
253 t = mutex_end_timer(tp1);
254 printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n",
255 (uint32_t)pthread_self(), name, t);
258 printf("mutex lock: thread %d, lock %s failed rc=%d\n",
259 (uint32_t)pthread_self(), name, rc);
260 SMB_ASSERT(errno == 0); /* force error */
266 mutex unlock for thread model
268 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
270 return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
273 /*****************************************************************
274 Read/write lock routines.
275 *****************************************************************/
277 rwlock init function for thread model
279 static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
281 pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
282 rwlock->rwlock = memdup(&m, sizeof(m));
283 if (! rwlock->rwlock) {
287 return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
291 rwlock destroy function for thread model
293 static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
295 return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
299 rwlock lock for read function for thread model
301 static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
303 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
307 /* Test below is ONLY for debugging */
308 if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
310 mutex_start_timer(&tp1);
311 printf("rwlock lock_read: thread %d, lock %s not available\n",
312 (uint32_t)pthread_self(), name);
313 print_suspicious_usage("rwlock_lock_read", name);
314 pthread_rwlock_rdlock(rwlock);
315 t = mutex_end_timer(tp1);
316 printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n",
317 (uint32_t)pthread_self(), name, t);
320 printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n",
321 (uint32_t)pthread_self(), name, rc);
322 SMB_ASSERT(errno == 0); /* force error */
328 rwlock lock for write function for thread model
330 static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
332 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
336 /* Test below is ONLY for debugging */
337 if ((rc = pthread_rwlock_trywrlock(rwlock))) {
339 mutex_start_timer(&tp1);
340 printf("rwlock lock_write: thread %d, lock %s not available\n",
341 (uint32_t)pthread_self(), name);
342 print_suspicious_usage("rwlock_lock_write", name);
343 pthread_rwlock_wrlock(rwlock);
344 t = mutex_end_timer(tp1);
345 printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n",
346 (uint32_t)pthread_self(), name, t);
349 printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n",
350 (uint32_t)pthread_self(), name, rc);
351 SMB_ASSERT(errno == 0); /* force error */
358 rwlock unlock for thread model
360 static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
362 return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
365 /*****************************************************************
366 Log suspicious usage (primarily for possible thread-unsafe behavior).
367 *****************************************************************/
368 static void thread_log_suspicious_usage(const char* from, const char* info)
370 DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
371 #ifdef HAVE_BACKTRACE
374 int num_addresses = backtrace(addresses, 8);
375 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
379 for (i=0; i<num_addresses; i++) {
380 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
388 /*****************************************************************
389 Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
390 Used in mutex code where DEBUG calls would cause recursion.
391 *****************************************************************/
392 static void thread_print_suspicious_usage(const char* from, const char* info)
394 printf("log_suspicious_usage: from %s info='%s'\n", from, info);
395 #ifdef HAVE_BACKTRACE
398 int num_addresses = backtrace(addresses, 8);
399 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
403 for (i=0; i<num_addresses; i++) {
404 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
412 static uint32_t thread_get_task_id(void)
414 return (uint32_t)pthread_self();
417 static void thread_log_task_id(int fd)
421 asprintf(&s, "thread[%u][%s]:\n",
422 (uint32_t)pthread_self(),
423 (const char *)pthread_getspecific(title_key));
425 write(fd, s, strlen(s));
429 /****************************************************************************
431 ****************************************************************************/
432 static void thread_sig_fault(int sig)
434 DEBUG(0,("===============================================================\n"));
435 DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread [%u][%s] (%s)\n",
436 sig,(uint32_t)pthread_self(),
437 (const char *)pthread_getspecific(title_key),
438 SAMBA_VERSION_STRING));
439 DEBUG(0,("===============================================================\n"));
440 exit(1); /* kill the whole server for now */
443 /*******************************************************************
444 setup our recursive fault handlers
445 ********************************************************************/
446 static void thread_fault_setup(void)
449 CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault);
452 CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault);
455 CatchSignal(SIGABRT,SIGNAL_CAST thread_sig_fault);
459 /*******************************************************************
460 report a fault in a thread
461 ********************************************************************/
462 static void thread_fault_handler(int sig)
466 /* try to catch recursive faults */
467 thread_fault_setup();
469 counter++; /* count number of faults that have occurred */
471 DEBUG(0,("===============================================================\n"));
472 DEBUG(0,("INTERNAL ERROR: Signal %d in thread [%u] [%s] (%s)\n",
473 sig,(uint32_t)pthread_self(),
474 (const char *)pthread_getspecific(title_key),
475 SAMBA_VERSION_STRING));
476 DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
477 DEBUG(0,("===============================================================\n"));
478 #ifdef HAVE_BACKTRACE
481 int num_addresses = backtrace(addresses, 8);
482 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
486 for (i=0; i<num_addresses; i++) {
487 DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
493 pthread_exit(NULL); /* terminate failing thread only */
497 called when the process model is selected
499 static void thread_model_init(struct event_context *event_context)
501 struct mutex_ops m_ops;
502 struct debug_ops d_ops;
507 pthread_key_create(&title_key, NULL);
508 pthread_setspecific(title_key, talloc_strdup(event_context, ""));
510 /* register mutex/rwlock handlers */
511 m_ops.mutex_init = thread_mutex_init;
512 m_ops.mutex_lock = thread_mutex_lock;
513 m_ops.mutex_unlock = thread_mutex_unlock;
514 m_ops.mutex_destroy = thread_mutex_destroy;
516 m_ops.rwlock_init = thread_rwlock_init;
517 m_ops.rwlock_lock_write = thread_rwlock_lock_write;
518 m_ops.rwlock_lock_read = thread_rwlock_lock_read;
519 m_ops.rwlock_unlock = thread_rwlock_unlock;
520 m_ops.rwlock_destroy = thread_rwlock_destroy;
522 register_mutex_handlers("thread", &m_ops);
524 register_fault_handler("thread", thread_fault_handler);
526 d_ops.log_suspicious_usage = thread_log_suspicious_usage;
527 d_ops.print_suspicious_usage = thread_print_suspicious_usage;
528 d_ops.get_task_id = thread_get_task_id;
529 d_ops.log_task_id = thread_log_task_id;
531 register_debug_handlers("thread", &d_ops);
535 static const struct model_ops thread_ops = {
537 .model_init = thread_model_init,
538 .accept_connection = thread_accept_connection,
539 .new_task = thread_new_task,
540 .terminate = thread_terminate,
541 .set_title = thread_set_title,
545 initialise the thread process model, registering ourselves with the model subsystem
547 NTSTATUS process_model_thread_init(void)
551 /* register ourselves with the PROCESS_MODEL subsystem. */
552 ret = register_process_model(&thread_ops);
553 if (!NT_STATUS_IS_OK(ret)) {
554 DEBUG(0,("Failed to register process_model 'thread'!\n"));