Ensure that close() system calls don't close stdio file descriptors
because that is almost never the intention.
This is also a partial workaround for a kernel bug that seems to affect
all Linux kernels when stdin is a pipe that gets closed: fd 0 keeps
signalling EPOLLHUP but a subsequent call to epoll_ctl(EPOLL_CTL_DEL)
fails with EBADF. See joyent/node#6271 for details and a test case.
Passing or returning structs as values makes life hard for people that
work with libuv through a foreign function interface. Switch to a
pointer-based approach.
Fixes#684.
Passing or returning structs as values makes life hard for people that
work with libuv through a foreign function interface. Switch to a
pointer-based approach.
Fixes#684.
This commit changes the libuv API to return error codes directly rather
than storing them in a loop-global field.
A code snippet like this one:
if (uv_foo(loop) < 0) {
uv_err_t err = uv_last_error(loop);
fprintf(stderr, "%s\n", uv_strerror(err));
}
Should be rewritten like this:
int err = uv_foo(loop);
if (err < 0)
fprintf(stderr, "%s\n", uv_strerror(err));
The rationale for this change is that it should make creating bindings
for other languages a lot easier: dealing with struct return values is
painful with most FFIs and often downright buggy.
Remove the errno preserving code. Libuv only implemented it in a
haphazard way and there seems to be a general consensus that no one
really cares anyway. Therefore, remove it.
Inverts the meaning of the 'enable' argument. Before, it actually set
the UV_TCP_SINGLE_ACCEPT flag when enable=1. Now it clears it, which is
what uv-win does and what you would expect it to do.
Don't use the relaxed accept() algorithm introduced in be2a217 unless
explicitly requested. It causes a 50+% performance drop on some node.js
benchmarks:
$ alias bench='out/Release/node benchmark/http_simple_auto.js \
-c 10 -n 50000 bytes/1 2>&1 | grep Req'
$ UV_TCP_SINGLE_ACCEPT=0 bench
Requests per second: 12331.84 [#/sec] (mean)
$ UV_TCP_SINGLE_ACCEPT=1 bench
Requests per second: 3944.63 [#/sec] (mean)
kqueue(2) on osx doesn't work (emits EINVAL error) with specific fds
(i.e. /dev/tty, /dev/null, etc). When given such descriptors - start
select(2) watcher thread that will emit io events.
Avoid the extra syscall, it's a no-op for non-listening sockets.
At least, it should be - it remains to be investigated if a FreeBSD kernel bug
affects ephemeral port allocation inside connect(). See [1] for details.
[1] http://www.freebsd.org/cgi/query-pr.cgi?pr=174087
Benchmarks demonstrated that the idle timer handle approach didn't balance the
load quite fair enough, the majority of new connections still ended up in one
or two processes.
The new approach voluntarily gives up a scheduler timeslice by calling
nanosleep() with a one nanosecond timeout.
Why not sched_yield()? Because on Linux (and this is probably true for other
Unices as well), sched_yield() only yields if there are other processes running
on the same CPU.
nanosleep() on the other hand always forces the process to sleep, which gives
other processes a chance to accept our pending connections.
Don't make the event loop spin when connect() returns EINPROGRESS.
Test case:
#include "uv.h"
static void connect_cb(uv_connect_t* req, int status) {
// ...
}
int main() {
uv_tcp_t handle;
uv_connect_t req;
struct sockaddr_in addr;
addr = uv_ip4_addr("8.8.8.8", 1234); // unreachable
uv_tcp_init(uv_default_loop(), &handle);
uv_tcp_connect(&req, (uv_stream_t*)&handle, addr, connect_cb);
uv_run(uv_default_loop()); // busy loops until connection times out
return 0;
}
After EINPROGRESS, there are zero active handles and one active request. That
in turn makes uv__poll_timeout() believe that it should merely poll, not block,
in epoll() / kqueue() / port_getn().
Sidestep that by artificially starting the handle on connect() and stopping it
again once the TCP handshake completes / is rejected / times out.
It's a slightly hacky approach because I don't want to change the ABI of the
stable branch. I'll address it properly in the master branch.
Incidentally fixes a rather obscure bug where uv_tcp_connect() reconnected
and leaked a file descriptor when the handle was already busy connecting,
handle->fd was zero (unlikely) and uv_tcp_connect() got called again.