- move the vars used by the backtrace stuff into the #ifdef
[samba.git] / source4 / smbd / process_thread.c
1 /* 
2    Unix SMB/CIFS implementation.
3    thread model: standard (1 thread per client connection)
4    Copyright (C) Andrew Tridgell 2003
5    Copyright (C) James J Myers 2003 <myersjj@samba.org>
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "pthread.h"
24 #ifdef HAVE_BACKTRACE
25 #include "execinfo.h"
26 #endif
27
28 static void *connection_thread(void *thread_parm)
29 {
30         struct event_context *ev = thread_parm;
31         /* wait for action */
32         event_loop_wait(ev);
33         
34 #if 0
35         pthread_cleanup_pop(1);  /* will invoke terminate_mt_connection() */
36 #endif
37         return NULL;
38 }
39
40 static int get_id(struct request_context *req)
41 {
42         return (int)pthread_self();
43 }
44
45 /*
46   called when a listening socket becomes readable
47 */
48 static void accept_connection(struct event_context *ev, struct fd_event *fde, 
49                               time_t t, uint16 flags)
50 {
51         int accepted_fd, rc;
52         struct sockaddr addr;
53         socklen_t in_addrlen = sizeof(addr);
54         pthread_t thread_id;
55         pthread_attr_t thread_attr;
56         struct model_ops *model_ops = fde->private;
57         
58         /* accept an incoming connection */
59         accepted_fd = accept(fde->fd,&addr,&in_addrlen);
60                         
61         if (accepted_fd == -1) {
62                 DEBUG(0,("accept_connection_thread: accept: %s\n",
63                          strerror(errno)));
64                 return;
65         }
66         
67         /* create new detached thread for this connection.  The new
68            thread gets a new event_context with a single fd_event for
69            receiving from the new socket. We set that thread running
70            with the main event loop, then return. When we return the
71            main event_context is continued.
72         */
73         ev = event_context_init();
74         MUTEX_LOCK_BY_ID(MUTEX_SMBD);
75         init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler);
76         MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
77         
78         pthread_attr_init(&thread_attr);
79         pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
80         rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev);
81         pthread_attr_destroy(&thread_attr);
82         if (rc == 0) {
83                 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", 
84                         (unsigned long int)thread_id, accepted_fd));
85         } else {
86                 DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc));
87         }
88 }
89
90
91 /*
92   called when a rpc listening socket becomes readable
93 */
94 static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
95 {
96         int accepted_fd, rc;
97         struct sockaddr addr;
98         socklen_t in_addrlen = sizeof(addr);
99         pthread_t thread_id;
100         pthread_attr_t thread_attr;
101         
102         /* accept an incoming connection */
103         accepted_fd = accept(fde->fd,&addr,&in_addrlen);
104                         
105         if (accepted_fd == -1) {
106                 DEBUG(0,("accept_connection_thread: accept: %s\n",
107                          strerror(errno)));
108                 return;
109         }
110         
111         ev = event_context_init();
112         MUTEX_LOCK_BY_ID(MUTEX_SMBD);
113         init_rpc_session(ev, fde->private, accepted_fd);
114         MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
115         
116         pthread_attr_init(&thread_attr);
117         pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
118         rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev);
119         pthread_attr_destroy(&thread_attr);
120         if (rc == 0) {
121                 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", 
122                         (unsigned long int)thread_id, accepted_fd));
123         } else {
124                 DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc));
125         }
126 }
127
128 /* called when a SMB connection goes down */
129 static void terminate_connection(struct server_context *server, const char *reason) 
130 {
131         server_terminate(server);
132
133         /* terminate this thread */
134         pthread_exit(NULL);  /* thread cleanup routine will do actual cleanup */
135 }
136
137 /* called when a rpc connection goes down */
138 static void terminate_rpc_connection(void *r, const char *reason) 
139 {
140         rpc_server_terminate(r);
141
142         /* terminate this thread */
143         pthread_exit(NULL);  /* thread cleanup routine will do actual cleanup */
144 }
145
146 /*
147   mutex init function for thread model
148 */
149 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
150 {
151         pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
152         mutex->mutex = memdup(&m, sizeof(m));
153         if (! mutex->mutex) {
154                 errno = ENOMEM;
155                 return -1;
156         }
157         return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
158 }
159
160 /*
161   mutex destroy function for thread model
162 */
163 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
164 {
165         return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
166 }
167
168 static void mutex_start_timer(struct timeval *tp1)
169 {
170         gettimeofday(tp1,NULL);
171 }
172
173 static double mutex_end_timer(struct timeval tp1)
174 {
175         struct timeval tp2;
176         gettimeofday(&tp2,NULL);
177         return((tp2.tv_sec - tp1.tv_sec) + 
178                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
179 }
180
181 /*
182   mutex lock function for thread model
183 */
184 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
185 {
186         pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
187         int rc;
188         double t;
189         struct timeval tp1;
190         /* Test below is ONLY for debugging */
191         if ((rc = pthread_mutex_trylock(mutex))) {
192                 if (rc == EBUSY) {
193                         mutex_start_timer(&tp1);
194                         printf("mutex lock: thread %d, lock %s not available\n", 
195                                 (uint32)pthread_self(), name);
196                         print_suspicious_usage("mutex_lock", name);
197                         pthread_mutex_lock(mutex);
198                         t = mutex_end_timer(tp1);
199                         printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n", 
200                                 (uint32)pthread_self(), name, t);
201                         return 0;
202                 }
203                 printf("mutex lock: thread %d, lock %s failed rc=%d\n", 
204                                 (uint32)pthread_self(), name, rc);
205                 SMB_ASSERT(errno == 0); /* force error */
206         }
207         return 0;
208 }
209
210 /* 
211    mutex unlock for thread model
212 */
213 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
214 {
215         return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
216 }
217
218 /*****************************************************************
219  Read/write lock routines.
220 *****************************************************************/  
221 /*
222   rwlock init function for thread model
223 */
224 static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
225 {
226         pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
227         rwlock->rwlock = memdup(&m, sizeof(m));
228         if (! rwlock->rwlock) {
229                 errno = ENOMEM;
230                 return -1;
231         }
232         return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
233 }
234
235 /*
236   rwlock destroy function for thread model
237 */
238 static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
239 {
240         return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
241 }
242
243 /*
244   rwlock lock for read function for thread model
245 */
246 static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
247 {
248         pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
249         int rc;
250         double t;
251         struct timeval tp1;
252         /* Test below is ONLY for debugging */
253         if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
254                 if (rc == EBUSY) {
255                         mutex_start_timer(&tp1);
256                         printf("rwlock lock_read: thread %d, lock %s not available\n", 
257                                 (uint32)pthread_self(), name);
258                         print_suspicious_usage("rwlock_lock_read", name);
259                         pthread_rwlock_rdlock(rwlock);
260                         t = mutex_end_timer(tp1);
261                         printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n", 
262                                 (uint32)pthread_self(), name, t);
263                         return 0;
264                 }
265                 printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n", 
266                                 (uint32)pthread_self(), name, rc);
267                 SMB_ASSERT(errno == 0); /* force error */
268         }
269         return 0;
270 }
271
272 /*
273   rwlock lock for write function for thread model
274 */
275 static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
276 {
277         pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
278         int rc;
279         double t;
280         struct timeval tp1;
281         /* Test below is ONLY for debugging */
282         if ((rc = pthread_rwlock_trywrlock(rwlock))) {
283                 if (rc == EBUSY) {
284                         mutex_start_timer(&tp1);
285                         printf("rwlock lock_write: thread %d, lock %s not available\n", 
286                                 (uint32)pthread_self(), name);
287                         print_suspicious_usage("rwlock_lock_write", name);
288                         pthread_rwlock_wrlock(rwlock);
289                         t = mutex_end_timer(tp1);
290                         printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n", 
291                                 (uint32)pthread_self(), name, t);
292                         return 0;
293                 }
294                 printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n", 
295                                 (uint32)pthread_self(), name, rc);
296                 SMB_ASSERT(errno == 0); /* force error */
297         }
298         return 0;
299 }
300
301
302 /* 
303    rwlock unlock for thread model
304 */
305 static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
306 {
307         return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
308 }
309
310 /*****************************************************************
311  Log suspicious usage (primarily for possible thread-unsafe behavior.
312 *****************************************************************/  
313 static void thread_log_suspicious_usage(const char* from, const char* info)
314 {
315         DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
316 #ifdef HAVE_BACKTRACE
317         {
318                 void *addresses[10];
319                 int num_addresses = backtrace(addresses, 8);
320                 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
321                 int i;
322
323                 if (bt_symbols) {
324                         for (i=0; i<num_addresses; i++) {
325                                 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
326                         }
327                         free(bt_symbols);
328                 }
329         }
330 #endif
331 }
332
333 /*****************************************************************
334  Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
335  Used in mutex code where DEBUG calls would cause recursion.
336 *****************************************************************/  
337 static void thread_print_suspicious_usage(const char* from, const char* info)
338 {
339         printf("log_suspicious_usage: from %s info='%s'\n", from, info);
340 #ifdef HAVE_BACKTRACE
341         {
342                 void *addresses[10];
343                 int num_addresses = backtrace(addresses, 8);
344                 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
345                 int i;
346
347                 if (bt_symbols) {
348                         for (i=0; i<num_addresses; i++) {
349                                 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
350                         }
351                         free(bt_symbols);
352                 }
353         }
354 #endif
355 }
356
357 static uint32 thread_get_task_id(void)
358 {
359         return (uint32)pthread_self();
360 }
361
362 static void thread_log_task_id(int fd)
363 {
364         char *s;
365         
366         asprintf(&s, "thread %u: ", (uint32)pthread_self());
367         write(fd, s, strlen(s));
368         free(s);
369 }
370 /****************************************************************************
371 catch serious errors
372 ****************************************************************************/
373 static void thread_sig_fault(int sig)
374 {
375         DEBUG(0,("===============================================================\n"));
376         DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION));
377         DEBUG(0,("===============================================================\n"));
378         exit(1); /* kill the whole server for now */
379 }
380
381 /*******************************************************************
382 setup our recursive fault handlers
383 ********************************************************************/
384 static void thread_fault_setup(void)
385 {
386 #ifdef SIGSEGV
387         CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault);
388 #endif
389 #ifdef SIGBUS
390         CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault);
391 #endif
392 #ifdef SIGABRT
393         CatchSignal(SIGABRT,SIGNAL_CAST thread_sig_fault);
394 #endif
395 }
396
397 /*******************************************************************
398 report a fault in a thread
399 ********************************************************************/
400 static void thread_fault_handler(int sig)
401 {
402         static int counter;
403         
404         /* try to catch recursive faults */
405         thread_fault_setup();
406         
407         counter++;      /* count number of faults that have occurred */
408
409         DEBUG(0,("===============================================================\n"));
410         DEBUG(0,("INTERNAL ERROR: Signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION));
411         DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
412         DEBUG(0,("===============================================================\n"));
413 #ifdef HAVE_BACKTRACE
414         {
415                 void *addresses[10];
416                 int num_addresses = backtrace(addresses, 8);
417                 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
418                 int i;
419
420                 if (bt_symbols) {
421                         for (i=0; i<num_addresses; i++) {
422                                 DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
423                         }
424                         free(bt_symbols);
425                 }
426         }
427 #endif
428         pthread_exit(NULL); /* terminate failing thread only */
429 }
430
431 /*
432   called when the process model is selected
433 */
434 static void model_startup(void)
435 {
436         struct mutex_ops m_ops;
437         struct debug_ops d_ops;
438
439         ZERO_STRUCT(m_ops);
440         ZERO_STRUCT(d_ops);
441
442         smbd_process_init();
443
444         /* register mutex/rwlock handlers */
445         m_ops.mutex_init = thread_mutex_init;
446         m_ops.mutex_lock = thread_mutex_lock;
447         m_ops.mutex_unlock = thread_mutex_unlock;
448         m_ops.mutex_destroy = thread_mutex_destroy;
449         
450         m_ops.rwlock_init = thread_rwlock_init;
451         m_ops.rwlock_lock_write = thread_rwlock_lock_write;
452         m_ops.rwlock_lock_read = thread_rwlock_lock_read;
453         m_ops.rwlock_unlock = thread_rwlock_unlock;
454         m_ops.rwlock_destroy = thread_rwlock_destroy;
455
456         register_mutex_handlers("thread", &m_ops);
457
458         register_fault_handler("thread", thread_fault_handler);
459
460         d_ops.log_suspicious_usage = thread_log_suspicious_usage;
461         d_ops.print_suspicious_usage = thread_print_suspicious_usage;
462         d_ops.get_task_id = thread_get_task_id;
463         d_ops.log_task_id = thread_log_task_id;
464
465         register_debug_handlers("thread", &d_ops);      
466 }
467
468 /*
469   initialise the thread process model, registering ourselves with the model subsystem
470  */
471 void process_model_thread_init(void)
472 {
473         struct model_ops ops;
474
475         ZERO_STRUCT(ops);
476         
477         /* fill in all the operations */
478         ops.model_startup = model_startup;
479         ops.accept_connection = accept_connection;
480         ops.accept_rpc_connection = accept_rpc_connection;
481         ops.terminate_connection = terminate_connection;
482         ops.terminate_rpc_connection = terminate_rpc_connection;
483         ops.exit_server = NULL;
484         ops.get_id = get_id;
485         
486         /* register ourselves with the process model subsystem. We
487            register under the name 'thread'. */
488         register_process_model("thread", &ops);
489 }