2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
2005-01-30 03:54:57 +03:00
2003-08-13 05:53:07 +04:00
thread model : standard ( 1 thread per client connection )
2005-01-30 03:54:57 +03:00
Copyright ( C ) Andrew Tridgell 2003 - 2005
2003-08-13 05:53:07 +04:00
Copyright ( C ) James J Myers 2003 < myersjj @ samba . org >
2004-07-14 01:04:56 +04:00
Copyright ( C ) Stefan ( metze ) Metzmacher 2004
2003-08-13 05:53:07 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2005-01-18 12:30:43 +03:00
# include "version.h"
2004-11-04 05:19:25 +03:00
# include <pthread.h>
# ifdef HAVE_BACKTRACE
# include <execinfo.h>
# endif
# include "system/wait.h"
2005-02-10 08:29:38 +03:00
# include "system/filesys.h"
2010-09-07 05:25:42 +04:00
# include "system/time.h"
2005-02-03 14:56:03 +03:00
# include "lib/events/events.h"
2006-08-30 15:29:34 +04:00
# include "lib/util/dlinklist.h"
2006-03-09 20:58:25 +03:00
# include "lib/util/mutex.h"
2006-03-26 05:23:40 +04:00
# include "smbd/process_model.h"
2005-01-30 03:54:57 +03:00
2006-03-09 23:51:24 +03:00
static pthread_key_t title_key ;
2005-01-30 03:54:57 +03:00
struct new_conn_state {
2008-12-29 22:24:57 +03:00
struct tevent_context * ev ;
2005-01-30 03:54:57 +03:00
struct socket_context * sock ;
2008-01-06 04:03:43 +03:00
struct loadparm_context * lp_ctx ;
2008-12-29 22:24:57 +03:00
void ( * new_conn ) ( struct tevent_context * , struct loadparm_context * lp_ctx , struct socket_context * , uint32_t , void * ) ;
2009-02-02 10:41:28 +03:00
void * private_data ;
2005-01-30 03:54:57 +03:00
} ;
2003-08-13 05:53:07 +04:00
2004-07-14 01:04:56 +04:00
static void * thread_connection_fn ( void * thread_parm )
2003-08-13 05:53:07 +04:00
{
2005-01-30 03:54:57 +03:00
struct new_conn_state * new_conn = talloc_get_type ( thread_parm , struct new_conn_state ) ;
2005-01-14 04:32:56 +03:00
2009-02-02 10:41:28 +03:00
new_conn - > new_conn ( new_conn - > ev , new_conn - > lp_ctx , new_conn - > sock , pthread_self ( ) , new_conn - > private_data ) ;
2005-01-14 04:32:56 +03:00
2005-01-30 03:54:57 +03:00
/* run this connection from here */
event_loop_wait ( new_conn - > ev ) ;
talloc_free ( new_conn ) ;
2004-07-14 01:04:56 +04:00
2003-08-13 05:53:07 +04:00
return NULL ;
}
/*
called when a listening socket becomes readable
*/
2008-12-29 22:24:57 +03:00
static void thread_accept_connection ( struct tevent_context * ev ,
2010-07-16 08:32:42 +04:00
struct loadparm_context * lp_ctx ,
2005-01-30 03:54:57 +03:00
struct socket_context * sock ,
2008-12-29 22:24:57 +03:00
void ( * new_conn ) ( struct tevent_context * ,
2008-01-06 04:03:43 +03:00
struct loadparm_context * ,
struct socket_context * ,
2005-01-30 03:54:57 +03:00
uint32_t , void * ) ,
2009-02-02 10:41:28 +03:00
void * private_data )
2004-07-14 01:04:56 +04:00
{
2004-09-20 16:31:07 +04:00
NTSTATUS status ;
int rc ;
2003-08-13 05:53:07 +04:00
pthread_t thread_id ;
pthread_attr_t thread_attr ;
2005-01-30 03:54:57 +03:00
struct new_conn_state * state ;
2008-12-29 22:24:57 +03:00
struct tevent_context * ev2 ;
2004-07-14 01:04:56 +04:00
2008-06-14 21:00:53 +04:00
ev2 = s4_event_context_init ( ev ) ;
2005-01-30 03:54:57 +03:00
if ( ev2 = = NULL ) return ;
2005-01-14 04:32:56 +03:00
2005-01-30 03:54:57 +03:00
state = talloc ( ev2 , struct new_conn_state ) ;
if ( state = = NULL ) {
talloc_free ( ev2 ) ;
2005-01-14 04:32:56 +03:00
return ;
2003-12-13 13:58:48 +03:00
}
2005-01-30 03:54:57 +03:00
state - > new_conn = new_conn ;
2009-02-02 10:41:28 +03:00
state - > private_data = private_data ;
2008-01-06 04:03:43 +03:00
state - > lp_ctx = lp_ctx ;
2005-01-30 03:54:57 +03:00
state - > ev = ev2 ;
/* accept an incoming connection. */
status = socket_accept ( sock , & state - > sock ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( ev2 ) ;
2005-10-12 15:04:01 +04:00
/* We need to throttle things until the system clears
enough resources to handle this new socket . If we
don ' t then we will spin filling the log and causing
more problems . We don ' t panic as this is probably a
temporary resource constraint */
sleep ( 1 ) ;
2004-07-14 01:04:56 +04:00
return ;
}
2005-01-30 03:54:57 +03:00
talloc_steal ( state , state - > sock ) ;
2004-09-26 07:05:04 +04:00
2003-08-13 05:53:07 +04:00
pthread_attr_init ( & thread_attr ) ;
pthread_attr_setdetachstate ( & thread_attr , PTHREAD_CREATE_DETACHED ) ;
2005-01-30 03:54:57 +03:00
rc = pthread_create ( & thread_id , & thread_attr , thread_connection_fn , state ) ;
2003-08-13 05:53:07 +04:00
pthread_attr_destroy ( & thread_attr ) ;
if ( rc = = 0 ) {
DEBUG ( 4 , ( " accept_connection_thread: created thread_id=%lu for fd=%d \n " ,
2004-09-20 16:31:07 +04:00
( unsigned long int ) thread_id , socket_get_fd ( sock ) ) ) ;
2003-08-13 05:53:07 +04:00
} else {
2004-09-20 16:31:07 +04:00
DEBUG ( 0 , ( " accept_connection_thread: thread create failed for fd=%d, rc=%d \n " , socket_get_fd ( sock ) , rc ) ) ;
2005-01-30 03:54:57 +03:00
talloc_free ( ev2 ) ;
2003-08-13 05:53:07 +04:00
}
}
2005-01-30 05:55:30 +03:00
struct new_task_state {
2008-12-29 22:24:57 +03:00
struct tevent_context * ev ;
2008-01-06 04:03:43 +03:00
struct loadparm_context * lp_ctx ;
2008-12-29 22:24:57 +03:00
void ( * new_task ) ( struct tevent_context * , struct loadparm_context * ,
2008-01-06 04:03:43 +03:00
uint32_t , void * ) ;
2009-02-02 10:41:28 +03:00
void * private_data ;
2005-01-30 05:55:30 +03:00
} ;
static void * thread_task_fn ( void * thread_parm )
{
struct new_task_state * new_task = talloc_get_type ( thread_parm , struct new_task_state ) ;
2010-07-16 08:32:42 +04:00
new_task - > new_task ( new_task - > ev , new_task - > lp_ctx , pthread_self ( ) ,
2009-02-02 10:41:28 +03:00
new_task - > private_data ) ;
2005-01-30 05:55:30 +03:00
/* run this connection from here */
event_loop_wait ( new_task - > ev ) ;
talloc_free ( new_task ) ;
return NULL ;
}
/*
called when a new task is needed
*/
2008-12-29 22:24:57 +03:00
static void thread_new_task ( struct tevent_context * ev ,
2008-01-06 04:03:43 +03:00
struct loadparm_context * lp_ctx ,
2008-02-04 09:59:16 +03:00
const char * service_name ,
2008-12-29 22:24:57 +03:00
void ( * new_task ) ( struct tevent_context * ,
2008-01-06 04:03:43 +03:00
struct loadparm_context * ,
uint32_t , void * ) ,
2009-02-02 10:41:28 +03:00
void * private_data )
2005-01-30 05:55:30 +03:00
{
int rc ;
pthread_t thread_id ;
pthread_attr_t thread_attr ;
struct new_task_state * state ;
2008-12-29 22:24:57 +03:00
struct tevent_context * ev2 ;
2005-01-30 05:55:30 +03:00
2008-06-14 21:00:53 +04:00
ev2 = s4_event_context_init ( ev ) ;
2005-01-30 05:55:30 +03:00
if ( ev2 = = NULL ) return ;
state = talloc ( ev2 , struct new_task_state ) ;
if ( state = = NULL ) {
talloc_free ( ev2 ) ;
return ;
}
state - > new_task = new_task ;
2008-01-06 04:03:43 +03:00
state - > lp_ctx = lp_ctx ;
2009-02-02 10:41:28 +03:00
state - > private_data = private_data ;
2005-01-30 05:55:30 +03:00
state - > ev = ev2 ;
pthread_attr_init ( & thread_attr ) ;
pthread_attr_setdetachstate ( & thread_attr , PTHREAD_CREATE_DETACHED ) ;
rc = pthread_create ( & thread_id , & thread_attr , thread_task_fn , state ) ;
pthread_attr_destroy ( & thread_attr ) ;
if ( rc = = 0 ) {
2008-02-04 09:59:16 +03:00
DEBUG ( 4 , ( " thread_new_task: created %s thread_id=%lu \n " ,
service_name , ( unsigned long int ) thread_id ) ) ;
2005-01-30 05:55:30 +03:00
} else {
2008-02-04 09:59:16 +03:00
DEBUG ( 0 , ( " thread_new_task: thread create for %s failed rc=%d \n " , service_name , rc ) ) ;
2005-01-30 05:55:30 +03:00
talloc_free ( ev2 ) ;
}
}
/* called when a task goes down */
2010-07-16 08:32:42 +04:00
static void thread_terminate ( struct tevent_context * event_ctx , struct loadparm_context * lp_ctx , const char * reason )
2003-08-13 05:53:07 +04:00
{
2005-01-30 05:55:30 +03:00
DEBUG ( 10 , ( " thread_terminate: reason[%s] \n " , reason ) ) ;
2004-07-15 13:43:32 +04:00
2005-01-30 03:54:57 +03:00
talloc_free ( event_ctx ) ;
2004-07-15 13:43:32 +04:00
2003-12-14 02:25:15 +03:00
/* terminate this thread */
pthread_exit ( NULL ) ; /* thread cleanup routine will do actual cleanup */
}
2006-03-09 20:48:41 +03:00
/* called to set a title of a task or connection */
2008-12-29 22:24:57 +03:00
static void thread_set_title ( struct tevent_context * ev , const char * title )
2006-03-09 20:48:41 +03:00
{
2006-03-09 23:51:24 +03:00
char * old_title ;
char * new_title ;
old_title = pthread_getspecific ( title_key ) ;
talloc_free ( old_title ) ;
new_title = talloc_strdup ( ev , title ) ;
pthread_setspecific ( title_key , new_title ) ;
2006-03-09 20:48:41 +03:00
}
2003-08-13 05:53:07 +04:00
/*
mutex init function for thread model
*/
2003-08-15 21:13:41 +04:00
static int thread_mutex_init ( smb_mutex_t * mutex , const char * name )
2003-08-13 05:53:07 +04:00
{
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER ;
mutex - > mutex = memdup ( & m , sizeof ( m ) ) ;
if ( ! mutex - > mutex ) {
errno = ENOMEM ;
return - 1 ;
}
return pthread_mutex_init ( ( pthread_mutex_t * ) mutex - > mutex , NULL ) ;
}
/*
mutex destroy function for thread model
*/
2003-08-15 21:13:41 +04:00
static int thread_mutex_destroy ( smb_mutex_t * mutex , const char * name )
2003-08-13 05:53:07 +04:00
{
return pthread_mutex_destroy ( ( pthread_mutex_t * ) mutex - > mutex ) ;
}
2010-08-25 14:23:50 +04:00
static void mutex_start_timer ( struct timespec * tp1 )
2003-08-13 05:53:07 +04:00
{
2010-08-25 14:23:50 +04:00
clock_gettime_mono ( tp1 ) ;
2003-08-13 05:53:07 +04:00
}
2010-08-25 14:23:50 +04:00
static double mutex_end_timer ( struct timespec tp1 )
2003-08-13 05:53:07 +04:00
{
2010-08-25 14:23:50 +04:00
struct timespec tp2 ;
clock_gettime_mono ( & tp2 ) ;
2003-08-13 05:53:07 +04:00
return ( ( tp2 . tv_sec - tp1 . tv_sec ) +
2010-08-25 14:23:50 +04:00
( tp2 . tv_nsec - tp1 . tv_nsec ) * 1.0e-9 ) ;
2003-08-13 05:53:07 +04:00
}
/*
mutex lock function for thread model
*/
2003-08-15 21:13:41 +04:00
static int thread_mutex_lock ( smb_mutex_t * mutexP , const char * name )
2003-08-13 05:53:07 +04:00
{
pthread_mutex_t * mutex = ( pthread_mutex_t * ) mutexP - > mutex ;
int rc ;
double t ;
2010-08-25 14:23:50 +04:00
struct timespec tp1 ;
2003-08-13 05:53:07 +04:00
/* Test below is ONLY for debugging */
if ( ( rc = pthread_mutex_trylock ( mutex ) ) ) {
if ( rc = = EBUSY ) {
mutex_start_timer ( & tp1 ) ;
printf ( " mutex lock: thread %d, lock %s not available \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name ) ;
2003-08-13 05:53:07 +04:00
print_suspicious_usage ( " mutex_lock " , name ) ;
pthread_mutex_lock ( mutex ) ;
t = mutex_end_timer ( tp1 ) ;
printf ( " mutex lock: thread %d, lock %s now available, waited %g seconds \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name , t ) ;
2003-08-13 05:53:07 +04:00
return 0 ;
}
printf ( " mutex lock: thread %d, lock %s failed rc=%d \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name , rc ) ;
2003-08-13 05:53:07 +04:00
SMB_ASSERT ( errno = = 0 ) ; /* force error */
}
return 0 ;
}
/*
mutex unlock for thread model
*/
2003-08-15 21:13:41 +04:00
static int thread_mutex_unlock ( smb_mutex_t * mutex , const char * name )
2003-08-13 05:53:07 +04:00
{
return pthread_mutex_unlock ( ( pthread_mutex_t * ) mutex - > mutex ) ;
}
/*****************************************************************
Read / write lock routines .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
rwlock init function for thread model
*/
2003-12-16 06:27:36 +03:00
static int thread_rwlock_init ( smb_rwlock_t * rwlock , const char * name )
2003-08-13 05:53:07 +04:00
{
pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER ;
rwlock - > rwlock = memdup ( & m , sizeof ( m ) ) ;
if ( ! rwlock - > rwlock ) {
errno = ENOMEM ;
return - 1 ;
}
return pthread_rwlock_init ( ( pthread_rwlock_t * ) rwlock - > rwlock , NULL ) ;
}
/*
rwlock destroy function for thread model
*/
2003-12-16 06:27:36 +03:00
static int thread_rwlock_destroy ( smb_rwlock_t * rwlock , const char * name )
2003-08-13 05:53:07 +04:00
{
return pthread_rwlock_destroy ( ( pthread_rwlock_t * ) rwlock - > rwlock ) ;
}
/*
rwlock lock for read function for thread model
*/
2003-12-16 06:27:36 +03:00
static int thread_rwlock_lock_read ( smb_rwlock_t * rwlockP , const char * name )
2003-08-13 05:53:07 +04:00
{
pthread_rwlock_t * rwlock = ( pthread_rwlock_t * ) rwlockP - > rwlock ;
int rc ;
double t ;
2010-09-07 05:25:42 +04:00
struct timespec tp1 ;
2003-08-13 05:53:07 +04:00
/* Test below is ONLY for debugging */
if ( ( rc = pthread_rwlock_tryrdlock ( rwlock ) ) ) {
if ( rc = = EBUSY ) {
mutex_start_timer ( & tp1 ) ;
printf ( " rwlock lock_read: thread %d, lock %s not available \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name ) ;
2003-08-13 05:53:07 +04:00
print_suspicious_usage ( " rwlock_lock_read " , name ) ;
pthread_rwlock_rdlock ( rwlock ) ;
t = mutex_end_timer ( tp1 ) ;
printf ( " rwlock lock_read: thread %d, lock %s now available, waited %g seconds \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name , t ) ;
2003-08-13 05:53:07 +04:00
return 0 ;
}
printf ( " rwlock lock_read: thread %d, lock %s failed rc=%d \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name , rc ) ;
2003-08-13 05:53:07 +04:00
SMB_ASSERT ( errno = = 0 ) ; /* force error */
}
return 0 ;
}
/*
rwlock lock for write function for thread model
*/
2003-12-16 06:27:36 +03:00
static int thread_rwlock_lock_write ( smb_rwlock_t * rwlockP , const char * name )
2003-08-13 05:53:07 +04:00
{
pthread_rwlock_t * rwlock = ( pthread_rwlock_t * ) rwlockP - > rwlock ;
int rc ;
double t ;
2010-08-25 14:23:50 +04:00
struct timespec tp1 ;
2003-08-13 05:53:07 +04:00
/* Test below is ONLY for debugging */
if ( ( rc = pthread_rwlock_trywrlock ( rwlock ) ) ) {
if ( rc = = EBUSY ) {
mutex_start_timer ( & tp1 ) ;
printf ( " rwlock lock_write: thread %d, lock %s not available \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name ) ;
2003-08-13 05:53:07 +04:00
print_suspicious_usage ( " rwlock_lock_write " , name ) ;
pthread_rwlock_wrlock ( rwlock ) ;
t = mutex_end_timer ( tp1 ) ;
printf ( " rwlock lock_write: thread %d, lock %s now available, waited %g seconds \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name , t ) ;
2003-08-13 05:53:07 +04:00
return 0 ;
}
printf ( " rwlock lock_write: thread %d, lock %s failed rc=%d \n " ,
2004-05-25 20:24:13 +04:00
( uint32_t ) pthread_self ( ) , name , rc ) ;
2003-08-13 05:53:07 +04:00
SMB_ASSERT ( errno = = 0 ) ; /* force error */
}
return 0 ;
}
/*
rwlock unlock for thread model
*/
2003-12-16 06:27:36 +03:00
static int thread_rwlock_unlock ( smb_rwlock_t * rwlock , const char * name )
2003-08-13 05:53:07 +04:00
{
return pthread_rwlock_unlock ( ( pthread_rwlock_t * ) rwlock - > rwlock ) ;
}
/*****************************************************************
2006-05-13 22:12:53 +04:00
Log suspicious usage ( primarily for possible thread - unsafe behavior ) .
2003-08-13 05:53:07 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void thread_log_suspicious_usage ( const char * from , const char * info )
{
DEBUG ( 1 , ( " log_suspicious_usage: from %s info='%s' \n " , from , info ) ) ;
2003-12-04 14:01:58 +03:00
# ifdef HAVE_BACKTRACE
2004-01-22 05:28:17 +03:00
{
void * addresses [ 10 ] ;
int num_addresses = backtrace ( addresses , 8 ) ;
char * * bt_symbols = backtrace_symbols ( addresses , num_addresses ) ;
int i ;
if ( bt_symbols ) {
for ( i = 0 ; i < num_addresses ; i + + ) {
DEBUG ( 1 , ( " log_suspicious_usage: %s%s \n " , DEBUGTAB ( 1 ) , bt_symbols [ i ] ) ) ;
}
free ( bt_symbols ) ;
}
2003-08-13 05:53:07 +04:00
}
2003-12-04 14:01:58 +03:00
# endif
2003-08-13 05:53:07 +04:00
}
/*****************************************************************
Log suspicious usage to stdout ( primarily for possible thread - unsafe behavior .
Used in mutex code where DEBUG calls would cause recursion .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void thread_print_suspicious_usage ( const char * from , const char * info )
{
printf ( " log_suspicious_usage: from %s info='%s' \n " , from , info ) ;
2003-12-04 14:01:58 +03:00
# ifdef HAVE_BACKTRACE
2004-01-22 05:28:17 +03:00
{
void * addresses [ 10 ] ;
int num_addresses = backtrace ( addresses , 8 ) ;
char * * bt_symbols = backtrace_symbols ( addresses , num_addresses ) ;
int i ;
if ( bt_symbols ) {
for ( i = 0 ; i < num_addresses ; i + + ) {
printf ( " log_suspicious_usage: %s%s \n " , DEBUGTAB ( 1 ) , bt_symbols [ i ] ) ;
}
free ( bt_symbols ) ;
}
2003-08-13 05:53:07 +04:00
}
2003-12-04 14:01:58 +03:00
# endif
2003-08-13 05:53:07 +04:00
}
2004-05-25 20:24:13 +04:00
static uint32_t thread_get_task_id ( void )
2003-08-13 05:53:07 +04:00
{
2004-05-25 20:24:13 +04:00
return ( uint32_t ) pthread_self ( ) ;
2003-08-13 05:53:07 +04:00
}
2003-12-04 14:01:58 +03:00
static void thread_log_task_id ( int fd )
{
2006-01-09 20:43:48 +03:00
char * s = NULL ;
2006-03-09 23:51:24 +03:00
asprintf ( & s , " thread[%u][%s]: \n " ,
( uint32_t ) pthread_self ( ) ,
( const char * ) pthread_getspecific ( title_key ) ) ;
2006-01-09 20:43:48 +03:00
if ( ! s ) return ;
2003-12-04 14:01:58 +03:00
write ( fd , s , strlen ( s ) ) ;
free ( s ) ;
}
2005-01-30 03:54:57 +03:00
2003-08-13 05:53:07 +04:00
/****************************************************************************
catch serious errors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void thread_sig_fault ( int sig )
{
DEBUG ( 0 , ( " =============================================================== \n " ) ) ;
2006-03-09 23:51:24 +03:00
DEBUG ( 0 , ( " TERMINAL ERROR: Recursive signal %d in thread [%u][%s] (%s) \n " ,
sig , ( uint32_t ) pthread_self ( ) ,
( const char * ) pthread_getspecific ( title_key ) ,
SAMBA_VERSION_STRING ) ) ;
2003-08-13 05:53:07 +04:00
DEBUG ( 0 , ( " =============================================================== \n " ) ) ;
exit ( 1 ) ; /* kill the whole server for now */
}
/*******************************************************************
setup our recursive fault handlers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void thread_fault_setup ( void )
{
# ifdef SIGSEGV
2010-02-19 14:49:08 +03:00
CatchSignal ( SIGSEGV , thread_sig_fault ) ;
2003-08-13 05:53:07 +04:00
# endif
# ifdef SIGBUS
2010-02-19 14:49:08 +03:00
CatchSignal ( SIGBUS , thread_sig_fault ) ;
2003-08-13 05:53:07 +04:00
# endif
2004-01-22 05:28:17 +03:00
# ifdef SIGABRT
2010-02-19 14:49:08 +03:00
CatchSignal ( SIGABRT , thread_sig_fault ) ;
2004-01-22 05:28:17 +03:00
# endif
2003-08-13 05:53:07 +04:00
}
/*******************************************************************
report a fault in a thread
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void thread_fault_handler ( int sig )
{
static int counter ;
/* try to catch recursive faults */
thread_fault_setup ( ) ;
counter + + ; /* count number of faults that have occurred */
DEBUG ( 0 , ( " =============================================================== \n " ) ) ;
2006-03-09 23:51:24 +03:00
DEBUG ( 0 , ( " INTERNAL ERROR: Signal %d in thread [%u] [%s] (%s) \n " ,
sig , ( uint32_t ) pthread_self ( ) ,
( const char * ) pthread_getspecific ( title_key ) ,
SAMBA_VERSION_STRING ) ) ;
2003-08-13 05:53:07 +04:00
DEBUG ( 0 , ( " Please read the file BUGS.txt in the distribution \n " ) ) ;
DEBUG ( 0 , ( " =============================================================== \n " ) ) ;
2003-12-04 14:01:58 +03:00
# ifdef HAVE_BACKTRACE
2004-01-22 05:28:17 +03:00
{
void * addresses [ 10 ] ;
int num_addresses = backtrace ( addresses , 8 ) ;
char * * bt_symbols = backtrace_symbols ( addresses , num_addresses ) ;
int i ;
if ( bt_symbols ) {
for ( i = 0 ; i < num_addresses ; i + + ) {
DEBUG ( 1 , ( " fault_report: %s%s \n " , DEBUGTAB ( 1 ) , bt_symbols [ i ] ) ) ;
}
free ( bt_symbols ) ;
}
2003-08-13 05:53:07 +04:00
}
2003-12-04 14:01:58 +03:00
# endif
2003-08-13 05:53:07 +04:00
pthread_exit ( NULL ) ; /* terminate failing thread only */
}
/*
called when the process model is selected
*/
2008-12-29 22:24:57 +03:00
static void thread_model_init ( struct tevent_context * event_context )
2003-08-13 05:53:07 +04:00
{
struct mutex_ops m_ops ;
struct debug_ops d_ops ;
ZERO_STRUCT ( m_ops ) ;
ZERO_STRUCT ( d_ops ) ;
2006-03-09 23:51:24 +03:00
pthread_key_create ( & title_key , NULL ) ;
pthread_setspecific ( title_key , talloc_strdup ( event_context , " " ) ) ;
2003-08-13 05:53:07 +04:00
/* register mutex/rwlock handlers */
m_ops . mutex_init = thread_mutex_init ;
m_ops . mutex_lock = thread_mutex_lock ;
m_ops . mutex_unlock = thread_mutex_unlock ;
m_ops . mutex_destroy = thread_mutex_destroy ;
m_ops . rwlock_init = thread_rwlock_init ;
m_ops . rwlock_lock_write = thread_rwlock_lock_write ;
m_ops . rwlock_lock_read = thread_rwlock_lock_read ;
m_ops . rwlock_unlock = thread_rwlock_unlock ;
m_ops . rwlock_destroy = thread_rwlock_destroy ;
register_mutex_handlers ( " thread " , & m_ops ) ;
register_fault_handler ( " thread " , thread_fault_handler ) ;
d_ops . log_suspicious_usage = thread_log_suspicious_usage ;
d_ops . print_suspicious_usage = thread_print_suspicious_usage ;
d_ops . get_task_id = thread_get_task_id ;
2003-12-04 14:01:58 +03:00
d_ops . log_task_id = thread_log_task_id ;
2003-08-13 05:53:07 +04:00
2005-12-15 23:25:37 +03:00
register_debug_handlers ( " thread " , & d_ops ) ;
2003-08-13 05:53:07 +04:00
}
2005-01-14 04:32:56 +03:00
static const struct model_ops thread_ops = {
. name = " thread " ,
. model_init = thread_model_init ,
. accept_connection = thread_accept_connection ,
2005-01-30 05:55:30 +03:00
. new_task = thread_new_task ,
. terminate = thread_terminate ,
2006-03-09 20:48:41 +03:00
. set_title = thread_set_title ,
2005-01-14 04:32:56 +03:00
} ;
2003-08-13 05:53:07 +04:00
/*
initialise the thread process model , registering ourselves with the model subsystem
*/
2004-02-02 16:43:03 +03:00
NTSTATUS process_model_thread_init ( void )
2003-08-13 05:53:07 +04:00
{
2004-02-02 16:43:03 +03:00
NTSTATUS ret ;
/* register ourselves with the PROCESS_MODEL subsystem. */
2005-01-14 04:32:56 +03:00
ret = register_process_model ( & thread_ops ) ;
2004-02-02 16:43:03 +03:00
if ( ! NT_STATUS_IS_OK ( ret ) ) {
DEBUG ( 0 , ( " Failed to register process_model 'thread'! \n " ) ) ;
return ret ;
}
return ret ;
2003-08-13 05:53:07 +04:00
}