diff options
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | docs/api.md | 24 | ||||
-rw-r--r-- | docs/implementation-guide.md | 4 | ||||
-rw-r--r-- | include/uv_link_t.h | 8 | ||||
-rw-r--r-- | src/defaults.c | 5 | ||||
-rw-r--r-- | src/uv_link_t.c | 65 | ||||
-rw-r--r-- | test/src/test-list.h | 1 | ||||
-rw-r--r-- | test/src/test-strerror.c | 73 | ||||
-rw-r--r-- | test/test.gyp | 1 |
9 files changed, 175 insertions, 11 deletions
diff --git a/README.md b/README.md index 31952b9..a8287c6 100644 --- a/README.md +++ b/README.md @@ -80,11 +80,6 @@ static int shutdown_impl(uv_link_t* link, [API Docs][2] [Implementation Guide][3] -## Further Work - -* Error reporting. Right now all we get is a UV_... error, it would be nice to - have a method for obtaining string description. - ## LICENSE This software is licensed under the MIT License. diff --git a/docs/api.md b/docs/api.md index 2d2877b..0d7e634 100644 --- a/docs/api.md +++ b/docs/api.md @@ -118,6 +118,16 @@ Invoke `shutdown` from the link's [`uv_link_methods_t`][]. Acts similarly to `uv_shutdown()`. `cb(uv_link_t* link, int status, void* arg)` is invoked on completion. +### const char* uv_link_strerror(...) + +* `uv_link_t* link` +* `int err` - error code, previously either returned the one of the + `uv_link...` methods or passed as a negative `nread` to `link->read_cb` + +Invoke `strerror` from the link's [`uv_link_methods_t`][]. Acts similarly to +`uv_strerror()`. Returns a description of error code that has just been given +back to the user. + ### void uv_link_propagate_alloc_cb(...) Should be used only by [`uv_link_methods_t`][] implementation. @@ -291,6 +301,7 @@ int uv_link_default_shutdown(uv_link_t* link, void* arg); void uv_link_default_close(uv_link_t* link, uv_link_t* source, uv_link_close_cb cb); +const char* uv_link_default_strerror(uv_link_t* link, int err); ``` These maybe used for [`uv_methods_talloc_cb_override`][] and @@ -385,6 +396,18 @@ is passed only only for internal operation. *NOTE: semantics are the same as of `uv_close`.* +### .strerror + +```c +const char* (*strerror)(uv_link_t* link, int err); +``` + +Invoked by [`uv_link_strerror()`][]. + +Should return a description string of the `err` that was emitted by the `link`. + +*NOTE: semantics are the same as of `uv_strerror`.* + ### .alloc_cb_override A method used to override that value of [`uv_link_t.alloc_cb`][] by @@ -468,6 +491,7 @@ Invoked by `uv_link_propagate_read_cb`. MUST not manage the data in `buf`. [`uv_link_chain()`]: #int-uv_link_chain [`uv_link_close()`]: #void-uv_link_close +[`uv_link_strerror()`]: #const-char-uv_link_strerror [`uv_link_init()`]: #int-uv_link_init [`uv_link_methods_t`]: #uv_link_methods_t [`uv_link_observer_t.observer_read_cb`]: #observer_read_cb diff --git a/docs/implementation-guide.md b/docs/implementation-guide.md index 9393bdc..65fb8fe 100644 --- a/docs/implementation-guide.md +++ b/docs/implementation-guide.md @@ -3,6 +3,10 @@ `uv_link_t` behaves very similar to [`uv_stream_t`][0]. All `uv_link_methods_t` MUST conform to this semantics. +## Error Codes + +All error codes MUST be negative and be less than `UV_ERRNO_MAX`. + ## uv_link_init() Links start in non-reading mode, `alloc_cb`/`read_cb` MUST NOT be called until diff --git a/include/uv_link_t.h b/include/uv_link_t.h index 61d4cf0..2f09d36 100644 --- a/include/uv_link_t.h +++ b/include/uv_link_t.h @@ -40,6 +40,8 @@ struct uv_link_methods_s { void (*close)(uv_link_t* link, uv_link_t* source, uv_link_close_cb cb); + const char* (*strerror)(uv_link_t* link, int err); + /* Overriding callbacks */ uv_link_alloc_cb alloc_cb_override; uv_link_read_cb read_cb_override; @@ -63,6 +65,9 @@ struct uv_link_methods_s { uv_link_alloc_cb saved_alloc_cb; \ uv_link_read_cb saved_read_cb; \ \ + /* Private, used for error reporting */ \ + unsigned int err_prefix; \ + \ /* Private, used for close */ \ int close_depth; \ int close_waiting; \ @@ -120,6 +125,8 @@ static int uv_link_shutdown(uv_link_t* link, uv_link_shutdown_cb cb, return uv_link_propagate_shutdown(link, link, cb, arg); } +const char* uv_link_strerror(uv_link_t* link, int err); + /* Link Source */ struct uv_link_source_s { @@ -170,6 +177,7 @@ int uv_link_default_shutdown(uv_link_t* link, void* arg); void uv_link_default_close(uv_link_t* link, uv_link_t* source, uv_link_close_cb cb); +const char* uv_link_default_strerror(uv_link_t* link, int err); void uv_link_default_alloc_cb_override(uv_link_t* link, size_t suggested_size, diff --git a/src/defaults.c b/src/defaults.c index 1c486f8..5df3862 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -43,6 +43,11 @@ void uv_link_default_close(uv_link_t* link, uv_link_t* source, } +const char* uv_link_default_strerror(uv_link_t* link, int err) { + return NULL; +} + + void uv_link_default_alloc_cb_override(uv_link_t* link, size_t suggested_size, uv_buf_t* buf) { diff --git a/src/uv_link_t.c b/src/uv_link_t.c index f83a8a6..3df5264 100644 --- a/src/uv_link_t.c +++ b/src/uv_link_t.c @@ -3,8 +3,27 @@ #include "src/common.h" +static const size_t kErrorPrefixShift = 16; +static const int kErrorValueMask = (1 << kErrorPrefixShift) - 1; +static const unsigned int kErrorPrefixMask = ~kErrorValueMask; + static void uv_link_maybe_close(uv_link_t* link); + +static int uv_link_error(uv_link_t* link, int err) { + if (link == NULL) + return err; + + if (err >= UV_ERRNO_MAX) + return err; + + if (((-err) & kErrorPrefixMask) != 0) + return err; + + return -((-err) | link->err_prefix); +} + + static void uv_link_def_alloc_cb(uv_link_t* link, size_t suggested_size, uv_buf_t* buf) { @@ -32,6 +51,7 @@ int uv_link_init(uv_link_t* link, uv_link_methods_t const* methods) { link->alloc_cb = uv_link_def_alloc_cb; link->read_cb = uv_link_def_read_cb; + link->err_prefix = 1 << kErrorPrefixShift; link->methods = methods; @@ -46,7 +66,7 @@ int uv_link_init(uv_link_t* link, uv_link_methods_t const* methods) { err = (RES); \ if (--link->close_depth == 0) \ uv_link_maybe_close(link); \ - return err; \ + return uv_link_error(link, err); \ } while (0) @@ -55,7 +75,7 @@ int uv_link_propagate_write(uv_link_t* link, uv_link_t* source, uv_stream_t* send_handle, uv_link_write_cb cb, void* arg) { if (link == NULL) - return UV_EFAULT; + return uv_link_error(link, UV_EFAULT); CLOSE_WRAP(link->methods->write(link, source, bufs, nbufs, send_handle, cb, arg)); } @@ -66,21 +86,21 @@ int uv_link_propagate_shutdown(uv_link_t* link, uv_link_shutdown_cb cb, void* arg) { if (link == NULL) - return UV_EFAULT; + return uv_link_error(link, UV_EFAULT); CLOSE_WRAP(link->methods->shutdown(link, source, cb, arg)); } int uv_link_read_start(uv_link_t* link) { if (link == NULL) - return UV_EFAULT; + return uv_link_error(link, UV_EFAULT); CLOSE_WRAP(link->methods->read_start(link)); } int uv_link_read_stop(uv_link_t* link) { if (link == NULL) - return UV_EFAULT; + return uv_link_error(link, UV_EFAULT); CLOSE_WRAP(link->methods->read_stop(link)); } @@ -89,7 +109,7 @@ int uv_link_try_write(uv_link_t* link, const uv_buf_t bufs[], unsigned int nbufs) { if (link == NULL) - return UV_EFAULT; + return uv_link_error(link, UV_EFAULT); CLOSE_WRAP(link->methods->try_write(link, bufs, nbufs)); } @@ -154,6 +174,15 @@ void uv_link_propagate_close(uv_link_t* link, uv_link_t* source, } +static void uv_link_recalculate_prefixes(uv_link_t* link) { + unsigned short prev; + + prev = link->parent->err_prefix >> kErrorPrefixShift; + for (; link != NULL; link = link->child) + link->err_prefix = (++prev) << kErrorPrefixShift; +} + + int uv_link_chain(uv_link_t* from, uv_link_t* to) { if (from->child != NULL || to->parent != NULL) return UV_EINVAL; @@ -170,6 +199,8 @@ int uv_link_chain(uv_link_t* from, uv_link_t* to) { from->alloc_cb = to->methods->alloc_cb_override; from->read_cb = to->methods->read_cb_override; + uv_link_recalculate_prefixes(to); + return 0; } @@ -190,6 +221,24 @@ int uv_link_unchain(uv_link_t* from, uv_link_t* to) { } +const char* uv_link_strerror(uv_link_t* link, int err) { + unsigned int prefix; + int local_err; + + if (err >= UV_ERRNO_MAX) + return uv_strerror(err); + + prefix = (-err) & kErrorPrefixMask; + local_err = -((-err) & kErrorValueMask); + + for (; link != NULL; link = link->parent) + if (prefix == link->err_prefix) + return link->methods->strerror(link, local_err); + + return NULL; +} + + void uv_link_propagate_alloc_cb(uv_link_t* link, size_t suggested_size, uv_buf_t* buf) { @@ -215,6 +264,10 @@ void uv_link_propagate_read_cb(uv_link_t* link, if (link->child != NULL) target = link->child; + /* Prefix errors */ + if (nread < 0) + nread = uv_link_error(link, nread); + target->close_depth++; link->read_cb(target, nread, buf); if (--target->close_depth == 0) diff --git a/test/src/test-list.h b/test/src/test-list.h index 591b858..abb7cda 100644 --- a/test/src/test-list.h +++ b/test/src/test-list.h @@ -6,6 +6,7 @@ V(uv_link_observer_t) \ V(close_depth) \ V(stop_read_on_error) \ + V(strerror) \ #define TEST_DECL(N) void test__##N(); diff --git a/test/src/test-strerror.c b/test/src/test-strerror.c new file mode 100644 index 0000000..d2e307c --- /dev/null +++ b/test/src/test-strerror.c @@ -0,0 +1,73 @@ +#include <sys/socket.h> +#include <unistd.h> + +#include "test-common.h" + +static uv_link_t a_link; +static uv_link_t b_link; + +static int close_cb_called; + + +static int faulty_try_write(uv_link_t* link, + const uv_buf_t bufs[], + unsigned int nbufs) { + return UV_ERRNO_MAX - 1; +} + + +const char* a_strerror(uv_link_t* l, int err) { + CHECK_EQ(l, &a_link, "link == a_link"); + return "a"; +} + + +const char* b_strerror(uv_link_t* l, int err) { + CHECK_EQ(l, &b_link, "link == b_link"); + return "b"; +} + + +static uv_link_methods_t a_methods = { + .try_write = faulty_try_write, + .strerror = a_strerror, + .close = uv_link_default_close +}; + + +static uv_link_methods_t b_methods = { + .try_write = faulty_try_write, + .strerror = b_strerror, + .close = uv_link_default_close, + + .alloc_cb_override = uv_link_default_alloc_cb_override, + .read_cb_override = uv_link_default_read_cb_override +}; + + +static void close_cb(uv_link_t* l) { + close_cb_called++; +} + + +TEST_IMPL(strerror) { + int err; + + CHECK_EQ(uv_link_init(&a_link, &a_methods), 0, "uv_link_init()"); + CHECK_EQ(uv_link_init(&b_link, &b_methods), 0, "uv_link_init()"); + CHECK_EQ(uv_link_chain(&a_link, &b_link), 0, "uv_link_chain()"); + + CHECK_EQ(uv_link_strerror(&b_link, UV_ERRNO_MAX - 1), NULL, + "unprefixed error should not be found"); + + err = uv_link_try_write(&b_link, NULL, 0); + CHECK_EQ(strcmp(uv_link_strerror(&b_link, err), "b"), 0, + "error description should match"); + + err = uv_link_try_write(&a_link, NULL, 0); + CHECK_EQ(strcmp(uv_link_strerror(&b_link, err), "a"), 0, + "error description should match"); + + uv_link_close(&b_link, close_cb); + CHECK_EQ(close_cb_called, 1, "close_cb must be called"); +} diff --git a/test/test.gyp b/test/test.gyp index 0bd930d..131b93a 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -18,6 +18,7 @@ "src/test-uv-link-observer-t.c", "src/test-defaults.c", "src/test-close.c", + "src/test-strerror.c", ], }], } |