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 2 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, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
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"
37
38 static pthread_key_t title_key;
39
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;
45 };
46
thread_connection_fn(void * thread_parm)47 static 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->sock, pthread_self(), new_conn->private);
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 */
thread_accept_connection(struct event_context * ev,struct socket_context * sock,void (* new_conn)(struct event_context *,struct socket_context *,uint32_t,void *),void * private)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)
69 {
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;
76
77 ev2 = event_context_init(ev);
78 if (ev2 == NULL) return;
79
80 state = talloc(ev2, struct new_conn_state);
81 if (state == NULL) {
82 talloc_free(ev2);
83 return;
84 }
85
86 state->new_conn = new_conn;
87 state->private = private;
88 state->ev = ev2;
89
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;
101 }
102
103 talloc_steal(state, state->sock);
104
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);
115 }
116 }
117
118
119 struct new_task_state {
120 struct event_context *ev;
121 void (*new_task)(struct event_context *, uint32_t , void *);
122 void *private;
123 };
124
thread_task_fn(void * thread_parm)125 static void *thread_task_fn(void *thread_parm)
126 {
127 struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state);
128
129 new_task->new_task(new_task->ev, pthread_self(), new_task->private);
130
131 /* run this connection from here */
132 event_loop_wait(new_task->ev);
133
134 talloc_free(new_task);
135
136 return NULL;
137 }
138
139 /*
140 called when a new task is needed
141 */
thread_new_task(struct event_context * ev,void (* new_task)(struct event_context *,uint32_t,void *),void * private)142 static void thread_new_task(struct event_context *ev,
143 void (*new_task)(struct event_context *, uint32_t , void *),
144 void *private)
145 {
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;
151
152 ev2 = event_context_init(ev);
153 if (ev2 == NULL) return;
154
155 state = talloc(ev2, struct new_task_state);
156 if (state == NULL) {
157 talloc_free(ev2);
158 return;
159 }
160
161 state->new_task = new_task;
162 state->private = private;
163 state->ev = ev2;
164
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);
175 }
176 }
177
178 /* called when a task goes down */
thread_terminate(struct event_context * event_ctx,const char * reason)179 static void thread_terminate(struct event_context *event_ctx, const char *reason)
180 {
181 DEBUG(10,("thread_terminate: reason[%s]\n",reason));
182
183 talloc_free(event_ctx);
184
185 /* terminate this thread */
186 pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
187 }
188
189 /* called to set a title of a task or connection */
thread_set_title(struct event_context * ev,const char * title)190 static void thread_set_title(struct event_context *ev, const char *title)
191 {
192 char *old_title;
193 char *new_title;
194
195 old_title = pthread_getspecific(title_key);
196 talloc_free(old_title);
197
198 new_title = talloc_strdup(ev, title);
199 pthread_setspecific(title_key, new_title);
200 }
201
202 /*
203 mutex init function for thread model
204 */
thread_mutex_init(smb_mutex_t * mutex,const char * name)205 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
206 {
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;
212 }
213 return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
214 }
215
216 /*
217 mutex destroy function for thread model
218 */
thread_mutex_destroy(smb_mutex_t * mutex,const char * name)219 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
220 {
221 return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
222 }
223
mutex_start_timer(struct timeval * tp1)224 static void mutex_start_timer(struct timeval *tp1)
225 {
226 gettimeofday(tp1,NULL);
227 }
228
mutex_end_timer(struct timeval tp1)229 static double mutex_end_timer(struct timeval tp1)
230 {
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);
235 }
236
237 /*
238 mutex lock function for thread model
239 */
thread_mutex_lock(smb_mutex_t * mutexP,const char * name)240 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
241 {
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;
258 }
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 */
262 }
263 return 0;
264 }
265
266 /*
267 mutex unlock for thread model
268 */
thread_mutex_unlock(smb_mutex_t * mutex,const char * name)269 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
270 {
271 return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
272 }
273
274 /*****************************************************************
275 Read/write lock routines.
276 *****************************************************************/
277 /*
278 rwlock init function for thread model
279 */
thread_rwlock_init(smb_rwlock_t * rwlock,const char * name)280 static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
281 {
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;
287 }
288 return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
289 }
290
291 /*
292 rwlock destroy function for thread model
293 */
thread_rwlock_destroy(smb_rwlock_t * rwlock,const char * name)294 static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
295 {
296 return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
297 }
298
299 /*
300 rwlock lock for read function for thread model
301 */
thread_rwlock_lock_read(smb_rwlock_t * rwlockP,const char * name)302 static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
303 {
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;
320 }
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 */
324 }
325 return 0;
326 }
327
328 /*
329 rwlock lock for write function for thread model
330 */
thread_rwlock_lock_write(smb_rwlock_t * rwlockP,const char * name)331 static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
332 {
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;
349 }
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 */
353 }
354 return 0;
355 }
356
357
358 /*
359 rwlock unlock for thread model
360 */
thread_rwlock_unlock(smb_rwlock_t * rwlock,const char * name)361 static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
362 {
363 return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
364 }
365
366 /*****************************************************************
367 Log suspicious usage (primarily for possible thread-unsafe behavior).
368 *****************************************************************/
thread_log_suspicious_usage(const char * from,const char * info)369 static void thread_log_suspicious_usage(const char* from, const char* info)
370 {
371 DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
372 #ifdef HAVE_BACKTRACE
373 {
374 void *addresses[10];
375 int num_addresses = backtrace(addresses, 8);
376 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
377 int i;
378
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]));
382 }
383 free(bt_symbols);
384 }
385 }
386 #endif
387 }
388
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 *****************************************************************/
thread_print_suspicious_usage(const char * from,const char * info)393 static void thread_print_suspicious_usage(const char* from, const char* info)
394 {
395 printf("log_suspicious_usage: from %s info='%s'\n", from, info);
396 #ifdef HAVE_BACKTRACE
397 {
398 void *addresses[10];
399 int num_addresses = backtrace(addresses, 8);
400 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
401 int i;
402
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]);
406 }
407 free(bt_symbols);
408 }
409 }
410 #endif
411 }
412
thread_get_task_id(void)413 static uint32_t thread_get_task_id(void)
414 {
415 return (uint32_t)pthread_self();
416 }
417
thread_log_task_id(int fd)418 static void thread_log_task_id(int fd)
419 {
420 char *s= NULL;
421
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);
428 }
429
430 /****************************************************************************
431 catch serious errors
432 ****************************************************************************/
thread_sig_fault(int sig)433 static void thread_sig_fault(int sig)
434 {
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 */
442 }
443
444 /*******************************************************************
445 setup our recursive fault handlers
446 ********************************************************************/
thread_fault_setup(void)447 static void thread_fault_setup(void)
448 {
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
458 }
459
460 /*******************************************************************
461 report a fault in a thread
462 ********************************************************************/
thread_fault_handler(int sig)463 static void thread_fault_handler(int sig)
464 {
465 static int counter;
466
467 /* try to catch recursive faults */
468 thread_fault_setup();
469
470 counter++; /* count number of faults that have occurred */
471
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
480 {
481 void *addresses[10];
482 int num_addresses = backtrace(addresses, 8);
483 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
484 int i;
485
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]));
489 }
490 free(bt_symbols);
491 }
492 }
493 #endif
494 pthread_exit(NULL); /* terminate failing thread only */
495 }
496
497 /*
498 called when the process model is selected
499 */
thread_model_init(struct event_context * event_context)500 static void thread_model_init(struct event_context *event_context)
501 {
502 struct mutex_ops m_ops;
503 struct debug_ops d_ops;
504
505 ZERO_STRUCT(m_ops);
506 ZERO_STRUCT(d_ops);
507
508 pthread_key_create(&title_key, NULL);
509 pthread_setspecific(title_key, talloc_strdup(event_context, ""));
510
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;
516
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;
522
523 register_mutex_handlers("thread", &m_ops);
524
525 register_fault_handler("thread", thread_fault_handler);
526
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;
531
532 register_debug_handlers("thread", &d_ops);
533 }
534
535
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,
543 };
544
545 /*
546 initialise the thread process model, registering ourselves with the model subsystem
547 */
process_model_thread_init(void)548 NTSTATUS process_model_thread_init(void)
549 {
550 NTSTATUS ret;
551
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;
557 }
558
559 return ret;
560 }
561