Backport the minimal set of load/unload changes from corosync
that are needed to allow pacemaker to function.

Implements the ability to have plugins be notified sequentially
of a shutdown so they have an opportunity to clean up before they
are unloaded and aisexec terminates. 

diff -r b907692f6e1f -r 09edbef89566 exec/clm.c
--- a/exec/clm.c	Mon Jan 26 20:46:12 2009 +0000
+++ b/exec/clm.c	Fri Feb 06 11:34:06 2009 +0100
@@ -134,6 +134,8 @@ static void clm_sync_abort (void);
 
 static int clm_exec_init_fn (struct objdb_iface_ver0 *objdb);
 
+static int clm_exec_exit_fn (struct objdb_iface_ver0 *objdb);
+
 static int clm_lib_init_fn (void *conn);
 
 static int clm_lib_exit_fn (void *conn);
@@ -208,6 +210,7 @@ struct openais_service_handler clm_servi
 	.lib_service		= clm_lib_service,
 	.lib_service_count	= sizeof (clm_lib_service) / sizeof (struct openais_lib_handler),
 	.exec_init_fn		= clm_exec_init_fn,
+	.exec_exit_fn		= clm_exec_exit_fn,
 	.exec_dump_fn		= NULL,
 	.exec_service		= clm_exec_service,
 	.exec_service_count	= sizeof (clm_exec_service) / sizeof (struct openais_exec_handler),
@@ -336,6 +339,11 @@ static int clm_exec_init_fn (struct objd
 	return (0);
 }
 
+static int clm_exec_exit_fn (struct objdb_iface_ver0 *objdb)
+{
+	return (0);
+}
+
 static int clm_lib_exit_fn (void *conn)
 {
 	struct clm_pd *clm_pd = (struct clm_pd *)openais_conn_private_data_get (conn);
diff -r b907692f6e1f -r 09edbef89566 exec/main.c
--- a/exec/main.c	Mon Jan 26 20:46:12 2009 +0000
+++ b/exec/main.c	Fri Feb 06 11:34:06 2009 +0100
@@ -92,6 +92,8 @@ static struct totem_logging_configuratio
 
 static char delivery_data[MESSAGE_SIZE_MAX];
 
+static struct objdb_iface_ver0 *objdb = NULL;
+
 SaClmClusterNodeT *(*main_clm_get_by_nodeid) (unsigned int node_id);
 
 static void sigusr2_handler (int num)
@@ -105,32 +107,11 @@ static void sigusr2_handler (int num)
 	}
 }
 
-static void sigsegv_handler (int num)
+static void *aisexec_exit (void *arg)
 {
-	signal (SIGSEGV, SIG_DFL);
-	log_flush ();
-	raise (SIGSEGV);
-}
-
-static void sigabrt_handler (int num)
-{
-	signal (SIGABRT, SIG_DFL);
-	log_flush ();
-	raise (SIGABRT);
-}
-
-
-#define LOCALHOST_IP inet_addr("127.0.0.1")
-
-totempg_groups_handle openais_group_handle;
-
-struct totempg_group openais_group = {
-	.group		= "a",
-	.group_len	= 1
-};
-
-void sigintr_handler (int signum)
-{
+	if(objdb) {
+		openais_service_unlink_all (objdb);
+	}
 
 #ifdef DEBUG_MEMPOOL
 	int stats_inuse[MEMPOOL_GROUP_SIZE];
@@ -147,9 +128,57 @@ void sigintr_handler (int signum)
 		i, 1<<i, stats_inuse[i], stats_avail[i], stats_memoryused[i]);
 	}
 #endif
+	log_flush ();
 
 	totempg_finalize ();
 	openais_exit_error (AIS_DONE_EXIT);
+
+	/* never reached */
+	return NULL;
+}
+
+pthread_t aisexec_exit_thread;
+static void init_shutdown(void *data) 
+{
+	pthread_create (&aisexec_exit_thread, NULL, aisexec_exit, NULL);
+}
+
+
+static poll_timer_handle shutdown_handle;
+static void sigquit_handler (int num)
+{
+	/* avoid creating threads from within the interrupt context */
+	poll_timer_add (aisexec_poll_handle, 500, NULL, init_shutdown, &shutdown_handle);
+}
+
+
+static void sigsegv_handler (int num)
+{
+	signal (SIGSEGV, SIG_DFL);
+	log_flush ();
+	raise (SIGSEGV);
+}
+
+static void sigabrt_handler (int num)
+{
+	signal (SIGABRT, SIG_DFL);
+	log_flush ();
+	raise (SIGABRT);
+}
+
+
+#define LOCALHOST_IP inet_addr("127.0.0.1")
+
+totempg_groups_handle openais_group_handle;
+
+struct totempg_group openais_group = {
+	.group		= "a",
+	.group_len	= 1
+};
+
+void sigintr_handler (int signum)
+{
+	poll_timer_add (aisexec_poll_handle, 500, NULL, init_shutdown, &shutdown_handle);
 }
 
 
