changeset 1182:cc96a4dfb3d1

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.
author Sebastien Decugis <sdecugis@freediameter.net>
date Thu, 06 Jun 2013 11:25:23 +0800
parents 22de21feec64
children 42d3fd71e7ea
files freeDiameterd/main.c libfdcore/core.c
diffstat 2 files changed, 40 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }
 
 
--- 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) );
"Welcome to our mercurial repository"