void uv__stream_io(EV_P_ ev_io* watcher, int revents) { uv_stream_t* stream = watcher->data; assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); assert(watcher == &stream->read_watcher || watcher == &stream->write_watcher); assert(!(stream->flags & UV_CLOSING)); if (stream->connect_req) { uv__stream_connect(stream); } else { assert(revents & (EV_READ | EV_WRITE)); assert(stream->fd >= 0); if (revents & EV_READ) { uv__read((uv_stream_t*)stream); } if (revents & EV_WRITE) { uv__write(stream); uv__write_callbacks(stream); } } }
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv_stream_t* stream; stream = container_of(w, uv_stream_t, io_watcher); assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); assert(!(stream->flags & UV_CLOSING)); if (stream->connect_req) { uv__stream_connect(stream); return; } if (events & UV__POLLIN) { assert(uv__stream_fd(stream) >= 0); uv__read(stream); if (uv__stream_fd(stream) == -1) return; /* read_cb closed stream. */ } if (events & UV__POLLOUT) { assert(uv__stream_fd(stream) >= 0); uv__write(stream); uv__write_callbacks(stream); } }
void uv__tcp_io(EV_P_ ev_io* watcher, int revents) { uv_tcp_t* tcp = watcher->data; assert(tcp->type == UV_TCP); assert(watcher == &tcp->read_watcher || watcher == &tcp->write_watcher); assert(tcp->fd >= 0); assert(!uv_flag_is_set((uv_handle_t*)tcp, UV_CLOSING)); if (tcp->connect_req) { uv__tcp_connect(tcp); } else { if (revents & EV_READ) { uv__read(tcp); } if (revents & EV_WRITE) { uv_write_t* req = uv__write(tcp); if (req) { /* Error. Notify the user. */ if (req->cb) { req->cb(req, -1); } } else { uv__write_callbacks(tcp); } } } }
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, int events) { uv_stream_t* stream; /* either UV__IO_READ or UV__IO_WRITE but not both */ assert(!!(events & UV__IO_READ) ^ !!(events & UV__IO_WRITE)); if (events & UV__IO_READ) stream = container_of(w, uv_stream_t, read_watcher); else stream = container_of(w, uv_stream_t, write_watcher); assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); assert(!(stream->flags & UV_CLOSING)); if (stream->connect_req) uv__stream_connect(stream); else if (events & UV__IO_READ) { assert(stream->fd >= 0); uv__read(stream); } else { assert(stream->fd >= 0); uv__write(stream); uv__write_callbacks(stream); } }
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv_stream_t* stream; stream = container_of(w, uv_stream_t, io_watcher); assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); assert(!(stream->flags & UV_CLOSING)); if (stream->connect_req) { uv__stream_connect(stream); return; } assert(uv__stream_fd(stream) >= 0); /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP)) uv__read(stream); if (uv__stream_fd(stream) == -1) return; /* read_cb closed stream. */ /* Short-circuit iff POLLHUP is set, the user is still interested in read * events and uv__read() reported a partial read but not EOF. If the EOF * flag is set, uv__read() called read_cb with err=UV_EOF and we don't * have to do anything. If the partial read flag is not set, we can't * report the EOF yet because there is still data to read. */ if ((events & UV__POLLHUP) && (stream->flags & UV_STREAM_READING) && (stream->flags & UV_STREAM_READ_PARTIAL) && !(stream->flags & UV_STREAM_READ_EOF)) { uv_buf_t buf = { NULL, 0 }; uv__stream_eof(stream, &buf); } if (uv__stream_fd(stream) == -1) return; /* read_cb closed stream. */ if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { uv__write(stream); uv__write_callbacks(stream); /* Write queue drained. */ if (QUEUE_EMPTY(&stream->write_queue)) uv__drain(stream); } }
void uv__tcp_io(EV_P_ ev_io* watcher, int revents) { uv_handle_t* handle = watcher->data; assert(watcher == &handle->read_watcher || watcher == &handle->write_watcher); assert(handle->fd >= 0); assert(!uv_flag_is_set(handle, UV_CLOSING)); if (handle->connect_req) { uv__tcp_connect(handle); } else { if (revents & EV_READ) { uv__read(handle); } if (revents & EV_WRITE) { uv__write(handle); } } }
int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt, uv_stream_t* send_handle, uv_write_cb cb) { int empty_queue; assert(bufcnt > 0); assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY) && "uv_write (unix) does not yet support other types of streams"); if (uv__stream_fd(stream) < 0) { uv__set_sys_error(stream->loop, EBADF); return -1; } if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) { uv__set_sys_error(stream->loop, EOPNOTSUPP); return -1; } } empty_queue = (stream->write_queue_size == 0); /* Initialize the req */ uv__req_init(stream->loop, req, UV_WRITE); req->cb = cb; req->handle = stream; req->error = 0; req->send_handle = send_handle; ngx_queue_init(&req->queue); if (bufcnt <= (int) ARRAY_SIZE(req->bufsml)) req->bufs = req->bufsml; else req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t)); req->bufcnt = bufcnt; req->write_index = 0; stream->write_queue_size += uv__buf_count(bufs, bufcnt); /* Append the request to write_queue. */ ngx_queue_insert_tail(&stream->write_queue, &req->queue); /* If the queue was empty when this function began, we should attempt to * do the write immediately. Otherwise start the write_watcher and wait * for the fd to become writable. */ if (stream->connect_req) { /* Still connecting, do nothing. */ } else if (empty_queue) { uv__write(stream); } else { /* * blocking streams should never have anything in the queue. * if this assert fires then somehow the blocking stream isn't being * sufficiently flushed in uv__write. */ assert(!(stream->flags & UV_STREAM_BLOCKING)); uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); } return 0; }
int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt, uv_stream_t* send_handle, uv_write_cb cb) { int empty_queue; assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY) && "uv_write (unix) does not yet support other types of streams"); if (stream->fd < 0) { uv__set_sys_error(stream->loop, EBADF); return -1; } if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) { uv__set_sys_error(stream->loop, EOPNOTSUPP); return -1; } } empty_queue = (stream->write_queue_size == 0); /* Initialize the req */ uv__req_init(stream->loop, (uv_req_t*)req); req->cb = cb; req->handle = stream; req->error = 0; req->send_handle = send_handle; req->type = UV_WRITE; ngx_queue_init(&req->queue); if (bufcnt <= UV_REQ_BUFSML_SIZE) { req->bufs = req->bufsml; } else { req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); } memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t)); req->bufcnt = bufcnt; /* * fprintf(stderr, "cnt: %d bufs: %p bufsml: %p\n", bufcnt, req->bufs, req->bufsml); */ req->write_index = 0; stream->write_queue_size += uv__buf_count(bufs, bufcnt); /* Append the request to write_queue. */ ngx_queue_insert_tail(&stream->write_queue, &req->queue); assert(!ngx_queue_empty(&stream->write_queue)); assert(stream->write_watcher.cb == uv__stream_io); assert(stream->write_watcher.data == stream); assert(stream->write_watcher.fd == stream->fd); /* If the queue was empty when this function began, we should attempt to * do the write immediately. Otherwise start the write_watcher and wait * for the fd to become writable. */ if (empty_queue) { uv__write(stream); } else { /* * blocking streams should never have anything in the queue. * if this assert fires then somehow the blocking stream isn't being * sufficently flushed in uv__write. */ assert(!stream->blocking); ev_io_start(stream->loop->ev, &stream->write_watcher); } return 0; }
/* The buffers to be written must remain valid until the callback is called. * This is not required for the uv_buf_t array. */ int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt, uv_write_cb cb) { int empty_queue; uv_tcp_t* tcp = (uv_tcp_t*)handle; /* Initialize the req */ uv__req_init((uv_req_t*) req); req->cb = cb; req->handle = handle; ngx_queue_init(&req->queue); assert(handle->type == UV_TCP && "uv_write (unix) does not yet support other types of streams"); empty_queue = (tcp->write_queue_size == 0); assert(tcp->fd >= 0); ngx_queue_init(&req->queue); req->type = UV_WRITE; if (bufcnt < UV_REQ_BUFSML_SIZE) { req->bufs = req->bufsml; } else { req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); } memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t)); req->bufcnt = bufcnt; /* * fprintf(stderr, "cnt: %d bufs: %p bufsml: %p\n", bufcnt, req->bufs, req->bufsml); */ req->write_index = 0; tcp->write_queue_size += uv__buf_count(bufs, bufcnt); /* Append the request to write_queue. */ ngx_queue_insert_tail(&tcp->write_queue, &req->queue); assert(!ngx_queue_empty(&tcp->write_queue)); assert(tcp->write_watcher.cb == uv__tcp_io); assert(tcp->write_watcher.data == tcp); assert(tcp->write_watcher.fd == tcp->fd); /* If the queue was empty when this function began, we should attempt to * do the write immediately. Otherwise start the write_watcher and wait * for the fd to become writable. */ if (empty_queue) { if (uv__write(tcp)) { /* Error. uv_last_error has been set. */ return -1; } } /* If the queue is now empty - we've flushed the request already. That * means we need to make the callback. The callback can only be done on a * fresh stack so we feed the event loop in order to service it. */ if (ngx_queue_empty(&tcp->write_queue)) { ev_feed_event(EV_DEFAULT_ &tcp->write_watcher, EV_WRITE); } else { /* Otherwise there is data to write - so we should wait for the file * descriptor to become writable. */ ev_io_start(EV_DEFAULT_ &tcp->write_watcher); } return 0; }
int uv_write2(uv_write_t* req, uv_stream_t* stream, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb) { int empty_queue; assert(nbufs > 0); assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY) && "uv_write (unix) does not yet support other types of streams"); if (uv__stream_fd(stream) < 0) return -EBADF; if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) return -EINVAL; /* XXX We abuse uv_write2() to send over UDP handles to child processes. * Don't call uv__stream_fd() on those handles, it's a macro that on OS X * evaluates to a function that operates on a uv_stream_t with a couple of * OS X specific fields. On other Unices it does (handle)->io_watcher.fd, * which works but only by accident. */ if (uv__handle_fd((uv_handle_t*) send_handle) < 0) return -EBADF; } /* It's legal for write_queue_size > 0 even when the write_queue is empty; * it means there are error-state requests in the write_completed_queue that * will touch up write_queue_size later, see also uv__write_req_finish(). * We could check that write_queue is empty instead but that implies making * a write() syscall when we know that the handle is in error mode. */ empty_queue = (stream->write_queue_size == 0); /* Initialize the req */ uv__req_init(stream->loop, req, UV_WRITE); req->cb = cb; req->handle = stream; req->error = 0; req->send_handle = send_handle; QUEUE_INIT(&req->queue); req->bufs = req->bufsml; if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = (uv_buf_t*)malloc(nbufs * sizeof(bufs[0])); if (req->bufs == NULL) return -ENOMEM; memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); req->nbufs = nbufs; req->write_index = 0; stream->write_queue_size += uv__count_bufs(bufs, nbufs); /* Append the request to write_queue. */ QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); /* If the queue was empty when this function began, we should attempt to * do the write immediately. Otherwise start the write_watcher and wait * for the fd to become writable. */ if (stream->connect_req) { /* Still connecting, do nothing. */ } else if (empty_queue) { uv__write(stream); } else { /* * blocking streams should never have anything in the queue. * if this assert fires then somehow the blocking stream isn't being * sufficiently flushed in uv__write. */ assert(!(stream->flags & UV_STREAM_BLOCKING)); uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); } return 0; }