rename mutex_t to smb_mutex_t to prevent name collision
[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    
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 #include "execinfo.h"
25
26 static void *connection_thread(void *thread_parm)
27 {
28         struct event_context *ev = thread_parm;
29         /* wait for action */
30         event_loop_wait(ev);
31         
32 #if 0
33         pthread_cleanup_pop(1);  /* will invoke terminate_mt_connection() */
34 #endif
35         return NULL;
36 }
37
38 static int get_id(struct request_context *req)
39 {
40         return (int)pthread_self();
41 }
42
43 /*
44   called when a listening socket becomes readable
45 */
46 static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
47 {
48         int accepted_fd, rc;
49         struct sockaddr addr;
50         socklen_t in_addrlen = sizeof(addr);
51         pthread_t thread_id;
52         pthread_attr_t thread_attr;
53         struct model_ops *model_ops = fde->private;
54         
55         /* accept an incoming connection */
56         accepted_fd = accept(fde->fd,&addr,&in_addrlen);
57                         
58         if (accepted_fd == -1) {
59                 DEBUG(0,("accept_connection_thread: accept: %s\n",
60                          strerror(errno)));
61                 return;
62         }
63         
64         /* create new detached thread for this connection.  The new
65            thread gets a new event_context with a single fd_event for
66            receiving from the new socket. We set that thread running
67            with the main event loop, then return. When we return the
68            main event_context is continued.
69         */
70         ev = event_context_init();
71         MUTEX_LOCK_BY_ID(MUTEX_SMBD);
72         init_smbsession(ev, model_ops, accepted_fd);
73         MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
74         
75         pthread_attr_init(&thread_attr);
76         pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
77         rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev);
78         pthread_attr_destroy(&thread_attr);
79         if (rc == 0) {
80                 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", 
81                         (unsigned long int)thread_id, accepted_fd));
82         } else {
83                 DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc));
84         }
85 }
86
87 /* called when a SMB connection goes down */
88 static void terminate_connection(struct server_context *server, const char *reason) 
89 {
90         server_terminate(server);
91
92         /* terminate this thread */
93         pthread_exit(NULL);  /* thread cleanup routine will do actual cleanup */
94 }
95
96 /*
97   mutex init function for thread model
98 */
99 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
100 {
101         pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
102         mutex->mutex = memdup(&m, sizeof(m));
103         if (! mutex->mutex) {
104                 errno = ENOMEM;
105                 return -1;
106         }
107         return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
108 }
109
110 /*
111   mutex destroy function for thread model
112 */
113 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
114 {
115         return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
116 }
117
118 static void mutex_start_timer(struct timeval *tp1)
119 {
120         gettimeofday(tp1,NULL);
121 }
122
123 static double mutex_end_timer(struct timeval tp1)
124 {
125         struct timeval tp2;
126         gettimeofday(&tp2,NULL);
127         return((tp2.tv_sec - tp1.tv_sec) + 
128                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
129 }
130
131 /*
132   mutex lock function for thread model
133 */
134 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
135 {
136         pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
137         int rc;
138         double t;
139         struct timeval tp1;
140         /* Test below is ONLY for debugging */
141         if ((rc = pthread_mutex_trylock(mutex))) {
142                 if (rc == EBUSY) {
143                         mutex_start_timer(&tp1);
144                         printf("mutex lock: thread %d, lock %s not available\n", 
145                                 (uint32)pthread_self(), name);
146                         print_suspicious_usage("mutex_lock", name);
147                         pthread_mutex_lock(mutex);
148                         t = mutex_end_timer(tp1);
149                         printf("mutex lock: thread %d, lock %s now available, waited %g seconds\n", 
150                                 (uint32)pthread_self(), name, t);
151                         return 0;
152                 }
153                 printf("mutex lock: thread %d, lock %s failed rc=%d\n", 
154                                 (uint32)pthread_self(), name, rc);
155                 SMB_ASSERT(errno == 0); /* force error */
156         }
157         return 0;
158 }
159
160 /* 
161    mutex unlock for thread model
162 */
163 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
164 {
165         return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
166 }
167
168 /*****************************************************************
169  Read/write lock routines.
170 *****************************************************************/  
171 /*
172   rwlock init function for thread model
173 */
174 static int thread_rwlock_init(rwlock_t *rwlock, const char *name)
175 {
176         pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
177         rwlock->rwlock = memdup(&m, sizeof(m));
178         if (! rwlock->rwlock) {
179                 errno = ENOMEM;
180                 return -1;
181         }
182         return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
183 }
184
185 /*
186   rwlock destroy function for thread model
187 */
188 static int thread_rwlock_destroy(rwlock_t *rwlock, const char *name)
189 {
190         return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
191 }
192
193 /*
194   rwlock lock for read function for thread model
195 */
196 static int thread_rwlock_lock_read(rwlock_t *rwlockP, const char *name)
197 {
198         pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
199         int rc;
200         double t;
201         struct timeval tp1;
202         /* Test below is ONLY for debugging */
203         if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
204                 if (rc == EBUSY) {
205                         mutex_start_timer(&tp1);
206                         printf("rwlock lock_read: thread %d, lock %s not available\n", 
207                                 (uint32)pthread_self(), name);
208                         print_suspicious_usage("rwlock_lock_read", name);
209                         pthread_rwlock_rdlock(rwlock);
210                         t = mutex_end_timer(tp1);
211                         printf("rwlock lock_read: thread %d, lock %s now available, waited %g seconds\n", 
212                                 (uint32)pthread_self(), name, t);
213                         return 0;
214                 }
215                 printf("rwlock lock_read: thread %d, lock %s failed rc=%d\n", 
216                                 (uint32)pthread_self(), name, rc);
217                 SMB_ASSERT(errno == 0); /* force error */
218         }
219         return 0;
220 }
221
222 /*
223   rwlock lock for write function for thread model
224 */
225 static int thread_rwlock_lock_write(rwlock_t *rwlockP, const char *name)
226 {
227         pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
228         int rc;
229         double t;
230         struct timeval tp1;
231         /* Test below is ONLY for debugging */
232         if ((rc = pthread_rwlock_trywrlock(rwlock))) {
233                 if (rc == EBUSY) {
234                         mutex_start_timer(&tp1);
235                         printf("rwlock lock_write: thread %d, lock %s not available\n", 
236                                 (uint32)pthread_self(), name);
237                         print_suspicious_usage("rwlock_lock_write", name);
238                         pthread_rwlock_wrlock(rwlock);
239                         t = mutex_end_timer(tp1);
240                         printf("rwlock lock_write: thread %d, lock %s now available, waited %g seconds\n", 
241                                 (uint32)pthread_self(), name, t);
242                         return 0;
243                 }
244                 printf("rwlock lock_write: thread %d, lock %s failed rc=%d\n", 
245                                 (uint32)pthread_self(), name, rc);
246                 SMB_ASSERT(errno == 0); /* force error */
247         }
248         return 0;
249 }
250
251
252 /* 
253    rwlock unlock for thread model
254 */
255 static int thread_rwlock_unlock(rwlock_t *rwlock, const char *name)
256 {
257         return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
258 }
259
260 /*****************************************************************
261  Log suspicious usage (primarily for possible thread-unsafe behavior.
262 *****************************************************************/  
263 static void thread_log_suspicious_usage(const char* from, const char* info)
264 {
265         void *addresses[10];
266         int num_addresses, i;
267         char **bt_symbols;
268         
269         DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
270         num_addresses = backtrace(addresses, 8);
271         bt_symbols = backtrace_symbols(addresses, num_addresses);
272         for (i=0; i<num_addresses; i++) {
273                 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
274         }
275         free(bt_symbols);
276 }
277
278 /*****************************************************************
279  Log suspicious usage to stdout (primarily for possible thread-unsafe behavior.
280  Used in mutex code where DEBUG calls would cause recursion.
281 *****************************************************************/  
282 static void thread_print_suspicious_usage(const char* from, const char* info)
283 {
284         void *addresses[10];
285         int num_addresses, i;
286         char **bt_symbols;
287         
288         printf("log_suspicious_usage: from %s info='%s'\n", from, info);
289         num_addresses = backtrace(addresses, 8);
290         bt_symbols = backtrace_symbols(addresses, num_addresses);
291         for (i=0; i<num_addresses; i++) {
292                 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
293         }
294         free(bt_symbols);
295 }
296
297 uint32 thread_get_task_id(void)
298 {
299         return (uint32)pthread_self();
300 }
301
302 /****************************************************************************
303 catch serious errors
304 ****************************************************************************/
305 static void thread_sig_fault(int sig)
306 {
307         DEBUG(0,("===============================================================\n"));
308         DEBUG(0,("TERMINAL ERROR: Recursive signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION));
309         DEBUG(0,("===============================================================\n"));
310         exit(1); /* kill the whole server for now */
311 }
312
313 /*******************************************************************
314 setup our recursive fault handlers
315 ********************************************************************/
316 static void thread_fault_setup(void)
317 {
318 #ifdef SIGSEGV
319         CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault);
320 #endif
321 #ifdef SIGBUS
322         CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault);
323 #endif
324 }
325
326 /*******************************************************************
327 report a fault in a thread
328 ********************************************************************/
329 static void thread_fault_handler(int sig)
330 {
331         static int counter;
332         void *addresses[10];
333         int num_addresses, i;
334         char **bt_symbols;
335         
336         /* try to catch recursive faults */
337         thread_fault_setup();
338         
339         counter++;      /* count number of faults that have occurred */
340
341         DEBUG(0,("===============================================================\n"));
342         DEBUG(0,("INTERNAL ERROR: Signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION));
343         DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
344         DEBUG(0,("===============================================================\n"));
345
346         num_addresses = backtrace(addresses, 10);
347         bt_symbols = backtrace_symbols(addresses, num_addresses);
348         for (i=0; i<num_addresses; i++) {
349                 DEBUG(9,("fault_report:   %s\n", bt_symbols[i]));
350         }
351         free(bt_symbols);
352         pthread_exit(NULL); /* terminate failing thread only */
353 }
354
355 /*
356   called when the process model is selected
357 */
358 static void model_startup(void)
359 {
360         struct mutex_ops m_ops;
361         struct debug_ops d_ops;
362
363         ZERO_STRUCT(m_ops);
364         ZERO_STRUCT(d_ops);
365
366         smbd_process_init();
367
368         /* register mutex/rwlock handlers */
369         m_ops.mutex_init = thread_mutex_init;
370         m_ops.mutex_lock = thread_mutex_lock;
371         m_ops.mutex_unlock = thread_mutex_unlock;
372         m_ops.mutex_destroy = thread_mutex_destroy;
373         
374         m_ops.rwlock_init = thread_rwlock_init;
375         m_ops.rwlock_lock_write = thread_rwlock_lock_write;
376         m_ops.rwlock_lock_read = thread_rwlock_lock_read;
377         m_ops.rwlock_unlock = thread_rwlock_unlock;
378         m_ops.rwlock_destroy = thread_rwlock_destroy;
379
380         register_mutex_handlers("thread", &m_ops);
381
382         register_fault_handler("thread", thread_fault_handler);
383
384         d_ops.log_suspicious_usage = thread_log_suspicious_usage;
385         d_ops.print_suspicious_usage = thread_print_suspicious_usage;
386         d_ops.get_task_id = thread_get_task_id;
387
388         register_debug_handlers("thread", &d_ops);      
389 }
390
391 /*
392   initialise the thread process model, registering ourselves with the model subsystem
393  */
394 void process_model_thread_init(void)
395 {
396         struct model_ops ops;
397
398         ZERO_STRUCT(ops);
399         
400         /* fill in all the operations */
401         ops.model_startup = model_startup;
402         ops.accept_connection = accept_connection;
403         ops.terminate_connection = terminate_connection;
404         ops.exit_server = NULL;
405         ops.get_id = get_id;
406         
407         /* register ourselves with the process model subsystem. We
408            register under the name 'thread'. */
409         register_process_model("thread", &ops);
410 }