# HG changeset patch # User Sebastien Decugis # Date 1370489123 -28800 # Node ID cc96a4dfb3d161ee874c2db9ffa937c4e64882f4 # Parent 22de21feec64e4d4ced6aebd06705ef3f1f2273c Early shutdown situation: detect the race condition and delay the shutdown in freeDiameterd. Alternative would be to initialize in a separate thread that we can cancel before calling shutdown. diff -r 22de21feec64 -r cc96a4dfb3d1 freeDiameterd/main.c --- a/freeDiameterd/main.c Wed Jun 05 19:22:26 2013 +0800 +++ b/freeDiameterd/main.c Thu Jun 06 11:25:23 2013 +0800 @@ -86,17 +86,17 @@ TRACE_DEBUG(INFO, "Enabled GNUTLS debug at level %d", gnutls_debug); } - /* Allow SIGINT and SIGTERM from this point to terminate the application */ - CHECK_POSIX( pthread_create(&signals_thr, NULL, catch_signals, NULL) ); - /* Parse the configuration file */ - CHECK_FCT( fd_core_parseconf(conffile) ); + CHECK_FCT_DO( fd_core_parseconf(conffile), goto error ); /* Start the servers */ - CHECK_FCT( fd_core_start() ); + CHECK_FCT_DO( fd_core_start(), goto error ); + + /* Allow SIGINT and SIGTERM from this point to terminate the application */ + CHECK_POSIX_DO( pthread_create(&signals_thr, NULL, catch_signals, NULL), goto error ); TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); - + /* Now, just wait for termination */ CHECK_FCT( fd_core_wait_shutdown_complete() ); @@ -104,6 +104,11 @@ fd_thr_term(&signals_thr); return 0; +error: + CHECK_FCT_DO( fd_core_shutdown(), ); + CHECK_FCT( fd_core_wait_shutdown_complete() ); + fd_thr_term(&signals_thr); + return -1; } diff -r 22de21feec64 -r cc96a4dfb3d1 libfdcore/core.c --- a/libfdcore/core.c Wed Jun 05 19:22:26 2013 +0800 +++ b/libfdcore/core.c Thu Jun 06 11:25:23 2013 +0800 @@ -227,8 +227,10 @@ return 0; } +static pthread_mutex_t core_lock = PTHREAD_MUTEX_INITIALIZER; + /* Parse the freeDiameter.conf configuration file, load the extensions */ -int fd_core_parseconf(const char * conffile) +static int fd_core_parseconf_int(const char * conffile) { char * buf = NULL, *b; size_t len = 0, offset=0; @@ -273,6 +275,16 @@ return 0; } +int fd_core_parseconf(const char * conffile) +{ + int ret; + CHECK_POSIX( pthread_mutex_lock(&core_lock) ); + ret = fd_core_parseconf_int(conffile); + CHECK_POSIX( pthread_mutex_unlock(&core_lock) ); + return ret; +} + + /* For threads that would need to wait complete start of the framework (ex: in extensions) */ int fd_core_waitstartcomplete(void) { @@ -282,7 +294,7 @@ } /* Start the server & client threads */ -int fd_core_start(void) +static int fd_core_start_int(void) { /* Start server threads */ CHECK_FCT( fd_servers_start() ); @@ -300,6 +312,14 @@ return 0; } +int fd_core_start(void) +{ + int ret; + CHECK_POSIX( pthread_mutex_lock(&core_lock) ); + ret = fd_core_start_int(); + CHECK_POSIX( pthread_mutex_unlock(&core_lock) ); + return ret; +} /* Initialize shutdown of the framework. This is not blocking. */ int fd_core_shutdown(void) @@ -307,8 +327,15 @@ enum core_state cur_state = core_state_get(); if (cur_state < CORE_RUNNING) { + /* Calling application must make sure the initialization is not ongoing in a separate thread... */ + if (pthread_mutex_lock(&core_lock) != 0) { + /* This function must not be called asynchronously from fd_core_parseconf / fd_core_start ! Please review your main app design */ + ASSERT(0); + return EINVAL; + } core_shutdown(); core_state_set(CORE_TERM); + pthread_mutex_unlock(&core_lock); } else if (cur_state == CORE_RUNNING) { core_state_set(CORE_SHUTDOWN); CHECK_FCT( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL) );