From bb770a45a6a6b013d52d6e0a4b27fd630e365d30 Mon Sep 17 00:00:00 2001 From: erdgeist <> Date: Fri, 17 Jul 2009 18:00:26 +0000 Subject: Make accesslists thread safe. Signal handler is working in its own thread now, waiting for a signal. All other threads ignore signals. --- opentracker.c | 36 +++++++++++++++++++++++++++----- ot_accesslist.c | 65 +++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 76 insertions(+), 25 deletions(-) diff --git a/opentracker.c b/opentracker.c index c36ceaa..f715424 100644 --- a/opentracker.c +++ b/opentracker.c @@ -65,6 +65,32 @@ static void signal_handler( int s ) { } } +static void defaul_signal_handlers( void ) { + sigset_t signal_mask; + sigemptyset(&signal_mask); + sigaddset (&signal_mask, SIGPIPE); + sigaddset (&signal_mask, SIGHUP); + sigaddset (&signal_mask, SIGINT); + sigaddset (&signal_mask, SIGALRM); + pthread_sigmask (SIG_BLOCK, &signal_mask, NULL); +} + +static void install_signal_handlers( void ) { + struct sigaction sa; + sigset_t signal_mask; + sigemptyset(&signal_mask); + + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1) ) + panic( "install_signal_handlers" ); + + sigaddset (&signal_mask, SIGINT); + sigaddset (&signal_mask, SIGALRM); + pthread_sigmask (SIG_UNBLOCK, &signal_mask, NULL); +} + static void usage( char *name ) { fprintf( stderr, "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-A ip] [-f config] [-s livesyncport]" #ifdef WANT_ACCESSLIST_BLACK @@ -254,12 +280,14 @@ static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) { #endif #ifdef _DEBUG + { char *protos[] = {"TCP","UDP","UDP mcast"}; char _debug[512]; int off = snprintf( _debug, sizeof(_debug), "Binding socket type %s to address [", protos[proto] ); off += fmt_ip6c( _debug+off, ip); snprintf( _debug + off, sizeof(_debug)-off, "]:%d...", port); fputs( _debug, stderr ); + } #endif if( socket_bind6_reuse( sock, ip, port, 0 ) == -1 ) @@ -483,7 +511,7 @@ int main( int argc, char **argv ) { noipv6=1; #endif -while( scanon ) { + while( scanon ) { switch( getopt( argc, argv, ":i:p:A:P:d:r:s:f:l:v" #ifdef WANT_ACCESSLIST_BLACK "b:" @@ -540,10 +568,6 @@ while( scanon ) { if( drop_privileges( g_serverdir ? g_serverdir : "." ) == -1 ) panic( "drop_privileges failed, exiting. Last error"); - signal( SIGPIPE, SIG_IGN ); - signal( SIGINT, signal_handler ); - signal( SIGALRM, signal_handler ); - g_now_seconds = time( NULL ); /* Create our self pipe which allows us to interrupt mainloops @@ -555,8 +579,10 @@ while( scanon ) { io_setcookie( g_self_pipe[0], (void*)FLAG_SELFPIPE ); io_wantread( g_self_pipe[0] ); + defaul_signal_handlers( ); /* Init all sub systems. This call may fail with an exit() */ trackerlogic_init( ); + install_signal_handlers( ); /* Kick off our initial clock setting alarm */ alarm(5); diff --git a/ot_accesslist.c b/ot_accesslist.c index 65eceb7..cdf7731 100644 --- a/ot_accesslist.c +++ b/ot_accesslist.c @@ -4,6 +4,7 @@ $id$ */ /* System */ +#include #include #include #include @@ -26,25 +27,18 @@ char *g_accesslist_filename; static ot_hash *g_accesslist; static size_t g_accesslist_size; +static pthread_mutex_t g_accesslist_mutex; static int vector_compare_hash(const void *hash1, const void *hash2 ) { return memcmp( hash1, hash2, OT_HASH_COMPARE_SIZE ); } -void accesslist_deinit( void ) { - free( g_accesslist ); - g_accesslist = 0; - g_accesslist_size = 0; -} - /* Read initial access list */ -static void accesslist_readfile( int sig ) { - ot_hash *info_hash, *accesslist_new = NULL, *accesslist_old; +static void accesslist_readfile( void ) { + ot_hash *info_hash, *accesslist_new = NULL; char *map, *map_end, *read_offs; size_t maplen; - if( sig != SIGHUP ) return; - if( ( map = mmap_read( g_accesslist_filename, &maplen ) ) == NULL ) { char *wd = getcwd( NULL, 0 ); fprintf( stderr, "Warning: Can't open accesslist file: %s (but will try to create it later, if necessary and possible).\nPWD: %s\n", g_accesslist_filename, wd ); @@ -84,7 +78,7 @@ static void accesslist_readfile( int sig ) { while( read_offs < map_end && *(read_offs++) != '\n' ); } #ifdef _DEBUG - fprintf( stderr, "Added %d info_hashes to accesslist\n", info_hash - accesslist_new ); + fprintf( stderr, "Added %zd info_hashes to accesslist\n", (size_t)(info_hash - accesslist_new) ); #endif mmap_unmap( map, maplen); @@ -92,15 +86,20 @@ static void accesslist_readfile( int sig ) { qsort( accesslist_new, info_hash - accesslist_new, sizeof( *info_hash ), vector_compare_hash ); /* Now exchange the accesslist vector in the least race condition prone way */ - g_accesslist_size = 0; - accesslist_old = g_accesslist; + pthread_mutex_lock(&g_accesslist_mutex); + free( g_accesslist ); g_accesslist = accesslist_new; g_accesslist_size = info_hash - accesslist_new; - free( accesslist_old ); + pthread_mutex_unlock(&g_accesslist_mutex); } int accesslist_hashisvalid( ot_hash hash ) { - void *exactmatch = bsearch( hash, g_accesslist, g_accesslist_size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); + void *exactmatch; + + /* Lock should hardly ever be contended */ + pthread_mutex_lock(&g_accesslist_mutex); + exactmatch = bsearch( hash, g_accesslist, g_accesslist_size, OT_HASH_COMPARE_SIZE, vector_compare_hash ); + pthread_mutex_unlock(&g_accesslist_mutex); #ifdef WANT_ACCESSLIST_BLACK return exactmatch == NULL; @@ -109,12 +108,38 @@ int accesslist_hashisvalid( ot_hash hash ) { #endif } -void accesslist_init( ) { - /* Passing "0" since read_blacklist_file also is SIGHUP handler */ - if( g_accesslist_filename ) { - accesslist_readfile( SIGHUP ); - signal( SIGHUP, accesslist_readfile ); +static void * accesslist_worker( void * args ) { + int sig; + sigset_t signal_mask; + + sigemptyset(&signal_mask); + sigaddset(&signal_mask, SIGHUP); + + (void)args; + + while( 1 ) { + + /* Initial attempt to read accesslist */ + accesslist_readfile( ); + + /* Wait for signals */ + while( sigwait (&signal_mask, &sig) != 0 && sig != SIGHUP ); } + return NULL; +} + +static pthread_t thread_id; +void accesslist_init( ) { + pthread_mutex_init(&g_accesslist_mutex, NULL); + pthread_create( &thread_id, NULL, accesslist_worker, NULL ); +} + +void accesslist_deinit( void ) { + pthread_cancel( thread_id ); + pthread_mutex_destroy(&g_accesslist_mutex); + free( g_accesslist ); + g_accesslist = 0; + g_accesslist_size = 0; } #endif -- cgit v1.2.3