Hello.

After some tests I've found that write callback is really not called when data 
being read consists of all zeros.
The full test case:

*** Source code:
-------------------------------------------------------------------------------
#include <uv.h>
#include <stdlib.h>
#include <stdio.h>


#define PRINT_UV_ERR(prefix, code)  do {\
    fflush(stdout);\
    fprintf(stderr, "%s: %s (%i): %s\n", prefix, uv_err_name(code), 
(int)(code), uv_strerror(code));\
    fflush(stderr);\
} while (0)


/* assuming that stdin and stdout can be handled with as pipes */
uv_pipe_t in, out;


void alloc_cb(uv_handle_t*, size_t, uv_buf_t*);
void read_cb(uv_stream_t*, ssize_t, const uv_buf_t*);
void write_cb(uv_write_t*, int);


int main(int _argc, char *_argv[])
{
  int ret = 0;

  uv_loop_t *loop = uv_default_loop();

  uv_pipe_init(loop, &in, 0);
  ret = uv_pipe_open(&in, fileno(stdin));
  if (ret < 0)
  {
    PRINT_UV_ERR("stdin open", ret);
    return ret;
  };

  uv_pipe_init(loop, &out, 0);
  ret = uv_pipe_open(&out, fileno(stdout));
  if (ret < 0)
  {
    PRINT_UV_ERR("stdout open", ret);
    return ret;
  };

  uv_read_start((uv_stream_t*)&in, alloc_cb, read_cb);

  return uv_run(loop, UV_RUN_DEFAULT);
}



void alloc_cb(uv_handle_t *_handle, size_t _suggested_size, uv_buf_t *_buf)
{
  /* allocate the memory for a new I/O buffer */
  *_buf = uv_buf_init((char*)malloc(_suggested_size), _suggested_size);
#ifndef NDEBUG
  fprintf(stderr, "[%p] create: I/O buffer\n", _buf->base);  fflush(stderr);
#endif
}


void read_cb(uv_stream_t *_stream, ssize_t _nread, const uv_buf_t *_buf)
{
  if (_nread < 0)
  {
    PRINT_UV_ERR("read", _nread);
    uv_read_stop(_stream);
  }
  else if (_nread > 0)
  {
    /* initialize a new buffer descriptor specifying the actual data length */
    uv_buf_t buf = uv_buf_init(_buf->base, _nread);

    /* create a write request descriptor */
    uv_write_t *wr = (uv_write_t*)malloc(sizeof(uv_write_t));
#ifndef NDEBUG
    fprintf(stderr, "[%p] create: write request\n", (void*)wr);  fflush(stderr);
#endif

    /* save a reference to the output buffer somehow along with the write 
request */
    wr->data = _buf->base;
#ifndef NDEBUG
    fprintf(stderr, "[%p] address: I/O buffer\n", wr->data);  fflush(stderr);
#endif

    /* fire up the write request */
    uv_write(wr, (uv_stream_t*)&out, &buf, 1, write_cb);

    /* the I/O buffer being used up should be deleted somewhere */
  }
}


void write_cb(uv_write_t *_wr, int _status)
{
  if (_status < 0)
  {
    PRINT_UV_ERR("write", _status);
    uv_read_stop((uv_stream_t*)&in);
  };

  /* when the write request has completed it's safe to free up the memory 
allocated for the I/O buffer */
  free(_wr->data);
#ifndef NDEBUG
  fprintf(stderr, "[%p] free: I/O buffer\n", _wr->data);  fflush(stderr);
#endif

  /* delete the write request descriptor */
  free(_wr);
#ifndef NDEBUG
  fprintf(stderr, "[%p] free: write request\n", (void*)_wr);  fflush(stderr);
#endif
}
-------------------------------------------------------------------------------

*** Build command:
$ gcc -std=c99 -Wall -Wpedantic -O0 -g -pipe -D _DEFAULT_SOURCE   cpio-uv.c  
-lpthread -luv -o cpio-uv


*** Run test 1.
Note than there are no any message about memory freeing up:
-------------------------------------------------------------------------------
$ cat /dev/zero | ./cpio-uv | dd of=/dev/null iflag=fullblock bs=1M count=1

