source: vendor/3.6.0/source4/smbd/process_thread.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 16.4 KB
Line 
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 "system/time.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
38static pthread_key_t title_key;
39
40struct new_conn_state {
41 struct tevent_context *ev;
42 struct socket_context *sock;
43 struct loadparm_context *lp_ctx;
44 void (*new_conn)(struct tevent_context *, struct loadparm_context *lp_ctx, struct socket_context *, uint32_t , void *);
45 void *private_data;
46};
47
48static void *thread_connection_fn(void *thread_parm)
49{
50 struct new_conn_state *new_conn = talloc_get_type(thread_parm, struct new_conn_state);
51
52 new_conn->new_conn(new_conn->ev, new_conn->lp_ctx, new_conn->sock, pthread_self(), new_conn->private_data);
53
54 /* run this connection from here */
55 event_loop_wait(new_conn->ev);
56
57 talloc_free(new_conn);
58
59 return NULL;
60}
61
62/*
63 called when a listening socket becomes readable
64*/
65static void thread_accept_connection(struct tevent_context *ev,
66 struct loadparm_context *lp_ctx,
67 struct socket_context *sock,
68 void (*new_conn)(struct tevent_context *,
69 struct loadparm_context *,
70 struct socket_context *,
71 uint32_t , void *),
72 void *private_data)
73{
74 NTSTATUS status;
75 int rc;
76 pthread_t thread_id;
77 pthread_attr_t thread_attr;
78 struct new_conn_state *state;
79 struct tevent_context *ev2;
80
81 ev2 = s4_event_context_init(ev);
82 if (ev2 == NULL) return;
83
84 state = talloc(ev2, struct new_conn_state);
85 if (state == NULL) {
86 talloc_free(ev2);
87 return;
88 }
89
90 state->new_conn = new_conn;
91 state->private_data = private_data;
92 state->lp_ctx = lp_ctx;
93 state->ev = ev2;
94
95 /* accept an incoming connection. */
96 status = socket_accept(sock, &state->sock);
97 if (!NT_STATUS_IS_OK(status)) {
98 talloc_free(ev2);
99 /* We need to throttle things until the system clears
100 enough resources to handle this new socket. If we
101 don't then we will spin filling the log and causing
102 more problems. We don't panic as this is probably a
103 temporary resource constraint */
104 sleep(1);
105 return;
106 }
107
108 talloc_steal(state, state->sock);
109
110 pthread_attr_init(&thread_attr);
111 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
112 rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, state);
113 pthread_attr_destroy(&thread_attr);
114 if (rc == 0) {
115 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n",
116 (unsigned long int)thread_id, socket_get_fd(sock)));
117 } else {
118 DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", socket_get_fd(sock), rc));
119 talloc_free(ev2);
120 }
121}
122
123
124struct new_task_state {
125 struct tevent_context *ev;
126 struct loadparm_context *lp_ctx;
127 void (*new_task)(struct tevent_context *, struct loadparm_context *,
128 uint32_t , void *);
129 void *private_data;
130};
131
132static void *thread_task_fn(void *thread_parm)
133{
134 struct new_task_state *new_task = talloc_get_type(thread_parm, struct new_task_state);
135
136 new_task->new_task(new_task->ev, new_task->lp_ctx, pthread_self(),
137 new_task->private_data);
138
139 /* run this connection from here */
140 event_loop_wait(new_task->ev);
141
142 talloc_free(new_task);
143
144 return NULL;
145}
146
147/*
148 called when a new task is needed
149*/
150static void thread_new_task(struct tevent_context *ev,
151 struct loadparm_context *lp_ctx,
152 const char *service_name,
153 void (*new_task)(struct tevent_context *,
154 struct loadparm_context *,
155 uint32_t , void *),
156 void *private_data)
157{
158 int rc;
159 pthread_t thread_id;
160 pthread_attr_t thread_attr;
161 struct new_task_state *state;
162 struct tevent_context *ev2;
163
164 ev2 = s4_event_context_init(ev);
165 if (ev2 == NULL) return;
166
167 state = talloc(ev2, struct new_task_state);
168 if (state == NULL) {
169 talloc_free(ev2);
170 return;
171 }
172
173 state->new_task = new_task;
174 state->lp_ctx = lp_ctx;
175 state->private_data = private_data;
176 state->ev = ev2;
177
178 pthread_attr_init(&thread_attr);
179 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
180 rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, state);
181 pthread_attr_destroy(&thread_attr);
182 if (rc == 0) {
183 DEBUG(4,("thread_new_task: created %s thread_id=%lu\n",
184 service_name, (unsigned long int)thread_id));
185 } else {
186 DEBUG(0,("thread_new_task: thread create for %s failed rc=%d\n", service_name, rc));
187 talloc_free(ev2);
188 }
189}
190
191/* called when a task goes down */
192static void thread_terminate(struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, const char *reason)
193{
194 DEBUG(10,("thread_terminate: reason[%s]\n",reason));
195
196 talloc_free(event_ctx);
197
198 /* terminate this thread */
199 pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
200}
201
202/* called to set a title of a task or connection */
203static void thread_set_title(struct tevent_context *ev, const char *title)
204{
205 char *old_title;
206 char *new_title;
207
208 old_title = pthread_getspecific(title_key);
209 talloc_free(old_title);
210
211 new_title = talloc_strdup(ev, title);
212 pthread_setspecific(title_key, new_title);
213}
214
215/*
216 mutex init function for thread model
217*/
218static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
219{
220 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
221 mutex->mutex = memdup(&m, sizeof(m));
222 if (! mutex->mutex) {
223 errno = ENOMEM;
224 return -1;
225 }
226 return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
227}
228
229/*
230 mutex destroy function for thread model
231*/
232static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
233{
234 return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
235}
236
237static void mutex_start_timer(struct timespec *tp1)
238{
239 clock_gettime_mono(tp1);
240}
241
242static double mutex_end_timer(struct timespec tp1)
243{
244 struct timespec tp2;
245
246 clock_gettime_mono(&tp2);
247 return((tp2.tv_sec - tp1.tv_sec) +
248 (tp2.tv_nsec - tp1.tv_nsec)*1.0e-9);
249}
250
251/*
252 mutex lock function for thread model
253*/
254static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
255{
256 pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
257 int rc;
258 double t;
259 struct timespec tp1;
260 /* Test below is ONLY for debugging */
261 if ((rc = pthread_mutex_trylock(mutex))) {
262 if (rc == EBUSY) {
263 mutex_start_timer(&tp1);
264 printf("mutex lock: thread %d, lock %s not available\n",
265 (uint32_t)pthread_self(), name);
266 print_suspicious_usage("mutex_lock", name);
267 pthread_mutex_lock(mutex);
268 t = mutex_end_timer(tp1);
269 printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n",
270 (uint32_t)pthread_self(), name, t);
271 return 0;
272 }
273 printf("mutex lock: thread %d, lock %s failed rc=%d\n",
274 (uint32_t)pthread_self(), name, rc);
275 SMB_ASSERT(errno == 0); /* force error */
276 }
277 return 0;
278}
279
280/*
281 mutex unlock for thread model
282*/
283static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
284{
285 return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
286}
287
288/*****************************************************************
289 Read/write lock routines.
290*****************************************************************/
291/*
292 rwlock init function for thread model
293*/
294static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
295{
296 pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
297 rwlock->rwlock = memdup(&m, sizeof(m));
298 if (! rwlock->rwlock) {
299 errno = ENOMEM;
300 return -1;
301 }
302 return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
303}
304
305/*
306 rwlock destroy function for thread model
307*/
308static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
309{
310 return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
311}
312
313/*
314 rwlock lock for read function for thread model
315*/
316static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
317{
318 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
319 int rc;
320 double t;
321 struct timespec tp1;
322 /* Test below is ONLY for debugging */
323 if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
324 if (rc == EBUSY) {
325 mutex_start_timer(&tp1);
326 printf("rwlock lock_read: thread %d, lock %s not available\n",
327 (uint32_t)pthread_self(), name);
328 print_suspicious_usage("rwlock_lock_read", name);
329 pthread_rwlock_rdlock(rwlock);
330 t = mutex_end_timer(tp1);
331 printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n",
332 (uint32_t)pthread_self(), name, t);
333 return 0;
334 }
335 printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n",
336 (uint32_t)pthread_self(), name, rc);
337 SMB_ASSERT(errno == 0); /* force error */
338 }
339 return 0;
340}
341
342/*
343 rwlock lock for write function for thread model
344*/
345static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
346{
347 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
348 int rc;
349 double t;
350 struct timespec tp1;
351 /* Test below is ONLY for debugging */
352 if ((rc = pthread_rwlock_trywrlock(rwlock))) {
353 if (rc == EBUSY) {
354 mutex_start_timer(&tp1);
355 printf("rwlock lock_write: thread %d, lock %s not available\n",
356 (uint32_t)pthread_self(), name);
357 print_suspicious_usage("rwlock_lock_write", name);
358 pthread_rwlock_wrlock(rwlock);
359 t = mutex_end_timer(tp1);
360 printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n",
361 (uint32_t)pthread_self(), name, t);
362 return 0;
363 }
364 printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n",
365 (uint32_t)pthread_self(), name, rc);
366 SMB_ASSERT(errno == 0); /* force error */
367 }
368 return 0;
369}
370
371
372/*
373 rwlock unlock for thread model
374*/
375static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
376{
377 return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
378}
379
380/*****************************************************************
381 Log suspicious usage (primarily for possible thread-unsafe behavior).
382*****************************************************************/
383static void thread_log_suspicious_usage(const char* from, const char* info)
384{
385 DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
386#ifdef HAVE_BACKTRACE
387 {
388 void *addresses[10];
389 int num_addresses = backtrace(addresses, 8);
390 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
391 int i;
392
393 if (bt_symbols) {
394 for (i=0; i<num_addresses; i++) {
395 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
396 }
397 free(bt_symbols);
398 }
399 }
400#endif
401}
402
403/*****************************************************************
404 Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
405 Used in mutex code where DEBUG calls would cause recursion.
406*****************************************************************/
407static void thread_print_suspicious_usage(const char* from, const char* info)
408{
409 printf("log_suspicious_usage: from %s info='%s'\n", from, info);
410#ifdef HAVE_BACKTRACE
411 {
412 void *addresses[10];
413 int num_addresses = backtrace(addresses, 8);
414 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
415 int i;
416
417 if (bt_symbols) {
418 for (i=0; i<num_addresses; i++) {
419 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
420 }
421 free(bt_symbols);
422 }
423 }
424#endif
425}
426
427static uint32_t thread_get_task_id(void)
428{
429 return (uint32_t)pthread_self();
430}
431
432static void thread_log_task_id(int fd)
433{
434 char *s= NULL;
435
436 asprintf(&s, "thread[%u][%s]:\n",
437 (uint32_t)pthread_self(),
438 (const char *)pthread_getspecific(title_key));
439 if (!s) return;
440 write(fd, s, strlen(s));
441 free(s);
442}
443
444/****************************************************************************
445catch serious errors
446****************************************************************************/
447static void thread_sig_fault(int sig)
448{
449 DEBUG(0,("===============================================================\n"));
450 DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread [%u][%s] (%s)\n",
451 sig,(uint32_t)pthread_self(),
452 (const char *)pthread_getspecific(title_key),
453 SAMBA_VERSION_STRING));
454 DEBUG(0,("===============================================================\n"));
455 exit(1); /* kill the whole server for now */
456}
457
458/*******************************************************************
459setup our recursive fault handlers
460********************************************************************/
461static void thread_fault_setup(void)
462{
463#ifdef SIGSEGV
464 CatchSignal(SIGSEGV, thread_sig_fault);
465#endif
466#ifdef SIGBUS
467 CatchSignal(SIGBUS, thread_sig_fault);
468#endif
469#ifdef SIGABRT
470 CatchSignal(SIGABRT, thread_sig_fault);
471#endif
472}
473
474/*******************************************************************
475report a fault in a thread
476********************************************************************/
477static void thread_fault_handler(int sig)
478{
479 static int counter;
480
481 /* try to catch recursive faults */
482 thread_fault_setup();
483
484 counter++; /* count number of faults that have occurred */
485
486 DEBUG(0,("===============================================================\n"));
487 DEBUG(0,("INTERNAL ERROR: Signal %d in thread [%u] [%s] (%s)\n",
488 sig,(uint32_t)pthread_self(),
489 (const char *)pthread_getspecific(title_key),
490 SAMBA_VERSION_STRING));
491 DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
492 DEBUG(0,("===============================================================\n"));
493#ifdef HAVE_BACKTRACE
494 {
495 void *addresses[10];
496 int num_addresses = backtrace(addresses, 8);
497 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
498 int i;
499
500 if (bt_symbols) {
501 for (i=0; i<num_addresses; i++) {
502 DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
503 }
504 free(bt_symbols);
505 }
506 }
507#endif
508 pthread_exit(NULL); /* terminate failing thread only */
509}
510
511/*
512 called when the process model is selected
513*/
514static void thread_model_init(void)
515{
516 struct mutex_ops m_ops;
517 struct debug_ops d_ops;
518
519 ZERO_STRUCT(m_ops);
520 ZERO_STRUCT(d_ops);
521
522 pthread_key_create(&title_key, NULL);
523 pthread_setspecific(title_key, NULL);
524
525 /* register mutex/rwlock handlers */
526 m_ops.mutex_init = thread_mutex_init;
527 m_ops.mutex_lock = thread_mutex_lock;
528 m_ops.mutex_unlock = thread_mutex_unlock;
529 m_ops.mutex_destroy = thread_mutex_destroy;
530
531 m_ops.rwlock_init = thread_rwlock_init;
532 m_ops.rwlock_lock_write = thread_rwlock_lock_write;
533 m_ops.rwlock_lock_read = thread_rwlock_lock_read;
534 m_ops.rwlock_unlock = thread_rwlock_unlock;
535 m_ops.rwlock_destroy = thread_rwlock_destroy;
536
537 register_mutex_handlers("thread", &m_ops);
538
539 register_fault_handler("thread", thread_fault_handler);
540
541 d_ops.log_suspicious_usage = thread_log_suspicious_usage;
542 d_ops.print_suspicious_usage = thread_print_suspicious_usage;
543 d_ops.get_task_id = thread_get_task_id;
544 d_ops.log_task_id = thread_log_task_id;
545
546 register_debug_handlers("thread", &d_ops);
547}
548
549
550static const struct model_ops thread_ops = {
551 .name = "thread",
552 .model_init = thread_model_init,
553 .accept_connection = thread_accept_connection,
554 .new_task = thread_new_task,
555 .terminate = thread_terminate,
556 .set_title = thread_set_title,
557};
558
559/*
560 initialise the thread process model, registering ourselves with the model subsystem
561 */
562NTSTATUS process_model_thread_init(void)
563{
564 NTSTATUS ret;
565
566 /* register ourselves with the PROCESS_MODEL subsystem. */
567 ret = register_process_model(&thread_ops);
568 if (!NT_STATUS_IS_OK(ret)) {
569 DEBUG(0,("Failed to register process_model 'thread'!\n"));
570 return ret;
571 }
572
573 return ret;
574}
Note: See TracBrowser for help on using the repository browser.