Browse Source

Upgrade libuv to 7108ca88

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
9dd979228d
  1. 2
      deps/uv/config-unix.mk
  2. 1
      deps/uv/include/uv-unix.h
  3. 5
      deps/uv/include/uv.h
  4. 6
      deps/uv/src/eio/eio.c
  5. 272
      deps/uv/src/uv-unix.c
  6. 4
      deps/uv/src/win/pipe.c
  7. 3
      deps/uv/test/benchmark-pump.c
  8. 4
      deps/uv/test/test-pipe-bind-error.c
  9. 2
      deps/uv/test/test-spawn.c

2
deps/uv/config-unix.mk

@ -98,7 +98,7 @@ src/ev/ev.o: src/ev/ev.c
EIO_CPPFLAGS += $(CPPFLAGS) EIO_CPPFLAGS += $(CPPFLAGS)
EIO_CPPFLAGS += -DEIO_CONFIG_H=\"$(EIO_CONFIG)\" EIO_CPPFLAGS += -DEIO_CONFIG_H=\"$(EIO_CONFIG)\"
EIO_CPPFLAGS += -DEIO_STACKSIZE=65536 EIO_CPPFLAGS += -DEIO_STACKSIZE=262144
EIO_CPPFLAGS += -D_GNU_SOURCE EIO_CPPFLAGS += -D_GNU_SOURCE
src/eio/eio.o: src/eio/eio.c src/eio/eio.o: src/eio/eio.c

1
deps/uv/include/uv-unix.h

