about summary refs log tree commit diff stats
path: root/src/uv_link_t.c
diff options
context:
space:
mode:
authorFedor Indutny <fedor@indutny.com>2016-06-04 14:37:26 -0400
committerFedor Indutny <fedor@indutny.com>2016-06-04 15:44:18 -0400
commitaf170cc9bbfbed228c386b64c1bb945ab4a502ed (patch)
tree901e5758c4ff05f72826c7e616591c7a548690e8 /src/uv_link_t.c
parenta66bb042e02bd1021a574c32a27fff087ab1c9f4 (diff)
downloaduv_link_t-af170cc9bbfbed228c386b64c1bb945ab4a502ed.tar.gz
api: experimental error reporting
Diffstat (limited to 'src/uv_link_t.c')
-rw-r--r--src/uv_link_t.c65
1 files changed, 59 insertions, 6 deletions
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)