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
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.
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.
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.
28 #include "system/wait.h"
30 #include "dlinklist.h"
31 #include "smb_server/smb_server.h"
32 #include "process_model.h"
34 static void *thread_connection_fn(void *thread_parm)
36 struct event_context *ev = thread_parm;
41 pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */
46 static int thread_get_id(struct smbsrv_request *req)
48 return (int)pthread_self();
52 called when a listening socket becomes readable
54 static void thread_accept_connection(struct event_context *ev, struct fd_event *srv_fde,
55 struct timeval t, uint16_t flags)
58 struct socket_context *sock;
61 pthread_attr_t thread_attr;
62 struct server_socket *server_socket = srv_fde->private;
63 struct server_connection *conn;
65 /* accept an incoming connection. */
66 status = socket_accept(server_socket->socket, &sock);
67 if (!NT_STATUS_IS_OK(status)) {
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.
78 ev = event_context_init(server_socket);
84 conn = server_setup_connection(ev, server_socket, sock, t, pthread_self());
86 event_context_destroy(ev);
91 talloc_steal(conn, ev);
92 talloc_steal(conn, sock);
94 /* TODO: is this MUTEX_LOCK in the right place here?
97 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
98 DLIST_ADD(server_socket->connection_list,conn);
99 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
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);
106 DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n",
107 (unsigned long int)thread_id, socket_get_fd(sock)));
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);
116 /* called when a SMB connection goes down */
117 static void thread_terminate_connection(struct server_connection *conn, const char *reason)
119 DEBUG(10,("thread_terminate_connection: reason[%s]\n",reason));
125 /* terminate this thread */
126 pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
130 mutex init function for thread model
132 static int thread_mutex_init(smb_mutex_t *mutex, const char *name)
134 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
135 mutex->mutex = memdup(&m, sizeof(m));
136 if (! mutex->mutex) {
140 return pthread_mutex_init((pthread_mutex_t *)mutex->mutex, NULL);
144 mutex destroy function for thread model
146 static int thread_mutex_destroy(smb_mutex_t *mutex, const char *name)
148 return pthread_mutex_destroy((pthread_mutex_t *)mutex->mutex);
151 static void mutex_start_timer(struct timeval *tp1)
153 gettimeofday(tp1,NULL);
156 static double mutex_end_timer(struct timeval tp1)
159 gettimeofday(&tp2,NULL);
160 return((tp2.tv_sec - tp1.tv_sec) +
161 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
165 mutex lock function for thread model
167 static int thread_mutex_lock(smb_mutex_t *mutexP, const char *name)
169 pthread_mutex_t *mutex = (pthread_mutex_t *)mutexP->mutex;
173 /* Test below is ONLY for debugging */
174 if ((rc = pthread_mutex_trylock(mutex))) {
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);
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 */
194 mutex unlock for thread model
196 static int thread_mutex_unlock(smb_mutex_t *mutex, const char *name)
198 return pthread_mutex_unlock((pthread_mutex_t *)mutex->mutex);
201 /*****************************************************************
202 Read/write lock routines.
203 *****************************************************************/
205 rwlock init function for thread model
207 static int thread_rwlock_init(smb_rwlock_t *rwlock, const char *name)
209 pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER;
210 rwlock->rwlock = memdup(&m, sizeof(m));
211 if (! rwlock->rwlock) {
215 return pthread_rwlock_init((pthread_rwlock_t *)rwlock->rwlock, NULL);
219 rwlock destroy function for thread model
221 static int thread_rwlock_destroy(smb_rwlock_t *rwlock, const char *name)
223 return pthread_rwlock_destroy((pthread_rwlock_t *)rwlock->rwlock);
227 rwlock lock for read function for thread model
229 static int thread_rwlock_lock_read(smb_rwlock_t *rwlockP, const char *name)
231 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
235 /* Test below is ONLY for debugging */
236 if ((rc = pthread_rwlock_tryrdlock(rwlock))) {
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);
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 */
256 rwlock lock for write function for thread model
258 static int thread_rwlock_lock_write(smb_rwlock_t *rwlockP, const char *name)
260 pthread_rwlock_t *rwlock = (pthread_rwlock_t *)rwlockP->rwlock;
264 /* Test below is ONLY for debugging */
265 if ((rc = pthread_rwlock_trywrlock(rwlock))) {
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);
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 */
286 rwlock unlock for thread model
288 static int thread_rwlock_unlock(smb_rwlock_t *rwlock, const char *name)
290 return pthread_rwlock_unlock((pthread_rwlock_t *)rwlock->rwlock);
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)
298 DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
299 #ifdef HAVE_BACKTRACE
302 int num_addresses = backtrace(addresses, 8);
303 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
307 for (i=0; i<num_addresses; i++) {
308 DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
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)
322 printf("log_suspicious_usage: from %s info='%s'\n", from, info);
323 #ifdef HAVE_BACKTRACE
326 int num_addresses = backtrace(addresses, 8);
327 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
331 for (i=0; i<num_addresses; i++) {
332 printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
340 static uint32_t thread_get_task_id(void)
342 return (uint32_t)pthread_self();
345 static void thread_log_task_id(int fd)
349 asprintf(&s, "thread %u: ", (uint32_t)pthread_self());
350 write(fd, s, strlen(s));
353 /****************************************************************************
355 ****************************************************************************/
356 static void thread_sig_fault(int sig)
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 */
364 /*******************************************************************
365 setup our recursive fault handlers
366 ********************************************************************/
367 static void thread_fault_setup(void)
370 CatchSignal(SIGSEGV,SIGNAL_CAST thread_sig_fault);
373 CatchSignal(SIGBUS,SIGNAL_CAST thread_sig_fault);
376 CatchSignal(SIGABRT,SIGNAL_CAST thread_sig_fault);
380 /*******************************************************************
381 report a fault in a thread
382 ********************************************************************/
383 static void thread_fault_handler(int sig)
387 /* try to catch recursive faults */
388 thread_fault_setup();
390 counter++; /* count number of faults that have occurred */
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
399 int num_addresses = backtrace(addresses, 8);
400 char **bt_symbols = backtrace_symbols(addresses, num_addresses);
404 for (i=0; i<num_addresses; i++) {
405 DEBUG(1,("fault_report: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
411 pthread_exit(NULL); /* terminate failing thread only */
415 called when the process model is selected
417 static void thread_model_startup(void)
419 struct mutex_ops m_ops;
420 struct debug_ops d_ops;
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;
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;
439 register_mutex_handlers("thread", &m_ops);
441 register_fault_handler("thread", thread_fault_handler);
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;
448 register_debug_handlers("thread", &d_ops);
451 static void thread_exit_server(struct server_context *srv_ctx, const char *reason)
453 DEBUG(1,("thread_exit_server: reason[%s]\n",reason));
457 initialise the thread process model, registering ourselves with the model subsystem
459 NTSTATUS process_model_thread_init(void)
462 struct model_ops ops;
466 /* fill in our name */
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;
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"));