ambrop7 15 лет назад
Родитель
Сommit
9e62542b6d

+ 1 - 0
blog_channels.txt

@@ -5,6 +5,7 @@ tun2socks 4
 ncd 4
 ncd_var 4
 ncd_list 4
+ncd_depend 4
 ncd_net_backend_physical 4
 ncd_net_backend_badvpn 4
 ncd_net_dns 4

+ 4 - 0
generated/blog_channel_ncd_depend.h

@@ -0,0 +1,4 @@
+#ifdef BLOG_CURRENT_CHANNEL
+#undef BLOG_CURRENT_CHANNEL
+#endif
+#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_ncd_depend

+ 24 - 23
generated/blog_channels_defines.h

@@ -5,26 +5,27 @@
 #define BLOG_CHANNEL_ncd 4
 #define BLOG_CHANNEL_ncd_var 5
 #define BLOG_CHANNEL_ncd_list 6
-#define BLOG_CHANNEL_ncd_net_backend_physical 7
-#define BLOG_CHANNEL_ncd_net_backend_badvpn 8
-#define BLOG_CHANNEL_ncd_net_dns 9
-#define BLOG_CHANNEL_ncd_net_ipv4_addr 10
-#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 11
-#define BLOG_CHANNEL_ncd_net_ipv4_route 12
-#define BLOG_CHANNEL_StreamPeerIO 13
-#define BLOG_CHANNEL_DatagramPeerIO 14
-#define BLOG_CHANNEL_BReactor 15
-#define BLOG_CHANNEL_BSignal 16
-#define BLOG_CHANNEL_FragmentProtoAssembler 17
-#define BLOG_CHANNEL_BPredicate 18
-#define BLOG_CHANNEL_ServerConnection 19
-#define BLOG_CHANNEL_Listener 20
-#define BLOG_CHANNEL_DataProto 21
-#define BLOG_CHANNEL_FrameDecider 22
-#define BLOG_CHANNEL_BSocksClient 23
-#define BLOG_CHANNEL_BDHCPClientCore 24
-#define BLOG_CHANNEL_BDHCPClient 25
-#define BLOG_CHANNEL_NCDIfConfig 26
-#define BLOG_CHANNEL_BUnixSignal 27
-#define BLOG_CHANNEL_BProcess 28
-#define BLOG_NUM_CHANNELS 29
+#define BLOG_CHANNEL_ncd_depend 7
+#define BLOG_CHANNEL_ncd_net_backend_physical 8
+#define BLOG_CHANNEL_ncd_net_backend_badvpn 9
+#define BLOG_CHANNEL_ncd_net_dns 10
+#define BLOG_CHANNEL_ncd_net_ipv4_addr 11
+#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 12
+#define BLOG_CHANNEL_ncd_net_ipv4_route 13
+#define BLOG_CHANNEL_StreamPeerIO 14
+#define BLOG_CHANNEL_DatagramPeerIO 15
+#define BLOG_CHANNEL_BReactor 16
+#define BLOG_CHANNEL_BSignal 17
+#define BLOG_CHANNEL_FragmentProtoAssembler 18
+#define BLOG_CHANNEL_BPredicate 19
+#define BLOG_CHANNEL_ServerConnection 20
+#define BLOG_CHANNEL_Listener 21
+#define BLOG_CHANNEL_DataProto 22
+#define BLOG_CHANNEL_FrameDecider 23
+#define BLOG_CHANNEL_BSocksClient 24
+#define BLOG_CHANNEL_BDHCPClientCore 25
+#define BLOG_CHANNEL_BDHCPClient 26
+#define BLOG_CHANNEL_NCDIfConfig 27
+#define BLOG_CHANNEL_BUnixSignal 28
+#define BLOG_CHANNEL_BProcess 29
+#define BLOG_NUM_CHANNELS 30

+ 1 - 0
generated/blog_channels_list.h

@@ -5,6 +5,7 @@
 {.name = "ncd", .loglevel = 4},
 {.name = "ncd_var", .loglevel = 4},
 {.name = "ncd_list", .loglevel = 4},
