Ver Fonte

ncd: modules: blocker: add blocker::rdownup()

ambrop7 há 14 anos atrás
pai
commit
a523969101
1 ficheiros alterados com 109 adições e 1 exclusões
  1. 109 1
      ncd/modules/blocker.c

+ 109 - 1
ncd/modules/blocker.c

@@ -33,13 +33,22 @@
  * 
  * 
  * Synopsis: blocker()
  * Synopsis: blocker()
  * Description: provides blocking operations. Initially the blocking state is down (but this statement
  * Description: provides blocking operations. Initially the blocking state is down (but this statement
- * does not block).
+ *              does not block). On deinitialization, waits for all corresponding use() statements
+ *              to die before dying itself.
  * 
  * 
  * Synopsis: blocker::up()
  * Synopsis: blocker::up()
  * Description: sets the blocking state to up.
  * Description: sets the blocking state to up.
+ *              The immediate effects of corresponding use() statements going up are processed before
+ *              this statement goes up; but this statement statement still goes up immediately,
+ *              assuming the effects mentioned haven't resulted in the intepreter scheduling this
+ *              very statement for destruction.
  * 
  * 
  * Synopsis: blocker::down()
  * Synopsis: blocker::down()
  * Description: sets the blocking state to down.
  * Description: sets the blocking state to down.
+ *              The immediate effects of corresponding use() statements going up are processed before
+ *              this statement goes up; but this statement statement still goes up immediately,
+ *              assuming the effects mentioned haven't resulted in the intepreter scheduling this
+ *              very statement for destruction.
  * 
  * 
  * Synopsis: blocker::downup()
  * Synopsis: blocker::downup()
  * Description: atomically sets the blocker to down state (if it was up), then (back) to up state.
  * Description: atomically sets the blocker to down state (if it was up), then (back) to up state.
@@ -49,6 +58,12 @@
  *              statement. In fact, it is possible that the effects of down() will prevent up() from
  *              statement. In fact, it is possible that the effects of down() will prevent up() from
  *              executing, which may leave the program in an undesirable state.
  *              executing, which may leave the program in an undesirable state.
  * 
  * 
+ * Synopsis: blocker::rdownup()
+ * Description: on deinitialization, atomically sets the blocker to down state (if it was up), then
+ *              (back) to up state.
+ *              The immediate effects of corresponding use() statements changing state are processed
+ *              *after* the immediate effects of this statement dying (in contrast to downup()).
+ * 
  * Synopsis: blocker::use()
  * Synopsis: blocker::use()
  * Description: blocks on the blocker. This module is in up state if and only if the blocking state of
  * Description: blocks on the blocker. This module is in up state if and only if the blocking state of
  * the blocker is up. Multiple use statements may be used with the same blocker.
  * the blocker is up. Multiple use statements may be used with the same blocker.
@@ -59,6 +74,8 @@
 
 
 #include <misc/offset.h>
 #include <misc/offset.h>
 #include <misc/debug.h>
 #include <misc/debug.h>
+#include <structure/LinkedList2.h>
+#include <structure/LinkedList0.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDModule.h>
 
 
 #include <generated/blog_channel_ncd_blocker.h>
 #include <generated/blog_channel_ncd_blocker.h>
@@ -68,10 +85,17 @@
 struct instance {
 struct instance {
     NCDModuleInst *i;
     NCDModuleInst *i;
     LinkedList2 users;
     LinkedList2 users;
+    LinkedList0 rdownups_list;
     int up;
     int up;
     int dying;
     int dying;
 };
 };
 
 
