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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# 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"
2005-02-03 14:56:03 +03:00
# include "lib/events/events.h"
2004-11-02 10:29:10 +03:00
# include "dlinklist.h"
# include "smb_server/smb_server.h"
2005-02-10 10:18:00 +03:00
# include "mutex.h"
2005-01-30 03:54:57 +03:00
2006-03-02 19:32:53 +03:00
/* For specifying event context to GSSAPI below */
2006-01-10 11:41:49 +03:00
# include "system/kerberos.h"
2005-12-15 23:25:37 +03:00
# include "heimdal/lib/gssapi/gssapi_locl.h"
2005-01-30 03:54:57 +03:00
struct new_conn_state {
struct event_context * ev ;
struct socket_context * sock ;
void ( * new_conn ) ( struct event_context * , struct socket_context * , uint32_t , void * ) ;
void * private ;
} ;
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
2005-01-30 03:54:57 +03:00
new_conn - > new_conn ( new_conn - > ev , new_conn - > sock , pthread_self ( ) , new_conn - > private ) ;
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
*/
2005-01-30 03:54:57 +03:00
static void thread_accept_connection ( struct event_context * ev ,
struct socket_context * sock ,
void ( * new_conn ) ( struct event_context * , struct socket_context * ,
uint32_t , void * ) ,
void * private )
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 ;
struct event_context * ev2 ;
2004-07-14 01:04:56 +04:00
2005-01-30 03:54:57 +03:00
ev2 = event_context_init ( ev ) ;
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 ;
state - > private = private ;
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 {
struct event_context * ev ;
void ( * new_task ) ( struct event_context * , uint32_t , void * ) ;
void * private ;
} ;
static void * thread_task_fn ( void * thread_parm )
{
struct new_task_state * new_task = talloc_get_type ( thread_parm , struct new_task_state ) ;
new_task - > new_task ( new_task - > ev , pthread_self ( ) , new_task - > private ) ;
/* run this connection from here */
event_loop_wait ( new_task - > ev ) ;
talloc_free ( new_task ) ;
return NULL ;
}
/*
called when a new task is needed
*/
static void thread_new_task ( struct event_context * ev ,
void ( * new_task ) ( struct event_context * , uint32_t , void * ) ,
void * private )
{
int rc ;
pthread_t thread_id ;
pthread_attr_t thread_attr ;
struct new_task_state * state ;
struct event_context * ev2 ;
ev2 = event_context_init ( ev ) ;
if ( ev2 = = NULL ) return ;
state = talloc ( ev2 , struct new_task_state ) ;
if ( state = = NULL ) {
talloc_free ( ev2 ) ;
return ;
}
state - > new_task = new_task ;
state - > private = private ;
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 ) {
DEBUG ( 4 , ( " thread_new_task: created thread_id=%lu \n " ,
( unsigned long int ) thread_id ) ) ;
} else {
DEBUG ( 0 , ( " thread_new_task: thread create failed rc=%d \n " , rc ) ) ;
talloc_free ( ev2 ) ;
}
}
/* called when a task goes down */
static void thread_terminate ( struct event_context * event_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 */
}
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 ) ;
}
static void mutex_start_timer ( struct timeval * tp1 )
{
gettimeofday ( tp1 , NULL ) ;
}
static double mutex_end_timer ( struct timeval tp1 )
{
struct timeval tp2 ;
gettimeofday ( & tp2 , NULL ) ;
return ( ( tp2 . tv_sec - tp1 . tv_sec ) +
( tp2 . tv_usec - tp1 . tv_usec ) * 1.0e-6 ) ;
}
/*
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 ;
struct timeval tp1 ;
/* 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 ;
struct timeval tp1 ;
/* 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 ;
struct timeval tp1 ;
/* 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 ) ;
}
/*****************************************************************
Log suspicious usage ( primarily for possible thread - unsafe behavior .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 ;
2003-12-04 14:01:58 +03:00
2004-05-25 20:24:13 +04:00
asprintf ( & s , " thread %u: " , ( uint32_t ) pthread_self ( ) ) ;
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 " ) ) ;
2004-01-28 15:47:52 +03:00
DEBUG ( 0 , ( " TERMINAL ERROR: Recursive signal %d in thread %lu (%s) \n " , sig , ( unsigned long int ) pthread_self ( ) , 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
CatchSignal ( SIGSEGV , SIGNAL_CAST thread_sig_fault ) ;
# endif
# ifdef SIGBUS
CatchSignal ( SIGBUS , SIGNAL_CAST thread_sig_fault ) ;
# endif
2004-01-22 05:28:17 +03:00
# ifdef SIGABRT
CatchSignal ( SIGABRT , SIGNAL_CAST thread_sig_fault ) ;
# 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 " ) ) ;
2004-01-28 15:47:52 +03:00
DEBUG ( 0 , ( " INTERNAL ERROR: Signal %d in thread %lu (%s) \n " , sig , ( unsigned long int ) pthread_self ( ) , 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
*/
2005-01-30 03:54:57 +03:00
static void thread_model_init ( struct event_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 ) ;
/* 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 ) ;
/* Hack to ensure that GSSAPI uses the right event context */
gssapi_krb5_init_ev ( event_context ) ;
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 ,
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
}