diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | include/uv_link_t.h | 21 | ||||
-rw-r--r-- | src/uv_link_observer_t.c | 34 | ||||
-rw-r--r-- | src/uv_link_source_t.c | 33 | ||||
-rw-r--r-- | src/uv_link_t.c | 36 | ||||
-rw-r--r-- | test/src/test-uv-link-observer-t.c | 30 | ||||
-rw-r--r-- | test/src/test-uv-link-source-t.c | 13 |
7 files changed, 132 insertions, 36 deletions
diff --git a/README.md b/README.md index 2003bff..981bbe0 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ static uv_link_methods_t methods = { .write = write_impl, .try_write = try_write_impl, .shutdown = shutdown_impl, + .close = close_impl, /* These will be used only when chaining two links together */ diff --git a/include/uv_link_t.h b/include/uv_link_t.h index 25c229a..68b66c1 100644 --- a/include/uv_link_t.h +++ b/include/uv_link_t.h @@ -16,6 +16,7 @@ typedef void (*uv_link_read_cb)(uv_link_t* link, const uv_buf_t* buf); typedef void (*uv_link_write_cb)(uv_link_t* source, int status, void* arg); typedef void (*uv_link_shutdown_cb)(uv_link_t* source, int status, void* arg); +typedef void (*uv_link_close_cb)(uv_link_t* source); struct uv_link_methods_s { int (*read_start)(uv_link_t* link); @@ -37,6 +38,8 @@ struct uv_link_methods_s { uv_link_shutdown_cb cb, void* arg); + void (*close)(uv_link_t* link, uv_link_t* source, uv_link_close_cb cb); + /* Overriding callbacks */ uv_link_alloc_cb alloc_cb_override; uv_link_read_cb read_cb_override; @@ -59,10 +62,14 @@ struct uv_link_s { /* Private, used for chain/unchain */ uv_link_alloc_cb saved_alloc_cb; uv_link_read_cb saved_read_cb; + + /* Private, used for close */ + uv_link_t* saved_close_source; + uv_link_close_cb saved_close_cb; }; UV_EXTERN int uv_link_init(uv_link_t* link, uv_link_methods_t const* methods); -UV_EXTERN void uv_link_close(uv_link_t* link); +static void uv_link_close(uv_link_t* link, uv_link_close_cb cb); UV_EXTERN int uv_link_chain(uv_link_t* from, uv_link_t* to); UV_EXTERN int uv_link_unchain(uv_link_t* from, uv_link_t* to); @@ -89,8 +96,15 @@ static int uv_link_propagate_shutdown(uv_link_t* link, return link->methods->shutdown(link, source, cb, arg); } +void uv_link_propagate_close(uv_link_t* link, uv_link_t* source, + uv_link_close_cb cb); + /* Use this to invoke methods of `link` */ +void uv_link_close(uv_link_t* link, uv_link_close_cb cb) { + return uv_link_propagate_close(link, link, cb); +} + static int uv_link_read_start(uv_link_t* link) { return link->methods->read_start(link); } @@ -122,12 +136,14 @@ struct uv_link_source_s { uv_link_t link; uv_stream_t* stream; + + uv_link_close_cb close_cb; + uv_link_t* close_source; }; /* NOTE: uses `stream->data` field */ UV_EXTERN int uv_link_source_init(uv_link_source_t* source, uv_stream_t* stream); -UV_EXTERN void uv_link_source_close(uv_link_source_t* source); /* Link Observer */ @@ -143,6 +159,5 @@ struct uv_link_observer_s { UV_EXTERN int uv_link_observer_init(uv_link_observer_t* observer, uv_link_t* target); -UV_EXTERN int uv_link_observer_close(uv_link_observer_t* observer); #endif /* INCLUDE_UV_LINK_H_ */ 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); } diff --git a/test/src/test-uv-link-observer-t.c b/test/src/test-uv-link-observer-t.c index eaba1ab..3c48908 100644 --- a/test/src/test-uv-link-observer-t.c +++ b/test/src/test-uv-link-observer-t.c @@ -7,9 +7,25 @@ static uv_link_t source; static uv_link_observer_t observer; static int observer_read_cb_called; +static int fake_close_called; +static int close_cb_called; + +static void fake_close(uv_link_t* link, + uv_link_t* src, + uv_link_close_cb cb) { + CHECK_EQ(link, &source, "fake_close link"); + /* NOTE: `src` may not be a proper source here */ + + fake_close_called++; + + /* Not 100% correct, since it is sync, but works here */ + cb(src); +} static uv_link_methods_t methods = { - /* no-op, won't be called */ + .close = fake_close + + /* rest are no-op, won't be called */ }; static void observer_read_cb(uv_link_observer_t* o, @@ -23,6 +39,13 @@ static void observer_read_cb(uv_link_observer_t* o, } +static void close_cb(uv_link_t* link) { + CHECK_EQ(link, &observer.link, "close_cb link"); + + close_cb_called++; +} + + TEST_IMPL(uv_link_observer_t) { uv_buf_t buf; @@ -39,6 +62,7 @@ TEST_IMPL(uv_link_observer_t) { uv_link_propagate_read_cb(&source, 1, &buf); CHECK_EQ(observer_read_cb_called, 1, "observer.read_cb must be called"); - CHECK_EQ(uv_link_observer_close(&observer), 0, "uv_link_observer_close"); - uv_link_close(&source); + uv_link_close(&observer.link, close_cb); + CHECK_EQ(fake_close_called, 1, "fake close count"); + CHECK_EQ(close_cb_called, 1, "close_cb count"); } diff --git a/test/src/test-uv-link-source-t.c b/test/src/test-uv-link-source-t.c index ba445a7..1d12ac0 100644 --- a/test/src/test-uv-link-source-t.c +++ b/test/src/test-uv-link-source-t.c @@ -12,6 +12,7 @@ static int test_arg; static int write_cb_called; static int alloc_cb_called; static int read_cb_called; +static int close_cb_called; static void read_one() { char buf[1024]; @@ -103,6 +104,12 @@ static void test_reads() { } +static void close_cb(uv_link_t* link) { + CHECK_EQ(link, &source.link, "close_cb link"); + close_cb_called++; +} + + TEST_IMPL(uv_link_source_t) { CHECK_NE(loop = uv_default_loop(), NULL, "uv_default_loop()"); @@ -117,8 +124,10 @@ TEST_IMPL(uv_link_source_t) { test_writes(); test_reads(); - uv_link_source_close(&source); - uv_close((uv_handle_t*) &pair_right, NULL); + uv_link_close(&source.link, close_cb); + CHECK_EQ(uv_run(loop, UV_RUN_DEFAULT), 0, "uv_run()"); + CHECK_EQ(close_cb_called, 1, "close_cb count"); CHECK_EQ(close(fds[0]), 0, "close(fds[0])"); + CHECK_NE(close(fds[1]), 0, "close(fds[1]) must fail"); } |