api: experimental error reporting

This commit is contained in:
Fedor Indutny 2016-06-04 14:37:26 -04:00
parent a66bb042e0
commit af170cc9bb
9 changed files with 175 additions and 11 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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) {

View File

@ -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)

View File

@ -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();

73
test/src/test-strerror.c Normal file
View File

@ -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");
}

View File

@ -18,6 +18,7 @@
"src/test-uv-link-observer-t.c",
"src/test-defaults.c",
"src/test-close.c",
"src/test-strerror.c",
],
}],
}