+struct rdownup_instance {
+    NCDModuleInst *i;
+    struct instance *blocker;
+    LinkedList0Node rdownups_list_node;
+};
+
 struct use_instance {
 struct use_instance {
     NCDModuleInst *i;
     NCDModuleInst *i;
     struct instance *blocker;
     struct instance *blocker;
@@ -100,6 +124,9 @@ static void func_new (NCDModuleInst *i)
     // init users list
     // init users list
     LinkedList2_Init(&o->users);
     LinkedList2_Init(&o->users);
     
     
+    // init rdownups list
+    LinkedList0_Init(&o->rdownups_list);
+    
     // set not up
     // set not up
     o->up = 0;
     o->up = 0;
     
     
@@ -123,6 +150,15 @@ static void instance_free (struct instance *o)
     ASSERT(LinkedList2_IsEmpty(&o->users))
     ASSERT(LinkedList2_IsEmpty(&o->users))
     NCDModuleInst *i = o->i;
     NCDModuleInst *i = o->i;
     
     
+    // break any rdownups
+    LinkedList0Node *ln;
+    while (ln = LinkedList0_GetFirst(&o->rdownups_list)) {
+        struct rdownup_instance *rdu = UPPER_OBJECT(ln, struct rdownup_instance, rdownups_list_node);
+        ASSERT(rdu->blocker == o)
+        LinkedList0_Remove(&o->rdownups_list, &rdu->rdownups_list_node);
+        rdu->blocker = NULL;
+    }
+    
     // free instance
     // free instance
     free(o);
     free(o);
     
     
@@ -204,6 +240,74 @@ static void downup_func_new (NCDModuleInst *i)
     updown_func_new_templ(i, 1, 1);
     updown_func_new_templ(i, 1, 1);
 }
 }
 
 
+static void rdownup_func_new (NCDModuleInst *i)
+{
+    // allocate structure
+    struct rdownup_instance *o = malloc(sizeof(*o));
+    if (!o) {
+        ModuleLog(i, BLOG_ERROR, "malloc failed");
+        goto fail0;
+    }
+    o->i = i;
+    NCDModuleInst_Backend_SetUser(i, o);
+    
+    // check arguments
+    if (!NCDValue_ListRead(i->args, 0)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    
+    // get blocker
+    struct instance *blk = ((NCDModuleInst *)i->method_user)->inst_user;
+    
+    // set blocker
+    o->blocker = blk;
+    
+    // insert to rdownups list
+    LinkedList0_Prepend(&blk->rdownups_list, &o->rdownups_list_node);
+    
+    // signal up
+    NCDModuleInst_Backend_Up(i);
+    return;
+    
+fail1:
+    free(o);
+fail0:
+    NCDModuleInst_Backend_SetError(i);
+    NCDModuleInst_Backend_Dead(i);
+}
+
+static void rdownup_func_die (void *vo)
+{
+    struct rdownup_instance *o = vo;
+    NCDModuleInst *i = o->i;
+    
+    struct instance *blk = o->blocker;
+    
+    if (blk) {
+        // remove from rdownups list
+        LinkedList0_Remove(&blk->rdownups_list, &o->rdownups_list_node);
+        
+        // downup users
+        for (LinkedList2Node *ln = LinkedList2_GetFirst(&blk->users); ln; ln = LinkedList2Node_Next(ln)) {
+            struct use_instance *user = UPPER_OBJECT(ln, struct use_instance, blocker_node);
+            ASSERT(user->blocker == blk)
+            if (blk->up) {
+                NCDModuleInst_Backend_Down(user->i);
+            }
+            NCDModuleInst_Backend_Up(user->i);
+        }
+        
+        // set up
+        blk->up = 1;
+    }
+    
+    // free instance
+    free(o);
+    
+    NCDModuleInst_Backend_Dead(i);
+}
+
 static void use_func_new (NCDModuleInst *i)
 static void use_func_new (NCDModuleInst *i)
 {
 {
     // allocate instance
     // allocate instance
@@ -276,6 +380,10 @@ static const struct NCDModule modules[] = {
     }, {
     }, {
         .type = "blocker::downup",
         .type = "blocker::downup",
         .func_new = downup_func_new
         .func_new = downup_func_new
+    }, {
+        .type = "blocker::rdownup",
+        .func_new = rdownup_func_new,
+        .func_die = rdownup_func_die
     }, {
     }, {
         .type = "blocker::use",
         .type = "blocker::use",
         .func_new = use_func_new,
         .func_new = use_func_new,