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.