[0x16a30a0] create: I/O buffer
[0x16b30b0] create: write request
[0x16a30a0] address: I/O buffer
[0x16b3180] create: I/O buffer
[0x16c3190] create: write request
[0x16b3180] address: I/O buffer
[0x16c3260] create: I/O buffer
[0x16d3270] create: write request
[0x16c3260] address: I/O buffer
[0x16d3340] create: I/O buffer
[0x16e3350] create: write request
[0x16d3340] address: I/O buffer
[0x16e3420] create: I/O buffer
[0x16f3430] create: write request
[0x16e3420] address: I/O buffer
[0x16f3500] create: I/O buffer
[0x1703510] create: write request
[0x16f3500] address: I/O buffer
[0x17035e0] create: I/O buffer
[0x17135f0] create: write request
[0x17035e0] address: I/O buffer
[0x17136c0] create: I/O buffer
[0x17236d0] create: write request
[0x17136c0] address: I/O buffer
[0x17237a0] create: I/O buffer
[0x17337b0] create: write request
[0x17237a0] address: I/O buffer
[0x1733880] create: I/O buffer
[0x1743890] create: write request
[0x1733880] address: I/O buffer
[0x1743960] create: I/O buffer
[0x1753970] create: write request
[0x1743960] address: I/O buffer
[0x1753a40] create: I/O buffer
[0x1763a50] create: write request
[0x1753a40] address: I/O buffer
[0x1763b20] create: I/O buffer
[0x1773b30] create: write request
[0x1763b20] address: I/O buffer
[0x1773c00] create: I/O buffer
[0x1783c10] create: write request
[0x1773c00] address: I/O buffer
[0x1783ce0] create: I/O buffer
[0x1793cf0] create: write request
[0x1783ce0] address: I/O buffer
[0x1793dc0] create: I/O buffer
[0x17a3dd0] create: write request
[0x1793dc0] address: I/O buffer
[0x17a3ea0] create: I/O buffer
[0x17b3eb0] create: write request
[0x17a3ea0] address: I/O buffer
1+0 records in
1+0 records out
1048576 bytes (1.0 MB) copied, 0.00597094 s, 176 MB/s
-------------------------------------------------------------------------------


*** Run test 2.
Note that there are messages about freeing up the I/O buffers and request 
descriptors.
As a result, no memory leaking is observed with this run.
-------------------------------------------------------------------------------
$ cat /dev/urandom | ./cpio-uv | dd of=/dev/null iflag=fullblock bs=1M count=1

[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x20c6260] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x20d6270] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x20e6280] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x20f6290] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x21062a0] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x21162b0] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x21262c0] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
[0x20b6180] create: I/O buffer
[0x20c6190] create: write request
[0x20b6180] address: I/O buffer
[0x21362d0] create: I/O buffer
[0x20a60a0] free: I/O buffer
[0x20b60b0] free: write request
[0x20b6180] free: I/O buffer
[0x20c6190] free: write request
1+0 records in
1+0 records out
1048576 bytes (1.0 MB) copied, 0.124255 s, 8.4 MB/s
[0x20a60a0] create: I/O buffer
[0x20b60b0] create: write request
[0x20a60a0] address: I/O buffer
-------------------------------------------------------------------------------

Also note that even though write_cb() is attempting to print error messages on 
every fault, there are no any such messages.

For being more careful I have then added EPIPE signal blocking at the start of 
the main() function:

#ifndef _WIN32
  sigset_t set;
  sigemptyset(&set);
  sigaddset(&set, SIGPIPE);
  ret = sigprocmask(SIG_BLOCK, &set, NULL);
  if (ret != 0)
  {
    perror("sigprocmask");
    return ret;
  };
#endif

But this does not alter the overall behavior of the program - even though the 
write callback now prints
a set of "write: EPIPE (-32): broken pipe" messages and frees up I/O buffer and 
write request descriptor resources
along with every such a message, the issue persists - when data being read 
consists of all zeros the memory used
by the program starts constantly growing rather quickly until it ends.


Thanks.

--
Mike

-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/d/optout.

Reply via email to