Просмотр исходного кода

ncd: gracefully finish modules when terminating

ambrop7 15 лет назад
Родитель
Сommit
b760ee95eb
1 измененных файлов с 114 добавлено и 63 удалено
  1. 114 63
      ncd/ncd.c

+ 114 - 63
ncd/ncd.c

@@ -54,6 +54,7 @@
 #define LOGGER_STDOUT 1
 #define LOGGER_SYSLOG 2
 
+#define INTERFACE_STATE_TERMINATING 0
 #define INTERFACE_STATE_WAITDEPS 1
 #define INTERFACE_STATE_RESETTING 2
 #define INTERFACE_STATE_WAITMODULE 3
@@ -93,6 +94,7 @@ struct interface {
     BTimer reset_timer;
     LinkedList2 deps_out;
     LinkedList2 deps_in;
+    BPending terminating_module_job;
     int have_module_instance;
     NCDInterfaceModuleInst module_instance;
     int module_instance_finishing;
@@ -133,6 +135,9 @@ struct ipv4_dns_entry {
 // reactor
 BReactor ss;
 
+// are we terminating
+int terminating;
+
 // process manager
 BProcessManager manager;
 
@@ -146,17 +151,18 @@ LinkedList2 interfaces;
 size_t num_ipv4_dns_servers;
 
 static void terminate (void);
+static void work_terminate (void);
 static void print_help (const char *name);
 static void print_version (void);
 static int parse_arguments (int argc, char *argv[]);
 static void signal_handler (void *unused);
 static void load_interfaces (struct NCDConfig_interfaces *conf);
-static void free_interfaces (void);
 static int set_dns_servers (void);
 static int dns_qsort_comparator (const void *v1, const void *v2);
 static struct interface * find_interface (const char *name);
 static int interface_init (struct NCDConfig_interfaces *conf);
-static void interface_free (struct interface *iface);
+static void interface_terminate (struct interface *iface);
+static void interface_terminating_module_job_handler (struct interface *iface);
 static void interface_down_to (struct interface *iface, int state);
 static void interface_reset (struct interface *iface);
 static void interface_start (struct interface *iface);
@@ -167,6 +173,8 @@ static int interface_module_init (struct interface *iface);
 static void interface_module_free (struct interface *iface);
 static void interface_module_handler_event (struct interface *iface, int event);
 static void interface_module_handler_error (struct interface *iface);
+static int interface_dhcp_init (struct interface *iface);
+static void interface_dhcp_free (struct interface *iface);
 static void interface_dhcp_handler (struct interface *iface, int event);
 static void interface_remove_dependencies (struct interface *iface);
 static int interface_add_dependency (struct interface *iface, struct interface *dst);
@@ -261,6 +269,9 @@ int main (int argc, char **argv)
         goto fail1;
     }
     
+    // set not terminating
+    terminating = 0;
+    
     // init process manager
     if (!BProcessManager_Init(&manager, &ss)) {
         BLog(BLOG_ERROR, "BProcessManager_Init failed");
@@ -304,60 +315,54 @@ int main (int argc, char **argv)
     // init interfaces
     load_interfaces(configuration);
     
-    goto event_loop;
+    // enter event loop
+    BLog(BLOG_NOTICE, "entering event loop");
+    BReactor_Exec(&ss);
     
 fail5:
+    // free configuration
     NCDConfig_free_interfaces(configuration);
 fail3:
+    // remove signal handler
     BSignal_Finish();
 fail2:
+    // free process manager
     BProcessManager_Free(&manager);
 fail1a:
-    BReactor_Free(&ss);
-fail1:
-    BLog(BLOG_ERROR, "initialization failed");
-    BLog_Free();
-fail0:
-    // finish objects
-    DebugObjectGlobal_Finish();
-    return 1;
-    
-event_loop:
-    // enter event loop
-    BLog(BLOG_NOTICE, "entering event loop");
-    int ret = BReactor_Exec(&ss);
-    
     // free reactor
     BReactor_Free(&ss);
-    
+fail1:
     // free logger
     BLog(BLOG_NOTICE, "exiting");
     BLog_Free();
-    
+fail0:
     // finish objects
     DebugObjectGlobal_Finish();
     
-    return ret;
+    return 1;
 }
 
 void terminate (void)
 {
-    BLog(BLOG_NOTICE, "tearing down");
-    
-    // free interfaces
-    free_interfaces();
+    ASSERT(!terminating)
     
-    // free configuration
-    NCDConfig_free_interfaces(configuration);
+    BLog(BLOG_NOTICE, "tearing down");
     
-    // remove signal handler
-    BSignal_Finish();
+    terminating = 1;
     
-    // free process manager
-    BProcessManager_Free(&manager);
+    work_terminate();
+}
+
+void work_terminate (void)
+{
+    ASSERT(terminating)
     
-    // exit reactor
-    BReactor_Quit(&ss, 1);
+    if (LinkedList2_IsEmpty(&interfaces)) {
+        BReactor_Quit(&ss, 1);
+    } else {
+        struct interface *iface = UPPER_OBJECT(LinkedList2_GetLast(&interfaces), struct interface, list_node);
+        interface_terminate(iface);
+    }
 }
 
 void print_help (const char *name)
@@ -510,8 +515,9 @@ void signal_handler (void *unused)
 {
     BLog(BLOG_NOTICE, "termination requested");
     
-    terminate();
-    return;
+    if (!terminating) {
+        terminate();
+    }
 }
 
 void load_interfaces (struct NCDConfig_interfaces *conf)
@@ -522,16 +528,6 @@ void load_interfaces (struct NCDConfig_interfaces *conf)
     }
 }
 
