about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/uv_link_observer_t.c33
-rw-r--r--src/uv_link_t.c49
2 files changed, 36 insertions, 46 deletions
diff --git a/src/uv_link_observer_t.c b/src/uv_link_observer_t.c
index 5479f67..dbd42ba 100644
--- a/src/uv_link_observer_t.c
+++ b/src/uv_link_observer_t.c
@@ -9,7 +9,7 @@ static int uv_link_observer_read_start(uv_link_t* link) {
 
   observer = container_of(link, uv_link_observer_t, link);
 
-  return uv_link_read_start(observer->target);
+  return uv_link_read_start(observer->link.parent);
 }
 
 
@@ -18,7 +18,7 @@ static int uv_link_observer_read_stop(uv_link_t* link) {
 
   observer = container_of(link, uv_link_observer_t, link);
 
-  return uv_link_read_stop(observer->target);
+  return uv_link_read_stop(observer->link.parent);
 }
 
 
@@ -33,7 +33,7 @@ static int uv_link_observer_write(uv_link_t* link,
 
   observer = container_of(link, uv_link_observer_t, link);
 
-  return uv_link_propagate_write(observer->target, source, bufs, nbufs,
+  return uv_link_propagate_write(observer->link.parent, source, bufs, nbufs,
                                  send_handle, cb, arg);
 }
 
@@ -45,7 +45,7 @@ static int uv_link_observer_try_write(uv_link_t* link,
 
   observer = container_of(link, uv_link_observer_t, link);
 
-  return uv_link_try_write(observer->target, bufs, nbufs);
+  return uv_link_try_write(observer->link.parent, bufs, nbufs);
 }
 
 
@@ -57,7 +57,7 @@ static int uv_link_observer_shutdown(uv_link_t* link,
 
   observer = container_of(link, uv_link_observer_t, link);
 
-  return uv_link_propagate_shutdown(observer->target, source, cb, arg);
+  return uv_link_propagate_shutdown(observer->link.parent, source, cb, arg);
 }
 
 
@@ -84,12 +84,7 @@ static void uv_link_observer_read_cb(uv_link_t* link,
 
 void uv_link_observer_close(uv_link_t* link, uv_link_t* source,
                             uv_link_close_cb cb) {
-  uv_link_observer_t* observer;
-
-  observer = container_of(link, uv_link_observer_t, link);
-
-  uv_link_propagate_close(observer->target, source, cb);
-  observer->target = NULL;
+  cb(source);
 }
 
 
@@ -106,13 +101,7 @@ static uv_link_methods_t uv_link_observer_methods = {
 };
 
 
-static void uv_link_observer_empty_close_cb(uv_link_t* link) {
-  /* no-op */
-}
-
-
-int uv_link_observer_init(uv_link_observer_t* observer,
-                          uv_link_t* target) {
+int uv_link_observer_init(uv_link_observer_t* observer) {
   int err;
 
   memset(observer, 0, sizeof(*observer));
@@ -121,13 +110,5 @@ int uv_link_observer_init(uv_link_observer_t* observer,
   if (err != 0)
     return err;
 
-  observer->target = target;
-
-  err = uv_link_chain(target, &observer->link);
-  if (err != 0) {
-    uv_link_close(&observer->link, uv_link_observer_empty_close_cb);
-    return err;
-  }
-
   return 0;
 }
diff --git a/src/uv_link_t.c b/src/uv_link_t.c
index e930a8f..d63a07b 100644
--- a/src/uv_link_t.c
+++ b/src/uv_link_t.c
@@ -35,38 +35,47 @@ int uv_link_init(uv_link_t* link, uv_link_methods_t const* methods) {
 }
 
 
-static void uv_link_close_parent(uv_link_t* link) {
-  uv_link_t* target;
-  uv_link_t* source;
-  uv_link_close_cb cb;
-
-  target = link->parent;
-  source = link->saved_close_source;
-  cb = link->saved_close_cb;
+static void uv_link_close_join(uv_link_t* link) {
+  if (--link->close_waiting == 0)
+    return link->saved_close_cb(link);
+}
 
-  memset(link, 0, sizeof(*link));
 
-  if (target == NULL)
-    cb(source);
-  else
-    uv_link_propagate_close(target, source, cb);
+void uv_link_close(uv_link_t* link, uv_link_close_cb cb) {
+  uv_link_propagate_close(link, link, cb);
 }
 
 
 void uv_link_propagate_close(uv_link_t* link, uv_link_t* source,
                              uv_link_close_cb cb) {
+  uv_link_t* root;
+  int count;
+
   CHECK_EQ(link->child, NULL, "uv_link_t: attempt to close chained link");
-  uv_link_methods_t const* methods;
 
-  methods = link->methods;
+  /* Find root */
+  count = 1;
+  for (root = link; root->parent != NULL; root = root->parent)
+    count++;
+
+  /* NOTE: This is very important line. Only because we `+=` here the
+   * recursive propagation is possible
+   */
+  source->close_waiting += count;
+
+  source->saved_close_cb = cb;
 
-  if (link->parent != NULL)
-    CHECK_EQ(uv_link_unchain(link->parent, link), 0, "uv_link_unchain()");
+  /* Go from the root to the leaf, disconnecting and closing everything */
+  while (root != NULL) {
+    uv_link_t* child;
 
-  link->saved_close_source = source;
-  link->saved_close_cb = cb;
+    child = root->child;
+    if (child != NULL)
+      CHECK_EQ(uv_link_unchain(root, child), 0, "close unchain");
 
-  methods->close(link, link, uv_link_close_parent);
+    root->methods->close(root, source, uv_link_close_join);
+    root = child;
+  }
 }