about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorFedor Indutny <fedor@indutny.com>2016-05-27 21:06:45 -0400
committerFedor Indutny <fedor@indutny.com>2016-05-27 21:06:45 -0400
commit9f6eff69114a493047ffdf1bb6f0e3c86b2119aa (patch)
tree8f76debcc351a9e52ced96419d81a71afd64ecb5 /src
parentad8e9d158cc420f99c2b7c89567bed4870a88777 (diff)
downloaduv_link_t-9f6eff69114a493047ffdf1bb6f0e3c86b2119aa.tar.gz
include: close callbacks
Diffstat (limited to 'src')
-rw-r--r--src/uv_link_observer_t.c34
-rw-r--r--src/uv_link_source_t.c33
-rw-r--r--src/uv_link_t.c36
3 files changed, 75 insertions, 28 deletions
diff --git a/src/uv_link_observer_t.c b/src/uv_link_observer_t.c
index e4deabb..5479f67 100644
--- a/src/uv_link_observer_t.c
+++ b/src/uv_link_observer_t.c
@@ -82,18 +82,35 @@ 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;
+}
+
+
 static uv_link_methods_t uv_link_observer_methods = {
   .read_start = uv_link_observer_read_start,
   .read_stop = uv_link_observer_read_stop,
   .write = uv_link_observer_write,
   .try_write = uv_link_observer_try_write,
   .shutdown = uv_link_observer_shutdown,
+  .close = uv_link_observer_close,
 
   .alloc_cb_override = uv_link_observer_alloc_cb,
   .read_cb_override = uv_link_observer_read_cb
 };
 
 
+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 err;
@@ -108,24 +125,9 @@ int uv_link_observer_init(uv_link_observer_t* observer,
 
   err = uv_link_chain(target, &observer->link);
   if (err != 0) {
-    uv_link_close(&observer->link);
+    uv_link_close(&observer->link, uv_link_observer_empty_close_cb);
     return err;
   }
 
   return 0;
 }
-
-
-int uv_link_observer_close(uv_link_observer_t* observer) {
-  int err;
-
-  err = uv_link_unchain(observer->target, &observer->link);
-  if (err != 0)
-    return err;
-
-  uv_link_close(&observer->link);
-
-  observer->target = NULL;
-
-  return 0;
-}
diff --git a/src/uv_link_source_t.c b/src/uv_link_source_t.c
index c445fab..3d94ab9 100644
--- a/src/uv_link_source_t.c
+++ b/src/uv_link_source_t.c
@@ -137,12 +137,36 @@ static int uv_link_source_shutdown(uv_link_t* link,
 }
 
 
+static void uv_link_source_close_cb(uv_handle_t* handle) {
+  uv_link_source_t* source;
+
+  source = handle->data;
+
+  source->stream = NULL;
+  source->close_cb(source->close_source);
+}
+
+
+static void uv_link_source_close(uv_link_t* link, uv_link_t* source,
+                                 uv_link_close_cb cb) {
+  uv_link_source_t* s;
+
+  s = container_of(link, uv_link_source_t, link);
+
+  s->close_cb = cb;
+  s->close_source = source;
+
+  uv_close((uv_handle_t*) s->stream, uv_link_source_close_cb);
+}
+
+
 static uv_link_methods_t uv_link_source_methods = {
   .read_start = uv_link_source_read_start,
   .read_stop = uv_link_source_read_stop,
   .write = uv_link_source_write,
   .try_write = uv_link_source_try_write,
-  .shutdown = uv_link_source_shutdown
+  .shutdown = uv_link_source_shutdown,
+  .close = uv_link_source_close
 };
 
 
@@ -161,10 +185,3 @@ int uv_link_source_init(uv_link_source_t* source,
 
   return 0;
 }
-
-
-void uv_link_source_close(uv_link_source_t* source) {
-  uv_link_close(&source->link);
-
-  source->stream = NULL;
-}
diff --git a/src/uv_link_t.c b/src/uv_link_t.c
index 08b5064..e930a8f 100644
--- a/src/uv_link_t.c
+++ b/src/uv_link_t.c
@@ -35,10 +35,38 @@ int uv_link_init(uv_link_t* link, uv_link_methods_t const* methods) {
 }
 
 
-void uv_link_close(uv_link_t* link) {
-  link->alloc_cb = NULL;
-  link->read_cb = NULL;
-  link->methods = NULL;
+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;
+
+  memset(link, 0, sizeof(*link));
+
+  if (target == NULL)
+    cb(source);
+  else
+    uv_link_propagate_close(target, source, cb);
+}
+
+
+void uv_link_propagate_close(uv_link_t* link, uv_link_t* source,
+                             uv_link_close_cb cb) {
+  CHECK_EQ(link->child, NULL, "uv_link_t: attempt to close chained link");
+  uv_link_methods_t const* methods;
+
+  methods = link->methods;
+
+  if (link->parent != NULL)
+    CHECK_EQ(uv_link_unchain(link->parent, link), 0, "uv_link_unchain()");
+
+  link->saved_close_source = source;
+  link->saved_close_cb = cb;
+
+  methods->close(link, link, uv_link_close_parent);
 }