-void free_interfaces (void)
-{
-    // remove in reverse order so we don't have to remove incoming dependencies
-    LinkedList2Node *node;
-    while (node = LinkedList2_GetLast(&interfaces)) {
-        struct interface *iface = UPPER_OBJECT(node, struct interface, list_node);
-        interface_free(iface);
-    }
-}
-
 struct dns_sort_entry {
     uint32_t addr;
     int priority;
@@ -685,6 +681,9 @@ int interface_init (struct NCDConfig_interfaces *conf)
     // init incoming dependencies list
     LinkedList2_Init(&iface->deps_in);
     
+    // init terminating module job
+    BPending_Init(&iface->terminating_module_job, BReactor_PendingGroup(&ss), (BPending_handler)interface_terminating_module_job_handler, iface);
+    
     // set no module instance
     iface->have_module_instance = 0;
     
@@ -715,22 +714,51 @@ fail0:
     return 0;
 }
 
-void interface_free (struct interface *iface)
+void interface_terminate (struct interface *iface)
 {
+    ASSERT(terminating)
     ASSERT(LinkedList2_IsEmpty(&iface->deps_in))
     
+    // stop reset timer
+    BReactor_RemoveTimer(&ss, &iface->reset_timer);
+    
     // deconfigure IPv4
     interface_deconfigure_ipv4(iface);
     
     // free DHCP
     if (iface->have_dhcp) {
-        BDHCPClient_Free(&iface->dhcp);
+        interface_dhcp_free(iface);
     }
     
-    // free module instance
+    // finish module instance
     if (iface->have_module_instance) {
-        interface_module_free(iface);
+        if (!iface->module_instance_finishing) {
+            NCDInterfaceModuleInst_Finish(&iface->module_instance);
+            iface->module_instance_finishing = 1;
+        }
+        
+        interface_log(iface, BLOG_INFO, "waiting for module to finish");
+        
+        // wait for module to finish
+        iface->state = INTERFACE_STATE_TERMINATING;
+    } else {
+        // continue now
+        BPending_Set(&iface->terminating_module_job);
     }
+}
+
+void interface_terminating_module_job_handler (struct interface *iface)
+{
+    ASSERT(terminating)
+    ASSERT(!BTimer_IsRunning(&iface->reset_timer))
+    ASSERT(LinkedList2_IsEmpty(&iface->ipv4_addresses))
+    ASSERT(LinkedList2_IsEmpty(&iface->ipv4_routes))
+    ASSERT(LinkedList2_IsEmpty(&iface->ipv4_dns_servers))
+    ASSERT(!iface->have_dhcp)
+    ASSERT(!iface->have_module_instance)
+    
+    // free terminating module job
+    BPending_Free(&iface->terminating_module_job);
     
     // remove from interfaces list
     LinkedList2_Remove(&interfaces, &iface->list_node);
@@ -738,11 +766,11 @@ void interface_free (struct interface *iface)
     // remove outgoing dependencies
     interface_remove_dependencies(iface);
     
-    // stop reset timer
-    BReactor_RemoveTimer(&ss, &iface->reset_timer);
-    
     // free memory
     free(iface);
+    
+    // continue terminating
+    work_terminate();
 }
 
 void interface_down_to (struct interface *iface, int state)
