Upgrade libuv to 7108ca88
This commit is contained in:
parent
de0b8d601c
commit
9dd979228d
2
deps/uv/config-unix.mk
vendored
2
deps/uv/config-unix.mk
vendored
@ -98,7 +98,7 @@ src/ev/ev.o: src/ev/ev.c
|
||||
|
||||
EIO_CPPFLAGS += $(CPPFLAGS)
|
||||
EIO_CPPFLAGS += -DEIO_CONFIG_H=\"$(EIO_CONFIG)\"
|
||||
EIO_CPPFLAGS += -DEIO_STACKSIZE=65536
|
||||
EIO_CPPFLAGS += -DEIO_STACKSIZE=262144
|
||||
EIO_CPPFLAGS += -D_GNU_SOURCE
|
||||
|
||||
src/eio/eio.o: src/eio/eio.c
|
||||
|
1
deps/uv/include/uv-unix.h
vendored
1
deps/uv/include/uv-unix.h
vendored
@ -88,6 +88,7 @@ typedef struct {
|
||||
#define UV_PIPE_PRIVATE_FIELDS \
|
||||
UV_TCP_PRIVATE_FIELDS \
|
||||
const char* pipe_fname; /* strdup'ed */ \
|
||||
void* pipe_flock;
|
||||
|
||||
|
||||
/* UV_PREPARE */ \
|
||||
|
5
deps/uv/include/uv.h
vendored
5
deps/uv/include/uv.h
vendored
@ -508,9 +508,8 @@ typedef struct uv_process_options_s {
|
||||
char** env;
|
||||
char* cwd;
|
||||
/*
|
||||
* The user should supply pointers to uninitialized uv_pipe_t structs for
|
||||
* stdio. They will be initialized by uv_spawn. The user is reponsible for
|
||||
* calling uv_close on them.
|
||||
* The user should supply pointers to initialized uv_pipe_t structs for
|
||||
* stdio. The user is reponsible for calling uv_close on them.
|
||||
*/
|
||||
uv_pipe_t* stdin_stream;
|
||||
uv_pipe_t* stdout_stream;
|
||||
|
6
deps/uv/src/eio/eio.c
vendored
6
deps/uv/src/eio/eio.c
vendored
@ -40,7 +40,7 @@
|
||||
#include "eio.h"
|
||||
|
||||
#ifdef EIO_STACKSIZE
|
||||
# define XTHREAD_STACKSIZE EIO_STACKSIZE
|
||||
# define X_STACKSIZE EIO_STACKSIZE
|
||||
#endif
|
||||
|
||||
// For statically-linked pthreads-w32, use:
|
||||
@ -1270,6 +1270,10 @@ eio__scandir (eio_req *req, etp_worker *self)
|
||||
X_LOCK (wrklock);
|
||||
/* the corresponding closedir is in ETP_WORKER_CLEAR */
|
||||
self->dirp = dirp = opendir (req->ptr1);
|
||||
|
||||
if (req->flags & EIO_FLAG_PTR1_FREE)
|
||||
free (req->ptr1);
|
||||
|
||||
req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
|
||||
req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
|
||||
req->ptr2 = names = malloc (namesalloc);
|
||||
|
278
deps/uv/src/uv-unix.c
vendored
278
deps/uv/src/uv-unix.c
vendored
@ -35,6 +35,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@ -42,6 +43,11 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <limits.h> /* PATH_MAX */
|
||||
|
||||
#ifdef __sun
|
||||
# include <sys/types.h>
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
#endif
|
||||
@ -73,6 +79,32 @@ struct uv_ares_data_s {
|
||||
|
||||
static struct uv_ares_data_s ares_data;
|
||||
|
||||
typedef struct {
|
||||
const char* lockfile;
|
||||
int lockfd;
|
||||
} uv_flock_t;
|
||||
|
||||
|
||||
/* Create a new advisory file lock for `filename`.
|
||||
* Call `uv_flock_acquire()` to actually acquire the lock.
|
||||
*/
|
||||
int uv_flock_init(uv_flock_t* lock, const char* filename);
|
||||
|
||||
/* Try to acquire the file lock. Returns 0 on success, -1 on error.
|
||||
* Does not wait for the lock to be released if it is held by another process.
|
||||
*
|
||||
* If `locked` is not NULL, the memory pointed it points to is set to 1 if
|
||||
* the file is locked by another process. Only relevant in error scenarios.
|
||||
*/
|
||||
int uv_flock_acquire(uv_flock_t* lock, int* locked);
|
||||
|
||||
/* Release the file lock. Returns 0 on success, -1 on error.
|
||||
*/
|
||||
int uv_flock_release(uv_flock_t* lock);
|
||||
|
||||
/* Destroy the file lock. Releases the file lock and associated resources.
|
||||
*/
|
||||
int uv_flock_destroy(uv_flock_t* lock);
|
||||
|
||||
void uv__req_init(uv_req_t*);
|
||||
void uv__next(EV_P_ ev_idle* watcher, int revents);
|
||||
@ -82,6 +114,7 @@ static uv_err_t uv_err_new(uv_handle_t* handle, int sys_error);
|
||||
|
||||
static int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
|
||||
static int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
static int uv_pipe_cleanup(uv_pipe_t* handle);
|
||||
static uv_write_t* uv__write(uv_stream_t* stream);
|
||||
static void uv__read(uv_stream_t* stream);
|
||||
static void uv__stream_connect(uv_stream_t*);
|
||||
@ -241,17 +274,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
pipe = (uv_pipe_t*)handle;
|
||||
if (pipe->pipe_fname) {
|
||||
/*
|
||||
* Unlink the file system entity before closing the file descriptor.
|
||||
* Doing it the other way around introduces a race where our process
|
||||
* unlinks a socket with the same name that's just been created by
|
||||
* another thread or process.
|
||||
*/
|
||||
unlink(pipe->pipe_fname);
|
||||
free((void*)pipe->pipe_fname);
|
||||
}
|
||||
uv_read_stop((uv_stream_t*)pipe);
|
||||
uv_pipe_cleanup(pipe);
|
||||
uv_read_stop((uv_stream_t*)handle);
|
||||
ev_io_stop(EV_DEFAULT_ &pipe->write_watcher);
|
||||
break;
|
||||
|
||||
@ -1807,6 +1831,7 @@ int uv_pipe_init(uv_pipe_t* handle) {
|
||||
uv_counters()->pipe_init++;
|
||||
|
||||
handle->type = UV_NAMED_PIPE;
|
||||
handle->pipe_flock = NULL; /* Only set by listener. */
|
||||
handle->pipe_fname = NULL; /* Only set by listener. */
|
||||
|
||||
ev_init(&handle->write_watcher, uv__stream_io);
|
||||
@ -1825,13 +1850,16 @@ int uv_pipe_init(uv_pipe_t* handle) {
|
||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
struct sockaddr_un sun;
|
||||
const char* pipe_fname;
|
||||
uv_flock_t* pipe_flock;
|
||||
int saved_errno;
|
||||
int locked;
|
||||
int sockfd;
|
||||
int status;
|
||||
int bound;
|
||||
|
||||
saved_errno = errno;
|
||||
pipe_fname = NULL;
|
||||
pipe_flock = NULL;
|
||||
sockfd = -1;
|
||||
status = -1;
|
||||
bound = 0;
|
||||
@ -1851,6 +1879,20 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
/* We've got a copy, don't touch the original any more. */
|
||||
name = NULL;
|
||||
|
||||
/* Create and acquire a file lock for this UNIX socket. */
|
||||
if ((pipe_flock = malloc(sizeof *pipe_flock)) == NULL
|
||||
|| uv_flock_init(pipe_flock, pipe_fname) == -1) {
|
||||
uv_err_new((uv_handle_t*)handle, ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (uv_flock_acquire(pipe_flock, &locked) == -1) {
|
||||
/* Another process holds the lock so the socket is in use. */
|
||||
uv_err_new_artificial((uv_handle_t*)handle,
|
||||
locked ? UV_EADDRINUSE : UV_EACCESS);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((sockfd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
uv_err_new((uv_handle_t*)handle, errno);
|
||||
goto out;
|
||||
@ -1861,17 +1903,13 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
sun.sun_family = AF_UNIX;
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&sun, sizeof sun) == -1) {
|
||||
#ifdef DONT_RACE_ME_BRO
|
||||
/*
|
||||
* Try to bind the socket. Note that we explicitly don't act
|
||||
* on EADDRINUSE. Unlinking and trying to bind again opens
|
||||
* a window for races with other threads and processes.
|
||||
*/
|
||||
uv_err_new((uv_handle_t*)handle, (errno == ENOENT) ? EACCES : errno);
|
||||
goto out;
|
||||
#else
|
||||
/*
|
||||
* Try to re-purpose the socket. This is a potential race window.
|
||||
/* On EADDRINUSE:
|
||||
*
|
||||
* We hold the file lock so there is no other process listening
|
||||
* on the socket. Ergo, it's stale - remove it.
|
||||
*
|
||||
* This assumes that the other process uses locking too
|
||||
* but that's a good enough assumption for now.
|
||||
*/
|
||||
if (errno != EADDRINUSE
|
||||
|| unlink(pipe_fname) == -1
|
||||
@ -1880,7 +1918,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
uv_err_new((uv_handle_t*)handle, (errno == ENOENT) ? EACCES : errno);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
bound = 1;
|
||||
|
||||
@ -1898,6 +1935,11 @@ out:
|
||||
unlink(pipe_fname);
|
||||
}
|
||||
uv__close(sockfd);
|
||||
|
||||
if (pipe_flock) {
|
||||
uv_flock_destroy(pipe_flock);
|
||||
}
|
||||
|
||||
free((void*)pipe_fname);
|
||||
}
|
||||
|
||||
@ -1914,7 +1956,7 @@ static int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
status = -1;
|
||||
|
||||
if (handle->fd == -1) {
|
||||
uv_err_new_artificial((uv_handle_t*)handle, UV_ENOTCONN);
|
||||
uv_err_new_artificial((uv_handle_t*)handle, UV_EINVAL);
|
||||
goto out;
|
||||
}
|
||||
assert(handle->fd >= 0);
|
||||
@ -1933,6 +1975,37 @@ out:
|
||||
}
|
||||
|
||||
|
||||
static int uv_pipe_cleanup(uv_pipe_t* handle) {
|
||||
int saved_errno;
|
||||
int status;
|
||||
|
||||
saved_errno = errno;
|
||||
status = -1;
|
||||
|
||||
if (handle->pipe_fname) {
|
||||
/*
|
||||
* Unlink the file system entity before closing the file descriptor.
|
||||
* Doing it the other way around introduces a race where our process
|
||||
* unlinks a socket with the same name that's just been created by
|
||||
* another thread or process.
|
||||
*
|
||||
* This is less of an issue now that we attach a file lock
|
||||
* to the socket but it's still a best practice.
|
||||
*/
|
||||
unlink(handle->pipe_fname);
|
||||
free((void*)handle->pipe_fname);
|
||||
}
|
||||
|
||||
if (handle->pipe_flock) {
|
||||
uv_flock_destroy((uv_flock_t*)handle->pipe_flock);
|
||||
free(handle->pipe_flock);
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_connect(uv_connect_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const char* name,
|
||||
@ -2198,17 +2271,37 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
|
||||
|
||||
process->exit_cb = options.exit_cb;
|
||||
|
||||
if (options.stdin_stream) {
|
||||
if (options.stdin_stream->type != UV_NAMED_PIPE) {
|
||||
errno = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (options.stdin_stream && pipe(stdin_pipe) < 0) {
|
||||
goto error;
|
||||
if (pipe(stdin_pipe) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.stdout_stream && pipe(stdout_pipe) < 0) {
|
||||
goto error;
|
||||
if (options.stdout_stream) {
|
||||
if (options.stdout_stream->type != UV_NAMED_PIPE) {
|
||||
errno = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pipe(stdout_pipe) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.stderr_stream && pipe(stderr_pipe) < 0) {
|
||||
goto error;
|
||||
if (options.stderr_stream) {
|
||||
if (options.stderr_stream->type != UV_NAMED_PIPE) {
|
||||
errno = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pipe(stderr_pipe) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
@ -2262,7 +2355,6 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
|
||||
assert(stdin_pipe[0] >= 0);
|
||||
close(stdin_pipe[0]);
|
||||
uv__nonblock(stdin_pipe[1], 1);
|
||||
uv_pipe_init(options.stdin_stream);
|
||||
uv__stream_open((uv_stream_t*)options.stdin_stream, stdin_pipe[1]);
|
||||
}
|
||||
|
||||
@ -2271,7 +2363,6 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
|
||||
assert(stdout_pipe[1] >= 0);
|
||||
close(stdout_pipe[1]);
|
||||
uv__nonblock(stdout_pipe[0], 1);
|
||||
uv_pipe_init(options.stdout_stream);
|
||||
uv__stream_open((uv_stream_t*)options.stdout_stream, stdout_pipe[0]);
|
||||
}
|
||||
|
||||
@ -2280,7 +2371,6 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
|
||||
assert(stderr_pipe[1] >= 0);
|
||||
close(stderr_pipe[1]);
|
||||
uv__nonblock(stderr_pipe[0], 1);
|
||||
uv_pipe_init(options.stderr_stream);
|
||||
uv__stream_open((uv_stream_t*)options.stderr_stream, stderr_pipe[0]);
|
||||
}
|
||||
|
||||
@ -2308,3 +2398,125 @@ int uv_process_kill(uv_process_t* process, int signum) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define LOCKFILE_SUFFIX ".lock"
|
||||
int uv_flock_init(uv_flock_t* lock, const char* filename) {
|
||||
int saved_errno;
|
||||
int status;
|
||||
char* lockfile;
|
||||
|
||||
saved_errno = errno;
|
||||
status = -1;
|
||||
|
||||
lock->lockfd = -1;
|
||||
lock->lockfile = NULL;
|
||||
|
||||
if ((lockfile = malloc(strlen(filename) + sizeof LOCKFILE_SUFFIX)) == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy(lockfile, filename);
|
||||
strcat(lockfile, LOCKFILE_SUFFIX);
|
||||
lock->lockfile = lockfile;
|
||||
status = 0;
|
||||
|
||||
out:
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
#undef LOCKFILE_SUFFIX
|
||||
|
||||
|
||||
int uv_flock_acquire(uv_flock_t* lock, int* locked_p) {
|
||||
char buf[32];
|
||||
int saved_errno;
|
||||
int status;
|
||||
int lockfd;
|
||||
int locked;
|
||||
|
||||
saved_errno = errno;
|
||||
status = -1;
|
||||
lockfd = -1;
|
||||
locked = 0;
|
||||
|
||||
do {
|
||||
lockfd = open(lock->lockfile, O_WRONLY | O_CREAT, 0666);
|
||||
}
|
||||
while (lockfd == -1 && errno == EINTR);
|
||||
|
||||
if (lockfd == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
do {
|
||||
status = flock(lockfd, LOCK_EX | LOCK_NB);
|
||||
}
|
||||
while (status == -1 && errno == EINTR);
|
||||
|
||||
if (status == -1) {
|
||||
locked = (errno == EAGAIN); /* Lock is held by another process. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof buf, "%d\n", getpid());
|
||||
do {
|
||||
status = write(lockfd, buf, strlen(buf));
|
||||
}
|
||||
while (status == -1 && errno == EINTR);
|
||||
|
||||
lock->lockfd = lockfd;
|
||||
status = 0;
|
||||
|
||||
out:
|
||||
if (status) {
|
||||
uv__close(lockfd);
|
||||
}
|
||||
|
||||
if (locked_p) {
|
||||
*locked_p = locked;
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int uv_flock_release(uv_flock_t* lock) {
|
||||
int saved_errno;
|
||||
int status;
|
||||
|
||||
saved_errno = errno;
|
||||
status = -1;
|
||||
|
||||
if (unlink(lock->lockfile) == -1) {
|
||||
/* Now what? */
|
||||
goto out;
|
||||
}
|
||||
|
||||
uv__close(lock->lockfd);
|
||||
lock->lockfd = -1;
|
||||
status = 0;
|
||||
|
||||
out:
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int uv_flock_destroy(uv_flock_t* lock) {
|
||||
int saved_errno;
|
||||
int status;
|
||||
|
||||
saved_errno = errno;
|
||||
status = unlink(lock->lockfile);
|
||||
|
||||
uv__close(lock->lockfd);
|
||||
lock->lockfd = -1;
|
||||
|
||||
free((void*)lock->lockfile);
|
||||
lock->lockfile = NULL;
|
||||
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
4
deps/uv/src/win/pipe.c
vendored
4
deps/uv/src/win/pipe.c
vendored
@ -444,13 +444,13 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
HANDLE pipeHandle;
|
||||
|
||||
if (handle->flags & UV_HANDLE_BIND_ERROR) {
|
||||
LOOP->last_error = handle->error;
|
||||
uv_set_error(UV_EINVAL, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND) &&
|
||||
!(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) {
|
||||
uv_set_error(UV_ENOTCONN, 0);
|
||||
uv_set_error(UV_EINVAL, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
3
deps/uv/test/benchmark-pump.c
vendored
3
deps/uv/test/benchmark-pump.c
vendored
@ -149,7 +149,6 @@ void read_sockets_close_cb(uv_handle_t* handle) {
|
||||
|
||||
|
||||
static void start_stats_collection() {
|
||||
uv_req_t* req = req_alloc();
|
||||
int r;
|
||||
|
||||
/* Show-stats timer */
|
||||
@ -184,8 +183,6 @@ static void read_cb(uv_stream_t* stream, ssize_t bytes, uv_buf_t buf) {
|
||||
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
uv_buf_t* buf = (uv_buf_t*) req->data;
|
||||
|
||||
ASSERT(status == 0);
|
||||
|
||||
req_free((uv_req_t*) req);
|
||||
|
4
deps/uv/test/test-pipe-bind-error.c
vendored
4
deps/uv/test/test-pipe-bind-error.c
vendored
@ -64,7 +64,7 @@ TEST_IMPL(pipe_bind_error_addrinuse) {
|
||||
r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL);
|
||||
ASSERT(r == -1);
|
||||
|
||||
ASSERT(uv_last_error().code == UV_EADDRINUSE);
|
||||
ASSERT(uv_last_error().code == UV_EINVAL);
|
||||
|
||||
uv_close((uv_handle_t*)&server1, close_cb);
|
||||
uv_close((uv_handle_t*)&server2, close_cb);
|
||||
@ -136,7 +136,7 @@ TEST_IMPL(pipe_listen_without_bind) {
|
||||
r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
|
||||
ASSERT(r == -1);
|
||||
|
||||
ASSERT(uv_last_error().code == UV_ENOTCONN);
|
||||
ASSERT(uv_last_error().code == UV_EINVAL);
|
||||
|
||||
uv_close((uv_handle_t*)&server, close_cb);
|
||||
|
||||
|
2
deps/uv/test/test-spawn.c
vendored
2
deps/uv/test/test-spawn.c
vendored
@ -114,6 +114,8 @@ TEST_IMPL(spawn_stdout) {
|
||||
uv_init();
|
||||
|
||||
init_process_options("spawn_helper2");
|
||||
|
||||
uv_pipe_init(&out);
|
||||
options.stdout_stream = &out;
|
||||
|
||||
r = uv_spawn(&process, options);
|
||||
|
Loading…
x
Reference in New Issue
Block a user