@ -88,6 +88,7 @@ typedef struct {
#define UV_PIPE_PRIVATE_FIELDS \ #define UV_PIPE_PRIVATE_FIELDS \
UV_TCP_PRIVATE_FIELDS \ UV_TCP_PRIVATE_FIELDS \
const char* pipe_fname; /* strdup'ed */ \ const char* pipe_fname; /* strdup'ed */ \
void* pipe_flock;
/* UV_PREPARE */ \ /* UV_PREPARE */ \

5
deps/uv/include/uv.h

@ -508,9 +508,8 @@ typedef struct uv_process_options_s {
char** env; char** env;
char* cwd; char* cwd;
/* /*
* The user should supply pointers to uninitialized uv_pipe_t structs for * The user should supply pointers to initialized uv_pipe_t structs for
* stdio. They will be initialized by uv_spawn. The user is reponsible for * stdio. The user is reponsible for calling uv_close on them.
* calling uv_close on them.
*/ */
uv_pipe_t* stdin_stream; uv_pipe_t* stdin_stream;
uv_pipe_t* stdout_stream; uv_pipe_t* stdout_stream;

6
deps/uv/src/eio/eio.c

@ -40,7 +40,7 @@
#include "eio.h" #include "eio.h"
#ifdef EIO_STACKSIZE #ifdef EIO_STACKSIZE
# define XTHREAD_STACKSIZE EIO_STACKSIZE # define X_STACKSIZE EIO_STACKSIZE
#endif #endif
// For statically-linked pthreads-w32, use: // For statically-linked pthreads-w32, use:
@ -1270,6 +1270,10 @@ eio__scandir (eio_req *req, etp_worker *self)
X_LOCK (wrklock); X_LOCK (wrklock);
/* the corresponding closedir is in ETP_WORKER_CLEAR */ /* the corresponding closedir is in ETP_WORKER_CLEAR */
self->dirp = dirp = opendir (req->ptr1); 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->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
req->ptr2 = names = malloc (namesalloc); req->ptr2 = names = malloc (namesalloc);

272
deps/uv/src/uv-unix.c

@ -35,6 +35,7 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
@ -42,6 +43,11 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <limits.h> /* PATH_MAX */ #include <limits.h> /* PATH_MAX */
#ifdef __sun
# include <sys/types.h>
# include <sys/wait.h>
#endif
#if defined(__APPLE__) #if defined(__APPLE__)
#include <mach-o/dyld.h> /* _NSGetExecutablePath */ #include <mach-o/dyld.h> /* _NSGetExecutablePath */
#endif #endif
@ -73,6 +79,32 @@ struct uv_ares_data_s {
static struct uv_ares_data_s ares_data; 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__req_init(uv_req_t*);
void uv__next(EV_P_ ev_idle* watcher, int revents); 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_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_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 uv_write_t* uv__write(uv_stream_t* stream);
static void uv__read(uv_stream_t* stream); static void uv__read(uv_stream_t* stream);
static void uv__stream_connect(uv_stream_t*); 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: case UV_NAMED_PIPE:
pipe = (uv_pipe_t*)handle; pipe = (uv_pipe_t*)handle;
if (pipe->pipe_fname) { uv_pipe_cleanup(pipe);
/* uv_read_stop((uv_stream_t*)handle);
* 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);
ev_io_stop(EV_DEFAULT_ &pipe->write_watcher); ev_io_stop(EV_DEFAULT_ &pipe->write_watcher);
break; break;
@ -1807,6 +1831,7 @@ int uv_pipe_init(uv_pipe_t* handle) {
uv_counters()->pipe_init++; uv_counters()->pipe_init++;
handle->type = UV_NAMED_PIPE; handle->type = UV_NAMED_PIPE;
handle->pipe_flock = NULL; /* Only set by listener. */
handle->pipe_fname = NULL; /* Only set by listener. */ handle->pipe_fname = NULL; /* Only set by listener. */
ev_init(&handle->write_watcher, uv__stream_io); 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) { int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
struct sockaddr_un sun; struct sockaddr_un sun;
const char* pipe_fname; const char* pipe_fname;
uv_flock_t* pipe_flock;
int saved_errno; int saved_errno;
int locked;
int sockfd; int sockfd;
int status; int status;
int bound; int bound;
saved_errno = errno; saved_errno = errno;
pipe_fname = NULL; pipe_fname = NULL;
pipe_flock = NULL;
sockfd = -1; sockfd = -1;
status = -1; status = -1;
bound = 0; 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. */ /* We've got a copy, don't touch the original any more. */
name = NULL; 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) { if ((sockfd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
uv_err_new((uv_handle_t*)handle, errno); uv_err_new((uv_handle_t*)handle, errno);
goto out; goto out;
@ -1861,17 +1903,13 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
sun.sun_family = AF_UNIX; sun.sun_family = AF_UNIX;
if (bind(sockfd, (struct sockaddr*)&sun, sizeof sun) == -1) { if (bind(sockfd, (struct sockaddr*)&sun, sizeof sun) == -1) {
#ifdef DONT_RACE_ME_BRO /* On EADDRINUSE:
/* *
* Try to bind the socket. Note that we explicitly don't act * We hold the file lock so there is no other process listening
* on EADDRINUSE. Unlinking and trying to bind again opens * on the socket. Ergo, it's stale - remove it.
* a window for races with other threads and processes. *
*/ * This assumes that the other process uses locking too
uv_err_new((uv_handle_t*)handle, (errno == ENOENT) ? EACCES : errno); * but that's a good enough assumption for now.
goto out;
#else
/*
* Try to re-purpose the socket. This is a potential race window.
*/ */
if (errno != EADDRINUSE if (errno != EADDRINUSE
|| unlink(pipe_fname) == -1 || 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); uv_err_new((uv_handle_t*)handle, (errno == ENOENT) ? EACCES : errno);
goto out; goto out;
} }
#endif
} }
bound = 1; bound = 1;
@ -1898,6 +1935,11 @@ out:
unlink(pipe_fname); unlink(pipe_fname);
} }
uv__close(sockfd); uv__close(sockfd);
if (pipe_flock) {
uv_flock_destroy(pipe_flock);
}
free((void*)pipe_fname); 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; status = -1;
if (handle->fd == -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; goto out;
} }
assert(handle->fd >= 0); 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, int uv_pipe_connect(uv_connect_t* req,
uv_pipe_t* handle, uv_pipe_t* handle,
const char* name, const char* name,
@ -2198,19 +2271,39 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
process->exit_cb = options.exit_cb; process->exit_cb = options.exit_cb;
if (options.stdin_stream) {
if (options.stdin_stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
goto error;
}
if (pipe(stdin_pipe) < 0) {
goto error;
}
}
if (options.stdin_stream && pipe(stdin_pipe) < 0) { if (options.stdout_stream) {
if (options.stdout_stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
goto error; goto error;
} }
if (options.stdout_stream && pipe(stdout_pipe) < 0) { if (pipe(stdout_pipe) < 0) {
goto error; goto error;
} }
}
if (options.stderr_stream && pipe(stderr_pipe) < 0) { if (options.stderr_stream) {
if (options.stderr_stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
goto error; goto error;
} }
if (pipe(stderr_pipe) < 0) {
goto error;
}
}
pid = fork(); pid = fork();
if (pid == 0) { if (pid == 0) {
@ -2262,7 +2355,6 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
assert(stdin_pipe[0] >= 0); assert(stdin_pipe[0] >= 0);
close(stdin_pipe[0]); close(stdin_pipe[0]);
uv__nonblock(stdin_pipe[1], 1); uv__nonblock(stdin_pipe[1], 1);
uv_pipe_init(options.stdin_stream);
uv__stream_open((uv_stream_t*)options.stdin_stream, stdin_pipe[1]); 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); assert(stdout_pipe[1] >= 0);
close(stdout_pipe[1]); close(stdout_pipe[1]);
uv__nonblock(stdout_pipe[0], 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]); 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); assert(stderr_pipe[1] >= 0);
close(stderr_pipe[1]); close(stderr_pipe[1]);
uv__nonblock(stderr_pipe[0], 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]); 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; 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

@ -444,13 +444,13 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
HANDLE pipeHandle; HANDLE pipeHandle;
if (handle->flags & UV_HANDLE_BIND_ERROR) { if (handle->flags & UV_HANDLE_BIND_ERROR) {
LOOP->last_error = handle->error; uv_set_error(UV_EINVAL, 0);
return -1; return -1;
} }
if (!(handle->flags & UV_HANDLE_BOUND) && if (!(handle->flags & UV_HANDLE_BOUND) &&
!(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) { !(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) {
uv_set_error(UV_ENOTCONN, 0); uv_set_error(UV_EINVAL, 0);
return -1; return -1;
} }

3
deps/uv/test/benchmark-pump.c

@ -149,7 +149,6 @@ void read_sockets_close_cb(uv_handle_t* handle) {
static void start_stats_collection() { static void start_stats_collection() {
uv_req_t* req = req_alloc();
int r; int r;
/* Show-stats timer */ /* 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) { static void write_cb(uv_write_t* req, int status) {
uv_buf_t* buf = (uv_buf_t*) req->data;
ASSERT(status == 0); ASSERT(status == 0);
req_free((uv_req_t*) req); req_free((uv_req_t*) req);

4
deps/uv/test/test-pipe-bind-error.c

@ -64,7 +64,7 @@ TEST_IMPL(pipe_bind_error_addrinuse) {
r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL); r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL);
ASSERT(r == -1); 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*)&server1, close_cb);
uv_close((uv_handle_t*)&server2, 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); r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
ASSERT(r == -1); 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); uv_close((uv_handle_t*)&server, close_cb);

2
deps/uv/test/test-spawn.c

@ -114,6 +114,8 @@ TEST_IMPL(spawn_stdout) {
uv_init(); uv_init();
init_process_options("spawn_helper2"); init_process_options("spawn_helper2");
uv_pipe_init(&out);
options.stdout_stream = &out; options.stdout_stream = &out;
r = uv_spawn(&process, options); r = uv_spawn(&process, options);

Loading…
Cancel
Save