s4:process_thread: use monotonic time for time deltas
[Samba/ita.git] / source4 / smbd / process_thread.c
blobc047d23d2683f268052090c7c25d3ed534121c67
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 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/>.
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"
37 static pthread_key_t title_key;
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;
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->lp_ctx, new_conn->sock, pthread_self(), new_conn->private_data);
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 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)
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;
80 ev2 = s4_event_context_init(ev);
81 if (ev2 == NULL) return;
83 state = talloc(ev2, struct new_conn_state);
84 if (state == NULL) {
85 talloc_free(ev2);
86 return;
89 state->new_conn = new_conn;
90 state->private_data = private_data;
91 state->lp_ctx = lp_ctx;
92 state->ev = ev2;
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;
107 talloc_steal(state, state->sock);
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);
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;
131 static void *thread_task_fn(void *thread_parm)
133 struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state);
135 new_task->new_task(new_task->ev, new_task->lp_ctx, pthread_self(),
136 new_task->private_data);
138 /* run this connection from here */
139 event_loop_wait(new_task->ev);
141 talloc_free(new_task);
143 return NULL;
147 called when a new task is needed
149 static 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)
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;
163 ev2 = s4_event_context_init(ev);
164 if (ev2 == NULL) return;
166 state = talloc(ev2, struct new_task_state);
167 if (state == NULL) {
168 talloc_free(ev2);
169 return;
172 state->new_task = new_task;
173 state->lp_ctx = lp_ctx;
174 state->private_data = private_data;
175 state->ev = ev2;
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);
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)
193 DEBUG(10,("thread_terminate: reason[%s]\n",reason));
195 talloc_free(event_ctx);
197 /* terminate this thread */
198 pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
201 /* called to set a title of a task or connection */
202 static void thread_set_title(struct tevent_context *ev, const char *title)
204 char *old_title;
205 char *new_title;
207 old_title = pthread_getspecific(title_key);
208 talloc_free(old_title);
210 new_title = talloc_strdup(ev, title);
211 pthread_setspecific(title_key, new_title);
215 mutex init function for thread model
217 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
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;
225 return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
229 mutex destroy function for thread model
231 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
233 return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
236 static void mutex_start_timer(struct timespec *tp1)
238 clock_gettime_mono(tp1);
241 static double mutex_end_timer(struct timespec tp1)
243 struct timespec tp2;
245 clock_gettime_mono(&tp2);
246 return((tp2.tv_sec - tp1.tv_sec) +
247 (tp2.tv_nsec - tp1.tv_nsec)*1.0e-9);
251 mutex lock function for thread model
253 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
255 pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
256 int rc;
257 double t;
258 struct timespec tp1;
259 /* Test below is ONLY for debugging */
260 if ((rc = pthread_mutex_trylock(mutex))) {
261 if (rc == EBUSY) {
262 mutex_start_timer(&tp1);
263 printf("mutex lock: thread %d, lock %s not available\n",
264 (uint32_t)pthread_self(), name);
265 print_suspicious_usage("mutex_lock", name);
266 pthread_mutex_lock(mutex);
267 t = mutex_end_timer(tp1);
268 printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n",
269 (uint32_t)pthread_self(), name, t);
270 return 0;
272 printf("mutex lock: thread %d, lock %s failed rc=%d\n",
273 (uint32_t)pthread_self(), name, rc);
274 SMB_ASSERT(errno == 0); /* force error */
276 return 0;
280 mutex unlock for thread model
282 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
284 return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
287 /*****************************************************************
288 Read/write lock routines.
289 *****************************************************************/
291 rwlock init function for thread model
293 static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
295 pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
296 rwlock->rwlock = memdup(&m, sizeof(m));
297 if (! rwlock->rwlock) {
298 errno = ENOMEM;
299 return -1;
301 return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
305 rwlock destroy function for thread model
307 static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
309 return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
313 rwlock lock for read function for thread model
315 static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
317 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
318 int rc;
319 double t;
320 struct time tp1;
321 /* Test below is ONLY for debugging */
322 if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
323 if (rc == EBUSY) {
324 mutex_start_timer(&tp1);
325 printf("rwlock lock_read: thread %d, lock %s not available\n",
326 (uint32_t)pthread_self(), name);
327 print_suspicious_usage("rwlock_lock_read", name);
328 pthread_rwlock_rdlock(rwlock);
329 t = mutex_end_timer(tp1);
330 printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n",
331 (uint32_t)pthread_self(), name, t);
332 return 0;
334 printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n",
335 (uint32_t)pthread_self(), name, rc);
336 SMB_ASSERT(errno == 0); /* force error */
338 return 0;
342 rwlock lock for write function for thread model
344 static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
346 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
347 int rc;
348 double t;
349 struct timespec tp1;
350 /* Test below is ONLY for debugging */
351 if ((rc = pthread_rwlock_trywrlock(rwlock))) {
352 if (rc == EBUSY) {
353 mutex_start_timer(&tp1);
354 printf("rwlock lock_write: thread %d, lock %s not available\n",
355 (uint32_t)pthread_self(), name);
356 print_suspicious_usage("rwlock_lock_write", name);
357 pthread_rwlock_wrlock(rwlock);
358 t = mutex_end_timer(tp1);
359 printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n",
360 (uint32_t)pthread_self(), name, t);
361 return 0;
363 printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n",
364 (uint32_t)pthread_self(), name, rc);
365 SMB_ASSERT(errno == 0); /* force error */
367 return 0;
372 rwlock unlock for thread model
374 static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
376 return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
379 /*****************************************************************
380 Log suspicious usage (primarily for possible thread-unsafe behavior).
381 *****************************************************************/
382 static void thread_log_suspicious_usage(const char* from, const char* info)
384 DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
385 #ifdef HAVE_BACKTRACE
387 void *addresses[10];
388 int num_addresses = backtrace(addresses, 8);
389 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
390 int i;
392 if (bt_symbols) {
393 for (i=0; i<num_addresses; i++) {
394 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
396 free(bt_symbols);
399 #endif
402 /*****************************************************************
403 Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
404 Used in mutex code where DEBUG calls would cause recursion.
405 *****************************************************************/
406 static void thread_print_suspicious_usage(const char* from, const char* info)
408 printf("log_suspicious_usage: from %s info='%s'\n", from, info);
409 #ifdef HAVE_BACKTRACE
411 void *addresses[10];
412 int num_addresses = backtrace(addresses, 8);
413 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
414 int i;
416 if (bt_symbols) {
417 for (i=0; i<num_addresses; i++) {
418 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
420 free(bt_symbols);
423 #endif
426 static uint32_t thread_get_task_id(void)
428 return (uint32_t)pthread_self();
431 static void thread_log_task_id(int fd)
433 char *s= NULL;
435 asprintf(&s, "thread[%u][%s]:\n",
436 (uint32_t)pthread_self(),
437 (const char *)pthread_getspecific(title_key));
438 if (!s) return;
439 write(fd, s, strlen(s));
440 free(s);
443 /****************************************************************************
444 catch serious errors
445 ****************************************************************************/
446 static void thread_sig_fault(int sig)
448 DEBUG(0,("===============================================================\n"));
449 DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread [%u][%s] (%s)\n",
450 sig,(uint32_t)pthread_self(),
451 (const char *)pthread_getspecific(title_key),
452 SAMBA_VERSION_STRING));
453 DEBUG(0,("===============================================================\n"));
454 exit(1); /* kill the whole server for now */
457 /*******************************************************************
458 setup our recursive fault handlers
459 ********************************************************************/
460 static void thread_fault_setup(void)
462 #ifdef SIGSEGV
463 CatchSignal(SIGSEGV, thread_sig_fault);
464 #endif
465 #ifdef SIGBUS
466 CatchSignal(SIGBUS, thread_sig_fault);
467 #endif
468 #ifdef SIGABRT
469 CatchSignal(SIGABRT, thread_sig_fault);
470 #endif
473 /*******************************************************************
474 report a fault in a thread
475 ********************************************************************/
476 static void thread_fault_handler(int sig)
478 static int counter;
480 /* try to catch recursive faults */
481 thread_fault_setup();
483 counter++; /* count number of faults that have occurred */
485 DEBUG(0,("===============================================================\n"));
486 DEBUG(0,("INTERNAL ERROR: Signal %d in thread [%u] [%s] (%s)\n",
487 sig,(uint32_t)pthread_self(),
488 (const char *)pthread_getspecific(title_key),
489 SAMBA_VERSION_STRING));
490 DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
491 DEBUG(0,("===============================================================\n"));
492 #ifdef HAVE_BACKTRACE
494 void *addresses[10];
495 int num_addresses = backtrace(addresses, 8);
496 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
497 int i;
499 if (bt_symbols) {
500 for (i=0; i<num_addresses; i++) {
501 DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
503 free(bt_symbols);
506 #endif
507 pthread_exit(NULL); /* terminate failing thread only */
511 called when the process model is selected
513 static void thread_model_init(struct tevent_context *event_context)
515 struct mutex_ops m_ops;
516 struct debug_ops d_ops;
518 ZERO_STRUCT(m_ops);
519 ZERO_STRUCT(d_ops);
521 pthread_key_create(&title_key, NULL);
522 pthread_setspecific(title_key, talloc_strdup(event_context, ""));
524 /* register mutex/rwlock handlers */
525 m_ops.mutex_init = thread_mutex_init;
526 m_ops.mutex_lock = thread_mutex_lock;
527 m_ops.mutex_unlock = thread_mutex_unlock;
528 m_ops.mutex_destroy = thread_mutex_destroy;
530 m_ops.rwlock_init = thread_rwlock_init;
531 m_ops.rwlock_lock_write = thread_rwlock_lock_write;
532 m_ops.rwlock_lock_read = thread_rwlock_lock_read;
533 m_ops.rwlock_unlock = thread_rwlock_unlock;
534 m_ops.rwlock_destroy = thread_rwlock_destroy;
536 register_mutex_handlers("thread", &m_ops);
538 register_fault_handler("thread", thread_fault_handler);
540 d_ops.log_suspicious_usage = thread_log_suspicious_usage;
541 d_ops.print_suspicious_usage = thread_print_suspicious_usage;
542 d_ops.get_task_id = thread_get_task_id;
543 d_ops.log_task_id = thread_log_task_id;
545 register_debug_handlers("thread", &d_ops);
549 static const struct model_ops thread_ops = {
550 .name = "thread",
551 .model_init = thread_model_init,
552 .accept_connection = thread_accept_connection,
553 .new_task = thread_new_task,
554 .terminate = thread_terminate,
555 .set_title = thread_set_title,
559 initialise the thread process model, registering ourselves with the model subsystem
561 NTSTATUS process_model_thread_init(void)
563 NTSTATUS ret;
565 /* register ourselves with the PROCESS_MODEL subsystem. */
566 ret = register_process_model(&thread_ops);
567 if (!NT_STATUS_IS_OK(ret)) {
568 DEBUG(0,("Failed to register process_model 'thread'!\n"));
569 return ret;
572 return ret;