@@ -273,6 +303,7 @@ static void aisexec_tty_detach (void)
 	/*
 	 * Disconnect from TTY if this is not a debug run
 	 */
+
 	switch (fork ()) {
 		case -1:
 			openais_exit_error (AIS_DONE_FORK);
@@ -281,6 +312,10 @@ static void aisexec_tty_detach (void)
 			/*
 			 * child which is disconnected, run this process
 			 */
+/* 			setset(); */
+			close (0);
+			close (1);
+			close (2);
 			break;
 		default:
 			exit (0);
@@ -373,6 +408,13 @@ static void deliver_fn (
 	 */
 	service = header->id >> 16;
 	fn_id = header->id & 0xffff;
+
+	if(service >= SERVICE_HANDLER_MAXIMUM_COUNT
+	   || ais_service[service] == NULL) {
+	    /* The component is no longer loaded */
+	    return;
+	}
+	
 	if (endian_conversion_required) {
 		ais_service[service]->exec_service[fn_id].exec_endian_convert_fn
 			(header);
@@ -390,7 +432,6 @@ int main (int argc, char **argv)
 	unsigned int objdb_handle;
 	unsigned int config_handle;
 	unsigned int config_version = 0;
-	struct objdb_iface_ver0 *objdb;
 	void *objdb_p;
 	struct config_iface_ver0 *config;
 	void *config_p;
@@ -427,7 +468,8 @@ int main (int argc, char **argv)
 	signal (SIGUSR2, sigusr2_handler);
 	signal (SIGSEGV, sigsegv_handler);
 	signal (SIGABRT, sigabrt_handler);
-
+	signal (SIGQUIT, sigquit_handler);
+	
 	openais_timer_init (
 		serialize_mutex_lock,
 		serialize_mutex_unlock);
@@ -456,7 +498,11 @@ int main (int argc, char **argv)
 
 	objdb->objdb_init ();
 
-	/* User's bootstrap config service */
+	/*
+	 * Bootstrap in the default configuration parser or use
+	 * the openais default built in parser if the configuration parser
+	 * isn't overridden
+	 */
 	config_iface = getenv("OPENAIS_DEFAULT_CONFIG_IFACE");
 	if (!config_iface) {
 		config_iface = "aisparser";
@@ -481,14 +527,6 @@ int main (int argc, char **argv)
 		openais_exit_error (AIS_DONE_MAINCONFIGREAD);
 	}
 
-	openais_service_default_objdb_set (objdb);
-
-	res = openais_service_link_all (objdb);
-	if (res == -1) {
-		log_printf (LOG_LEVEL_ERROR, "Could not load services\n");
-		openais_exit_error (AIS_DONE_DYNAMICLOAD);
-	}
-
 	res = openais_main_config_read (objdb, &error_string, &main_config);
 	if (res == -1) {
 		log_printf (LOG_LEVEL_ERROR, error_string);
@@ -568,12 +606,13 @@ int main (int argc, char **argv)
 	/*
 	 * This must occur after totempg is initialized because "this_ip" must be set
 	 */
-	res = openais_service_init_all (service_count, objdb);
+	res = openais_service_defaults_link_and_init (objdb);
 	if (res == -1) {
-		log_printf (LOG_LEVEL_ERROR, "Could not init services\n");
+		log_printf (LOG_LEVEL_ERROR, "Could not initialize default services\n");
 		openais_exit_error (AIS_DONE_INIT_SERVICES);
 	}
 
+
 	sync_register (openais_sync_callbacks_retrieve, openais_sync_completed,
 		totem_config.vsf_type);
 
diff -r b907692f6e1f -r 09edbef89566 exec/service.c
--- a/exec/service.c	Mon Jan 26 20:46:12 2009 +0000
+++ b/exec/service.c	Fri Feb 06 11:34:06 2009 +0100
@@ -84,59 +84,19 @@ static struct default_service default_se
 	{
 		.name			 = "openais_cpg",
 		.ver			 = 0,
-	}
+	},
 };
 
 struct openais_service_handler *ais_service[SERVICE_HANDLER_MAXIMUM_COUNT];
 
-/*
- * Adds a service handler to the object database
- */
-int openais_service_objdb_add (
-	struct objdb_iface_ver0 *objdb,
-	char *name,
-	int version)
+static unsigned int default_services_requested (struct objdb_iface_ver0 *objdb)
 {
-	unsigned int object_handle;
-
-	objdb->object_create (OBJECT_PARENT_HANDLE, &object_handle,
-		"service", strlen ("service"));
-	objdb->object_key_create (object_handle, "name", strlen ("name"),
-		name, strlen (name) + 1);
-	objdb->object_key_create (object_handle, "ver", strlen ("ver"),
-		&version, sizeof (version));
-
-	return (0);
-}
-
-static int service_handler_config (
-	struct openais_service_handler *handler,
-	struct objdb_iface_ver0 *objdb)
-{
-	int res = 0;
-
-	/* Already loaded? */
-	if (ais_service[handler->id] != NULL)
-		return 0;
-
-	log_printf (LOG_LEVEL_NOTICE, "Registering service handler '%s'\n", handler->name);
-	ais_service[handler->id] = handler;
-	if (ais_service[handler->id]->config_init_fn) {
-		res = ais_service[handler->id]->config_init_fn (objdb);
-	}
-	return (res);
-}
-
-/*
- * adds the default services to the object database
- */
-int openais_service_default_objdb_set (struct objdb_iface_ver0 *objdb)
-{
-	int i;
-	unsigned int object_service_handle;
+	unsigned int object_service_handle = 0;
 	char *value = NULL;
 
-	/* Load default services unless they have been explicitly disabled */
+	/*
+	 * Don't link default services if they have been disabled
+	 */
 	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
 	if (objdb->object_find (
 		OBJECT_PARENT_HANDLE,
@@ -158,25 +118,144 @@ int openais_service_default_objdb_set (s
 
 	log_init ("SERV");
 
-	for (i = 0; i < sizeof (default_services) / sizeof (struct default_service); i++) {
-		openais_service_objdb_add (objdb, default_services[i].name, default_services[i].ver);
-	}
-	return (0);
+	return (-1);
 }
 
-/*
- * Links dynamic services into the executive
- */
-int openais_service_link_all (struct objdb_iface_ver0 *objdb)
+unsigned int openais_service_link_and_init (
+	struct objdb_iface_ver0 *objdb,
+	char *service_name,
+	unsigned int service_ver, unsigned int object_handle)
 {
-	char *service_name;
-	char *service_ver;
-	unsigned int object_service_handle;
-	int ret;
-	unsigned int handle;
 	struct openais_service_handler_iface_ver0 *iface_ver0;
 	void *iface_ver0_p;
-	unsigned int ver_int;
+	unsigned int handle;
+	struct openais_service_handler *service;
+	unsigned int res;
+
+	/*
+	 * reference the service interface
+	 */
+	iface_ver0_p = NULL;
+	lcr_ifact_reference (
+		&handle,
+		service_name,
+		service_ver,
+		&iface_ver0_p,
+		(void *)0);
+
+	iface_ver0 = (struct openais_service_handler_iface_ver0 *)iface_ver0_p;
+
+	if (iface_ver0 == 0) {
+		log_printf(LOG_LEVEL_ERROR, "Service failed to load '%s'.\n", service_name);
+		return (-1);
+	}
+
+
+	/*
+	 * Initialize service
+	 */
+	service = iface_ver0->openais_get_service_handler_ver0();
+
+	ais_service[service->id] = service;
+	if (service->config_init_fn) {
+		res = service->config_init_fn (objdb);
+	}
+
+	if (service->exec_init_fn) {
+		res = service->exec_init_fn (objdb);
+	}
+
+	if(object_handle == 0) {
+	/*
+	 * Store service in object database
+	 */
+	objdb->object_create (OBJECT_PARENT_HANDLE,
+		&object_handle,
+		"service",
+		strlen ("service"));
+
+	objdb->object_key_create (object_handle,
+		"name",
+		strlen ("name"),
+		service_name,
+		strlen (service_name) + 1);
+	}
+
+	objdb->object_key_create (object_handle,
+		"ver",
+		strlen ("ver"),
+		&service_ver,
+		sizeof (service_ver));
+
+	res = objdb->object_key_create (object_handle,
+		"handle",
+		strlen ("handle"),
+		&handle,
+		sizeof (handle));
+
+	objdb->object_key_create (object_handle,
+		"service_id",
+		strlen ("service_id"),
+		&service->id,
+		sizeof (service->id));
+
+	log_printf (LOG_LEVEL_NOTICE, "Service initialized '%s'\n", service->name);
+	return (res);
+}
+
+static int openais_service_unlink_common(
+	struct objdb_iface_ver0 *objdb,
+	unsigned int object_service_handle,
+	const char *service_name,
+	unsigned int service_version) 
+{
+	unsigned int res;
+	unsigned short *service_id;
+	unsigned int *found_service_handle;
+	res = objdb->object_key_get (object_service_handle,
+				     "handle",
+				     strlen ("handle"),
+				     (void *)&found_service_handle,
+				     NULL);
+	
+	res = objdb->object_key_get (object_service_handle,
+				     "service_id",
+				     strlen ("service_id"),
+				     (void *)&service_id,
+				     NULL);
+	
+	log_printf(LOG_LEVEL_NOTICE, "Unloading openais component: %s v%u (%d/%d)\n",
+		   service_name, service_version, object_service_handle, *service_id);
+
+	if((*service_id) >= SERVICE_HANDLER_MAXIMUM_COUNT) {
+	    log_printf(LOG_LEVEL_NOTICE, "Invalid component: %s v%u (%d)\n",
+		       service_name, service_version, *service_id);
+	    return 0;
+	} 
+
+	if(ais_service[*service_id] == NULL) {
+	    /* The component is no longer loaded */
+	    log_printf(LOG_LEVEL_NOTICE, "Openais component is already unloaded: %s v%u (%d)\n",
+		       service_name, service_version, *service_id);
+	    return 0;
+	    
+	} else if (ais_service[*service_id]->exec_exit_fn) {
+	    ais_service[*service_id]->exec_exit_fn (objdb);
+	}
+
+	ais_service[*service_id] = NULL;
+	return lcr_ifact_release (*found_service_handle);	
+}
+
+extern unsigned int openais_service_unlink_and_exit (
+	struct objdb_iface_ver0 *objdb,
+	char *service_name,
+	unsigned int service_ver)
+{
+	unsigned int res = 0;
+	unsigned int object_service_handle = 0;
+	char *found_service_name = NULL;
+	unsigned int *found_service_ver = 0;
 
 	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
 	while (objdb->object_find (
@@ -188,56 +267,120 @@ int openais_service_link_all (struct obj
 		objdb->object_key_get (object_service_handle,
 			"name",
 			strlen ("name"),
+			(void *)&found_service_name,
+			NULL);
+
+		objdb->object_key_get (object_service_handle,
+			"ver",
+			strlen ("ver"),
+			(void *)&found_service_ver,
+			NULL);
+
+		/*
+		 * If service found and linked exit it
+		 */
+		if ((strcmp (service_name, found_service_name) == 0) &&
+			(service_ver == *found_service_ver)) {
+			res = openais_service_unlink_common(
+			    objdb, object_service_handle, service_name, service_ver);
+			objdb->object_destroy (object_service_handle);
+			return res;
+		}
+	}
+	return (-1);
+}
+
+extern unsigned int openais_service_unlink_all (
+	struct objdb_iface_ver0 *objdb)
+{
+	char *service_name = NULL;
+	unsigned int *service_ver = 0;
+	unsigned int object_service_handle = 0;
+
+	log_printf(LOG_LEVEL_NOTICE, "Unloading all openais components\n");
+	
+	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
+	while (objdb->object_find (OBJECT_PARENT_HANDLE,
+				   "service",
+				   strlen ("service"),
+				   &object_service_handle) == 0) {
+		
+		objdb->object_key_get (object_service_handle,
+			"name",
+			strlen ("name"),
 			(void *)&service_name,
 			NULL);
 
-		ret = objdb->object_key_get (object_service_handle,
+		objdb->object_key_get (object_service_handle,
 			"ver",
 			strlen ("ver"),
 			(void *)&service_ver,
 			NULL);
+				
+		openais_service_unlink_common(
+			objdb, object_service_handle, service_name, *service_ver);
 
-		ver_int = atoi (service_ver);
+		objdb->object_destroy (object_service_handle);
+		objdb->object_find_reset (OBJECT_PARENT_HANDLE);
+	}
 
-		/*
-		 * reference the interface and register it
-		 */
-		lcr_ifact_reference (
-			&handle,
-			service_name,
-			ver_int,
-			&iface_ver0_p,
-			(void *)0);
-
-		iface_ver0 = (struct openais_service_handler_iface_ver0 *)iface_ver0_p;
-
-		if (iface_ver0 == 0) {
-			log_printf(LOG_LEVEL_ERROR, "openais component %s did not load.\n", service_name);
-			openais_exit_error (AIS_DONE_DYNAMICLOAD);
-		} else {
-			log_printf(LOG_LEVEL_NOTICE, "openais component %s loaded.\n", service_name);
-		}
-
-		service_handler_config (
-			iface_ver0->openais_get_service_handler_ver0(), objdb);
-	}
 	return (0);
 }
 
-int openais_service_init_all (int service_count,
-			      struct objdb_iface_ver0 *objdb)
+/*
+ * Links default services into the executive
+ */
+unsigned int openais_service_defaults_link_and_init (struct objdb_iface_ver0 *objdb)
 {
-	int i;
-	int res=0;
+	unsigned int i = 0;
+	unsigned int object_service_handle = 0;
+	char *found_service_name = NULL;
+	char *found_service_ver = NULL;
+	unsigned int found_service_ver_atoi = 0;
 
-	for (i = 0; i < service_count; i++) {
-		if (ais_service[i] && ais_service[i]->exec_init_fn) {
-			log_printf (LOG_LEVEL_NOTICE, "Initialising service handler '%s'\n", ais_service[i]->name);
-			res = ais_service[i]->exec_init_fn (objdb);
-			if (res != 0) {
-				break;
-			}
-		}
+	objdb->object_find_reset (OBJECT_PARENT_HANDLE);
+	while (objdb->object_find (
+		OBJECT_PARENT_HANDLE,
+		"service",
+		strlen ("service"),
+		&object_service_handle) == 0) {
+
+		objdb->object_key_get (object_service_handle,
+			"name",
+			strlen ("name"),
+			(void *)&found_service_name,
+			NULL);
+
+		objdb->object_key_get (object_service_handle,
+			"ver",
+			strlen ("ver"),
+			(void *)&found_service_ver,
+			NULL);
+
+		found_service_ver_atoi = atoi (found_service_ver);
+		
+		/* Delete this so openais_service_link_and_init() can create it correctly */
+		objdb->object_key_delete(
+		    object_service_handle, "ver", strlen ("ver"), NULL, 0);
+
+		objdb->save_iter (OBJECT_PARENT_HANDLE);
+		openais_service_link_and_init (
+			objdb,
+			found_service_name,
+			found_service_ver_atoi, object_service_handle);
+		objdb->restore_iter (OBJECT_PARENT_HANDLE);
+ 	}
+
+	if (default_services_requested (objdb)) {
+	    for (i = 0;
+		i < sizeof (default_services) / sizeof (struct default_service); i++) {
+
+		openais_service_link_and_init (
+			objdb,
+			default_services[i].name,
+			default_services[i].ver, 0);
+	    }
 	}
-	return (res);
+	
+	return (0);
 }
diff -r b907692f6e1f -r 09edbef89566 exec/service.h
--- a/exec/service.h	Mon Jan 26 20:46:12 2009 +0000
+++ b/exec/service.h	Fri Feb 06 11:34:06 2009 +0100
@@ -74,6 +74,7 @@ struct openais_service_handler {
 	int lib_service_count;
 	struct openais_exec_handler *exec_service;
 	int (*exec_init_fn) (struct objdb_iface_ver0 *);
+	int (*exec_exit_fn) (struct objdb_iface_ver0 *);
 	int (*config_init_fn) (struct objdb_iface_ver0 *);
 	void (*exec_dump_fn) (void);
 	int exec_service_count;
@@ -90,26 +91,37 @@ struct openais_service_handler {
 };
 
 struct openais_service_handler_iface_ver0 {
-	void (*test) (void);
 	struct openais_service_handler *(*openais_get_service_handler_ver0) (void);
 };
 
-extern int openais_service_objdb_add (
-	struct objdb_iface_ver0 *objdb,
-	char *name,
-	int version);
+/*
+ * Link and initialize a service
+ */
+extern unsigned int openais_service_link_and_init (
+    struct objdb_iface_ver0 *objdb,
+    char *service_name,
+    unsigned int service_ver,
+    unsigned int object_handle);
 
+/*
+ * Unlink and exit a service
+ */
+extern unsigned int openais_service_unlink_and_exit (
+    struct objdb_iface_ver0 *objdb,
+    char *service_name,
+    unsigned int service_ver);
 
-extern int openais_service_handler_register (
-	struct openais_service_handler *handler);
+/*
+ * Unlink and exit all openais services
+ */
+extern unsigned int openais_service_unlink_all (
+    struct objdb_iface_ver0 *objdb);
 
-extern int openais_service_default_objdb_set (struct objdb_iface_ver0 *objdb);
 
-extern int openais_service_link_all (
-	struct objdb_iface_ver0 *objdb);
-
-extern int openais_service_init_all (
-	int service_count,
+/*
+ * Load all of the default services
+ */
+extern unsigned int openais_service_defaults_link_and_init (
 	struct objdb_iface_ver0 *objdb);
 
 extern struct openais_service_handler *ais_service[];