+{.name = "ncd_depend", .loglevel = 4},
 {.name = "ncd_net_backend_physical", .loglevel = 4},
 {.name = "ncd_net_backend_badvpn", .loglevel = 4},
 {.name = "ncd_net_dns", .loglevel = 4},

+ 1 - 0
ncd/CMakeLists.txt

@@ -6,6 +6,7 @@ add_executable(badvpn-ncd
     NCDInterfaceMonitor.c
     modules/var.c
     modules/list.c
+    modules/depend.c
     modules/net_backend_physical.c
     modules/net_backend_badvpn.c
     modules/net_dns.c

+ 43 - 16
ncd/NCDModule.c

@@ -34,17 +34,35 @@ static void event_job_handler (NCDModuleInst *n)
     return;
 }
 
-static void die_job_handler (NCDModuleInst *n)
+static void toevent_job_handler (NCDModuleInst *n)
 {
     DebugObject_Access(&n->d_obj);
     
-    if (!n->m->func_die) {
-        NCDModuleInst_Backend_Died(n, 0);
-        return;
+    switch (n->toevent_job_event) {
+        case NCDMODULE_TOEVENT_DIE: {
+            ASSERT(n->state == STATE_DYING)
+            
+            if (!n->m->func_die) {
+                NCDModuleInst_Backend_Died(n, 0);
+                return;
+            }
+            
+            n->m->func_die(n->inst_user);
+            return;
+        } break;
+        
+        case NCDMODULE_TOEVENT_CLEAN: {
+            ASSERT(n->state == STATE_UP || n->state == STATE_DOWN)
+            
+            if (n->m->func_clean) {
+                n->m->func_clean(n->inst_user);
+                return;
+            }
+        } break;
+        
+        default:
+            ASSERT(0);
     }
-    
-    n->m->func_die(n->inst_user);
-    return;
 }
 
 int NCDModuleInst_Init (NCDModuleInst *n, const char *name, const struct NCDModule *m, NCDValue *args, const char *logprefix, BReactor *reactor, BProcessManager *manager,
@@ -64,8 +82,8 @@ int NCDModuleInst_Init (NCDModuleInst *n, const char *name, const struct NCDModu
     // init event job
     BPending_Init(&n->event_job, BReactor_PendingGroup(n->reactor), (BPending_handler)event_job_handler, n);
     
-    // init die job
-    BPending_Init(&n->die_job, BReactor_PendingGroup(n->reactor), (BPending_handler)die_job_handler, n);
+    // init toevent job
+    BPending_Init(&n->toevent_job, BReactor_PendingGroup(n->reactor), (BPending_handler)toevent_job_handler, n);
     
     // set state
     n->state = STATE_DOWN;
@@ -83,7 +101,7 @@ int NCDModuleInst_Init (NCDModuleInst *n, const char *name, const struct NCDModu
     return 1;
     
 fail1:
-    BPending_Free(&n->die_job);
+    BPending_Free(&n->toevent_job);
     BPending_Free(&n->event_job);
     return 0;
 }
@@ -98,23 +116,31 @@ void NCDModuleInst_Free (NCDModuleInst *n)
     // free backend
     n->m->func_free(n->inst_user);
     
-    // free die job
-    BPending_Free(&n->die_job);
+    // free toevent job
+    BPending_Free(&n->toevent_job);
     
     // free event job
     BPending_Free(&n->event_job);
 }
 
-void NCDModuleInst_Die (NCDModuleInst *n)
+void NCDModuleInst_Event (NCDModuleInst *n, int event)
 {
+    ASSERT(event == NCDMODULE_TOEVENT_DIE || event == NCDMODULE_TOEVENT_CLEAN)
     ASSERT(n->state == STATE_UP || n->state == STATE_DOWN)
+    ASSERT(!BPending_IsSet(&n->event_job))
+    ASSERT(!BPending_IsSet(&n->toevent_job))
     DebugObject_Access(&n->d_obj);
     
-    // set state
-    n->state = STATE_DYING;
+    if (event == NCDMODULE_TOEVENT_DIE) {
+        // set state
+        n->state = STATE_DYING;
+    }
+    
+    // remember event
+    n->toevent_job_event = event;
     
     // set job
-    BPending_Set(&n->die_job);
+    BPending_Set(&n->toevent_job);
 }
 
 int NCDModuleInst_GetVar (NCDModuleInst *n, const char *name, NCDValue *out)
@@ -136,6 +162,7 @@ void NCDModuleInst_Backend_Event (NCDModuleInst *n, int event)
     ASSERT(!(event == NCDMODULE_EVENT_DOWN) || n->state == STATE_UP)
     ASSERT(!(event == NCDMODULE_EVENT_DYING) || (n->state == STATE_DOWN || n->state == STATE_UP))
     ASSERT(!BPending_IsSet(&n->event_job))
+    ASSERT(!BPending_IsSet(&n->toevent_job))
     
     switch (event) {
         case NCDMODULE_EVENT_UP:

+ 8 - 2
ncd/NCDModule.h

@@ -36,6 +36,9 @@
 #define NCDMODULE_EVENT_DOWN 2
 #define NCDMODULE_EVENT_DYING 3
 
+#define NCDMODULE_TOEVENT_DIE 101
+#define NCDMODULE_TOEVENT_CLEAN 102
+
 typedef void (*NCDModule_handler_event) (void *user, int event);
 typedef void (*NCDModule_handler_died) (void *user, int is_error);
 
@@ -53,7 +56,8 @@ typedef struct {
     void *user;
     BPending event_job;
     int event_job_event;
-    BPending die_job;
+    BPending toevent_job;
+    int toevent_job_event;
     int state;
     void *inst_user;
     DebugObject d_obj;
@@ -65,7 +69,7 @@ typedef struct {
 int NCDModuleInst_Init (NCDModuleInst *n, const char *name, const struct NCDModule *m, NCDValue *args, const char *logprefix, BReactor *reactor, BProcessManager *manager,
                         NCDModule_handler_event handler_event, NCDModule_handler_died handler_died, void *user);
 void NCDModuleInst_Free (NCDModuleInst *n);
-void NCDModuleInst_Die (NCDModuleInst *n);
+void NCDModuleInst_Event (NCDModuleInst *n, int event);
 int NCDModuleInst_GetVar (NCDModuleInst *n, const char *name, NCDValue *out);
 void NCDModuleInst_Backend_Event (NCDModuleInst *n, int event);
 void NCDModuleInst_Backend_Died (NCDModuleInst *n, int is_error);
@@ -76,6 +80,7 @@ typedef void * (*NCDModule_func_new) (NCDModuleInst *params);
 typedef void (*NCDModule_func_free) (void *o);
 typedef void (*NCDModule_func_die) (void *o);
 typedef int (*NCDModule_func_getvar) (void *o, const char *name, NCDValue *out);
+typedef void (*NCDModule_func_clean) (void *o);
 
 struct NCDModule {
     const char *type;
@@ -83,6 +88,7 @@ struct NCDModule {
     NCDModule_func_free func_free;
     NCDModule_func_die func_die;
     NCDModule_func_getvar func_getvar;
+    NCDModule_func_clean func_clean;
 };
 
 struct NCDModuleGroup {

+ 315 - 0
ncd/modules/depend.c

@@ -0,0 +1,315 @@
+/**
+ * @file depend.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * @section DESCRIPTION
+ * 
+ * Dependencies module.
+ * 
+ * Synopsis: provide(string name)
+ * 
+ * Synopsis: depend(string name)
+ */
+
+#include <stdlib.h>
+
+#include <misc/offset.h>
+#include <structure/LinkedList2.h>
+#include <ncd/NCDModule.h>
+
+#include <generated/blog_channel_ncd_depend.h>
+
+#define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+
+struct provide {
+    NCDModuleInst *i;
+    char *name;
+    LinkedList2Node provides_node;
+    LinkedList2 depends;
+    int dying;
+};
+
+struct depend {
+    NCDModuleInst *i;
+    char *name;
+    struct provide *p;
+    LinkedList2Node node;
+};
+
+LinkedList2 provides;
+LinkedList2 free_depends;
+
+static struct provide * find_provide (const char *name)
+{
+    LinkedList2Iterator it;
+    LinkedList2Iterator_InitForward(&it, &provides);
+    LinkedList2Node *n;
+    while (n = LinkedList2Iterator_Next(&it)) {
+        struct provide *p = UPPER_OBJECT(n, struct provide, provides_node);
+        if (!strcmp(p->name, name)) {
+            LinkedList2Iterator_Free(&it);
+            return p;
+        }
+    }
+    
+    return NULL;
+}
+
+static int func_globalinit (void)
+{
+    // init provides list
+    LinkedList2_Init(&provides);
+    
+    // init free depends list
+    LinkedList2_Init(&free_depends);
+    
+    return 1;
+}
+
+static void * provide_func_new (NCDModuleInst *i)
+{
+    // allocate instance
+    struct provide *o = malloc(sizeof(*o));
+    if (!o) {
+        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    
+    // init arguments
+    o->i = i;
+    
+    // read arguments
+    NCDValue *name_arg;
+    if (!NCDValue_ListRead(o->i->args, 1, &name_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    if (NCDValue_Type(name_arg) != NCDVALUE_STRING) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong type");
+        goto fail1;
+    }
+    o->name = NCDValue_StringValue(name_arg);
+    
+    // check for existing provide with this name
+    if (find_provide(o->name)) {
+        ModuleLog(o->i, BLOG_ERROR, "a provide with this name already exists");
+        goto fail1;
+    }
+    
+    // insert to provides list
+    LinkedList2_Append(&provides, &o->provides_node);
+    
+    // init depends list
+    LinkedList2_Init(&o->depends);
+    
+    // set not dying
+    o->dying = 0;
+    
+    // attach free depends with this name
+    LinkedList2Iterator it;
+    LinkedList2Iterator_InitForward(&it, &free_depends);
+    LinkedList2Node *n;
+    while (n = LinkedList2Iterator_Next(&it)) {
+        struct depend *d = UPPER_OBJECT(n, struct depend, node);
+        ASSERT(!d->p)
+        
+        if (strcmp(d->name, o->name)) {
+            continue;
+        }
+        
+        // remove from free depends list
+        LinkedList2_Remove(&free_depends, &d->node);
+        
+        // set provide
+        d->p = o;
+        
+        // insert to provide's list
+        LinkedList2_Append(&o->depends, &d->node);
+        
+        // signal up
+        NCDModuleInst_Backend_Event(d->i, NCDMODULE_EVENT_UP);
+    }
+    
+    NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
+    
+    return o;
+    
+fail1:
+    free(o);
+fail0:
+    return NULL;
+}
+
+static void provide_func_free (void *vo)
+{
+    struct provide *o = vo;
+    ASSERT(LinkedList2_IsEmpty(&o->depends))
+    
+    // remove from provides list
+    LinkedList2_Remove(&provides, &o->provides_node);
+    
+    // free instance
+    free(o);
+}
+
+static void provide_func_die (void *vo)
+{
+    struct provide *o = vo;
+    ASSERT(!o->dying)
+    
+    // if we have no depends, die immediately
+    if (LinkedList2_IsEmpty(&o->depends)) {
+        NCDModuleInst_Backend_Died(o->i, 0);
+        return;
+    }
+    
+    // set dying
+    o->dying = 1;
+    
+    // signal our depends down
+    LinkedList2Iterator it;
+    LinkedList2Iterator_InitForward(&it, &o->depends);
+    LinkedList2Node *n;
+    while (n = LinkedList2Iterator_Next(&it)) {
+        struct depend *d = UPPER_OBJECT(n, struct depend, node);
+        ASSERT(d->p == o)
+        
+        // signal down
+        NCDModuleInst_Backend_Event(d->i, NCDMODULE_EVENT_DOWN);
+    }
+}
+
+static void * depend_func_new (NCDModuleInst *i)
+{
+    // allocate instance
+    struct depend *o = malloc(sizeof(*o));
+    if (!o) {
+        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    
+    // init arguments
+    o->i = i;
+    
+    // read arguments
+    NCDValue *name_arg;
+    if (!NCDValue_ListRead(o->i->args, 1, &name_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    if (NCDValue_Type(name_arg) != NCDVALUE_STRING) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong type");
+        goto fail1;
+    }
+    o->name = NCDValue_StringValue(name_arg);
+    
+    // find a provide with our name
+    o->p = find_provide(o->name);
+    
+    // do not attach to a dying provide
+    if (o->p && o->p->dying) {
+        o->p = NULL;
+    }
+    
+    if (o->p) {
+        // insert to provide's list
+        LinkedList2_Append(&o->p->depends, &o->node);
+        
+        // signal up
+        NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
+    } else {
+        // insert to free depends list
+        LinkedList2_Append(&free_depends, &o->node);
+    }
+    
+    return o;
+    
+fail1:
+    free(o);
+fail0:
+    return NULL;
+}
+
+static void depend_func_free (void *vo)
+{
+    struct depend *o = vo;
+    
+    if (o->p) {
+        // remove from provide's list
+        LinkedList2_Remove(&o->p->depends, &o->node);
+        
+        // if provide is dying and is empty, let it die
+        if (o->p->dying && LinkedList2_IsEmpty(&o->p->depends)) {
+            NCDModuleInst_Backend_Died(o->p->i, 0);
+        }
+    } else {
+        // remove free depends list
+        LinkedList2_Remove(&free_depends, &o->node);
+    }
+    
+    // free instance
+    free(o);
+}
+
+static void depend_func_clean (void *vo)
+{
+    struct depend *o = vo;
+    
+    if (!(o->p && o->p->dying)) {
+        return;
+    }
+    
+    struct provide *p = o->p;
+    
+    // remove from provide's list
+    LinkedList2_Remove(&o->p->depends, &o->node);
+    
+    // set no provide
+    o->p = NULL;
+    
+    // insert to free depends list
+    LinkedList2_Append(&free_depends, &o->node);
+    
+    // if provide is empty, let it die
+    if (LinkedList2_IsEmpty(&p->depends)) {
+        NCDModuleInst_Backend_Died(p->i, 0);
+    }
+}
+
+static const struct NCDModule modules[] = {
+    {
+        .type = "provide",
+        .func_new = provide_func_new,
+        .func_free = provide_func_free,
+        .func_die = provide_func_die
+    }, {
+        .type = "depend",
+        .func_new = depend_func_new,
+        .func_free = depend_func_free,
+        .func_clean = depend_func_clean
+    }, {
+        .type = NULL
+    }
+};
+
+const struct NCDModuleGroup ncdmodule_depend = {
+    .func_globalinit = func_globalinit,
+    .modules = modules
+};

+ 4 - 0
ncd/modules/modules.h

@@ -23,10 +23,13 @@
 #ifndef BADVPN_NCD_MODULES_MODULES_H
 #define BADVPN_NCD_MODULES_MODULES_H
 
+#include <stddef.h>
+
 #include <ncd/NCDModule.h>
 
 extern const struct NCDModuleGroup ncdmodule_var;
 extern const struct NCDModuleGroup ncdmodule_list;
+extern const struct NCDModuleGroup ncdmodule_depend;
 extern const struct NCDModuleGroup ncdmodule_net_backend_physical;
 extern const struct NCDModuleGroup ncdmodule_net_backend_badvpn;
 extern const struct NCDModuleGroup ncdmodule_net_dns;
@@ -37,6 +40,7 @@ extern const struct NCDModuleGroup ncdmodule_net_ipv4_dhcp;
 static const struct NCDModuleGroup *ncd_modules[] = {
     &ncdmodule_var,
     &ncdmodule_list,
+    &ncdmodule_depend,
     &ncdmodule_net_backend_physical,
     &ncdmodule_net_backend_badvpn,
     &ncdmodule_net_dns,

+ 42 - 17
ncd/ncd.c

@@ -83,6 +83,7 @@ struct process {
     size_t ap;
     size_t fp;
     BTimer wait_timer;
+    BPending advance_job;
     LinkedList2Node list_node; // node in processes
 };
 
@@ -156,6 +157,7 @@ static void process_assert (struct process *p);
 static void process_log (struct process *p, int level, const char *fmt, ...);
 static void process_work (struct process *p);
 static void process_fight (struct process *p);
+static void process_advance_job_handler (struct process *p);
 static void process_advance (struct process *p);
 static void process_wait (struct process *p);
 static void process_wait_timer_handler (struct process *p);
@@ -681,6 +683,9 @@ int process_new (struct NCDConfig_interfaces *conf)
     // init timer
     BTimer_Init(&p->wait_timer, RETRY_TIME, (BTimer_handler)process_wait_timer_handler, p);
     
+    // init advance job
+    BPending_Init(&p->advance_job, BReactor_PendingGroup(&ss), (BPending_handler)process_advance_job_handler, p);
+    
     // insert to processes list
     LinkedList2_Append(&processes, &p->list_node);
     
@@ -706,6 +711,9 @@ void process_free (struct process *p)
     // remove from processes list
     LinkedList2_Remove(&processes, &p->list_node);
     
+    // free advance job
+    BPending_Free(&p->advance_job);
+    
     // free timer
     BReactor_RemoveTimer(&ss, &p->wait_timer);
     
@@ -775,6 +783,11 @@ void process_work (struct process *p)
     // stop timer in case we were WAITING
     BReactor_RemoveTimer(&ss, &p->wait_timer);
     
+    // stop advance job if we can't advance
+    if (!(p->ap == p->fp && !terminating)) {
+        BPending_Unset(&p->advance_job);
+    }
+    
     if (terminating) {
         process_retreat(p);
         return;
@@ -786,27 +799,39 @@ void process_work (struct process *p)
 void process_fight (struct process *p)
 {
     if (p->ap == p->fp) {
-        if (!(p->ap > 0 && p->statements[p->ap - 1].state == SSTATE_CHILD)) {
-            // advance
-            process_advance(p);
+        // schedule advance
+        BPending_Set(&p->advance_job);
+        
+        // report clean
+        if (p->ap > 0) {
+            NCDModuleInst_Event(&p->statements[p->ap - 1].inst, NCDMODULE_TOEVENT_CLEAN);
+        }
+    } else {
+        // order the last living statement to die, if needed
+        struct process_statement *ps = &p->statements[p->fp - 1];
+        if (ps->state != SSTATE_DYING) {
+            process_statement_log(ps, BLOG_INFO, "killing");
+            
+            // order it to die
+            NCDModuleInst_Event(&ps->inst, NCDMODULE_TOEVENT_DIE);
+            
+            // set statement state DYING
+            ps->state = SSTATE_DYING;
         }
         
-        return;
+        process_assert(p);
     }
+}
+
+void process_advance_job_handler (struct process *p)
+{
+    ASSERT(p->ap == p->fp)
+    ASSERT(!terminating)
     
-    // order the last living statement to die, if needed
-    struct process_statement *ps = &p->statements[p->fp - 1];
-    if (ps->state != SSTATE_DYING) {
-        process_statement_log(ps, BLOG_INFO, "killing");
-        
-        // order it to die
-        NCDModuleInst_Die(&ps->inst);
-        
-        // set statement state DYING
-        ps->state = SSTATE_DYING;
+    if (!(p->ap > 0 && p->statements[p->ap - 1].state == SSTATE_CHILD)) {
+        // advance
+        process_advance(p);
     }
-    
-    process_assert(p);
 }
 
 void process_advance (struct process *p)
@@ -959,7 +984,7 @@ void process_retreat (struct process *p)
         process_statement_log(ps, BLOG_INFO, "killing");
         
         // order it to die
-        NCDModuleInst_Die(&ps->inst);
+        NCDModuleInst_Event(&ps->inst, NCDMODULE_TOEVENT_DIE);
         
         // set statement state DYING
         ps->state = SSTATE_DYING;