9acd49916b9bd4b27e0eae74095acfa46ed2bfe5
[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         void *addresses[10];
316         int num_addresses, i;
317         char **bt_symbols;
318         
319         DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
320 #ifdef HAVE_BACKTRACE
321         num_addresses = backtrace(addresses, 8);
322         bt_symbols = backtrace_symbols(addresses, num_addresses);
323         for (i=0; i<num_addresses; i++) {
324                 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
325         }
326         free(bt_symbols);
327 #endif
328 }
329
330 /*****************************************************************
331  Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
332  Used in mutex code where DEBUG calls would cause recursion.
333 *****************************************************************/  
334 static void thread_print_suspicious_usage(const char* from, const char* info)
335 {
336         void *addresses[10];
337         int num_addresses, i;
338         char **bt_symbols;
339         
340         printf("log_suspicious_usage: from %s info='%s'\n", from, info);
341 #ifdef HAVE_BACKTRACE
342         num_addresses = backtrace(addresses, 8);
343         bt_symbols = backtrace_symbols(addresses, num_addresses);
344         for (i=0; i<num_addresses; i++) {
345                 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
346         }
347         free(bt_symbols);
348 #endif
349 }
350
351 static uint32 thread_get_task_id(void)
352 {
353         return (uint32)pthread_self();
354 }
355
356 static void thread_log_task_id(int fd)
357 {
358         char *s;
359         
360         asprintf(&s, "thread %u: ", (uint32)pthread_self());
361         write(fd, s, strlen(s));
362         free(s);
363 }
364 /****************************************************************************
365 catch serious errors
366 ****************************************************************************/
367 static void thread_sig_fault(int sig)
368 {
369         DEBUG(0,("===============================================================\n"));
370         DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION));
371         DEBUG(0,("===============================================================\n"));
372         exit(1); /* kill the whole server for now */
373 }
374
375 /*******************************************************************
376 setup our recursive fault handlers
377 ********************************************************************/
378 static void thread_fault_setup(void)
379 {
380 #ifdef SIGSEGV
381         CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault);
382 #endif
383 #ifdef SIGBUS
384         CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault);
385 #endif
386 }
387
388 /*******************************************************************
389 report a fault in a thread
390 ********************************************************************/
391 static void thread_fault_handler(int sig)
392 {
393         static int counter;
394         void *addresses[10];
395         int num_addresses, i;
396         char **bt_symbols;
397         
398         /* try to catch recursive faults */
399         thread_fault_setup();
400         
401         counter++;      /* count number of faults that have occurred */
402
403         DEBUG(0,("===============================================================\n"));
404         DEBUG(0,("INTERNAL ERROR: Signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION));
405         DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
406         DEBUG(0,("===============================================================\n"));
407 #ifdef HAVE_BACKTRACE
408         num_addresses = backtrace(addresses, 10);
409         bt_symbols = backtrace_symbols(addresses, num_addresses);
410         for (i=0; i<num_addresses; i++) {
411                 DEBUG(9,("fault_report:   %s\n", bt_symbols[i]));
412         }
413         free(bt_symbols);
414 #endif
415         pthread_exit(NULL); /* terminate failing thread only */
416 }
417
418 /*
419   called when the process model is selected
420 */
421 static void model_startup(void)
422 {
423         struct mutex_ops m_ops;
424         struct debug_ops d_ops;
425
426         ZERO_STRUCT(m_ops);
427         ZERO_STRUCT(d_ops);
428
429         smbd_process_init();
430
431         /* register mutex/rwlock handlers */
432         m_ops.mutex_init = thread_mutex_init;
433         m_ops.mutex_lock = thread_mutex_lock;
434         m_ops.mutex_unlock = thread_mutex_unlock;
435         m_ops.mutex_destroy = thread_mutex_destroy;
436         
437         m_ops.rwlock_init = thread_rwlock_init;
438         m_ops.rwlock_lock_write = thread_rwlock_lock_write;
439         m_ops.rwlock_lock_read = thread_rwlock_lock_read;
440         m_ops.rwlock_unlock = thread_rwlock_unlock;
441         m_ops.rwlock_destroy = thread_rwlock_destroy;
442
443         register_mutex_handlers("thread", &m_ops);
444
445         register_fault_handler("thread", thread_fault_handler);
446
447         d_ops.log_suspicious_usage = thread_log_suspicious_usage;
448         d_ops.print_suspicious_usage = thread_print_suspicious_usage;
449         d_ops.get_task_id = thread_get_task_id;
450         d_ops.log_task_id = thread_log_task_id;
451
452         register_debug_handlers("thread", &d_ops);      
453 }
454
455 /*
456   initialise the thread process model, registering ourselves with the model subsystem
457  */
458 void process_model_thread_init(void)
459 {
460         struct model_ops ops;
461
462         ZERO_STRUCT(ops);
463         
464         /* fill in all the operations */
465         ops.model_startup = model_startup;
466         ops.accept_connection = accept_connection;
467         ops.accept_rpc_connection = accept_rpc_connection;
468         ops.terminate_connection = terminate_connection;
469         ops.terminate_rpc_connection = terminate_rpc_connection;
470         ops.exit_server = NULL;
471         ops.get_id = get_id;
472         
473         /* register ourselves with the process model subsystem. We
474            register under the name 'thread'. */
475         register_process_model("thread", &ops);
476 }