@@ -759,8 +787,7 @@ void interface_down_to (struct interface *iface, int state)
     
     // deconfigure DHCP
     if (state < INTERFACE_STATE_DHCP && iface->have_dhcp) {
-        BDHCPClient_Free(&iface->dhcp);
-        iface->have_dhcp = 0;
+        interface_dhcp_free(iface);
     }
     
     // finish module instance
@@ -849,14 +876,10 @@ void interface_module_up (struct interface *iface)
         }
         
         // init DHCP client
-        if (!BDHCPClient_Init(&iface->dhcp, iface->conf->name, &ss, (BDHCPClient_handler)interface_dhcp_handler, iface)) {
-            interface_log(iface, BLOG_ERROR, "BDHCPClient_Init failed");
+        if (!interface_dhcp_init(iface)) {
             goto fail;
         }
         
-        // set have DHCP
-        iface->have_dhcp = 1;
-        
         // set state
         iface->state = INTERFACE_STATE_DHCP;
         
@@ -972,15 +995,43 @@ void interface_module_handler_error (struct interface *iface)
         // free module
         interface_module_free(iface);
         
-        if (
-            iface->state == INTERFACE_STATE_WAITDEPS ||
-            (iface->state == INTERFACE_STATE_RESETTING && !BTimer_IsRunning(&iface->reset_timer))
-        ) {
-            interface_start(iface);
+        if (iface->state >= INTERFACE_STATE_WAITDEPS) {
+            if (
+                iface->state == INTERFACE_STATE_WAITDEPS ||
+                (iface->state == INTERFACE_STATE_RESETTING && !BTimer_IsRunning(&iface->reset_timer))
+            ) {
+                interface_start(iface);
+            }
+        }
+        else { // INTERFACE_STATE_TERMINATING
+            BPending_Set(&iface->terminating_module_job);
         }
     }
 }
 
+static int interface_dhcp_init (struct interface *iface)
+{
+    ASSERT(!iface->have_dhcp)
+    
+    if (!BDHCPClient_Init(&iface->dhcp, iface->conf->name, &ss, (BDHCPClient_handler)interface_dhcp_handler, iface)) {
+        interface_log(iface, BLOG_ERROR, "BDHCPClient_Init failed");
+        return 0;
+    }
+    
+    iface->have_dhcp = 1;
+    
+    return 1;
+}
+
+static void interface_dhcp_free (struct interface *iface)
+{
+    ASSERT(iface->have_dhcp)
+    
+    BDHCPClient_Free(&iface->dhcp);
+    
+    iface->have_dhcp = 0;
+}
+
 void interface_dhcp_handler (struct interface *iface, int event)
 {
     ASSERT(iface->have_dhcp)