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