Upgrade libuv to f1859eb841be2fe48512bc10e64556383f408b01

This commit is contained in:
Brian Anderson 2011-11-07 19:24:25 -08:00
parent 06d14f3a1c
commit fdeb5ba304
62 changed files with 1619 additions and 355 deletions

View file

@ -40,17 +40,17 @@ do
# Comment out the gyp auto regeneration
for os in mac unix win; do
sed -i "" \
sed -i \
-e 's/^\(Makefile: $(srcdir)\/src\/rt\/libuv\/uv\.gyp\)/#\1/' \
mk/libuv/$ARCH/$os/Makefile
sed -i "" \
sed -i \
-e 's/^\( $(call do_cmd,regen_makefile)\)/#\1/' \
mk/libuv/$ARCH/$os/Makefile
done
done
# On Mac, GYP hardcodes a -arch i386 into the output. Fix that.
sed -i "" \
sed -i \
-e 's/-arch i386/-arch x86_64/' \
mk/libuv/x86_64/mac/src/rt/libuv/*.mk

View file

@ -0,0 +1,20 @@
#!/usr/bin/env python
import os
import re
import subprocess
import sys
def DoMain(*args):
cc = os.environ.get('CC', 'gcc')
stdin, stderr = os.pipe()
subprocess.call([cc, '-v'], stderr=stderr)
output = os.read(stdin, 4096)
match = re.search("\ngcc version (\d+\.\d+\.\d+)", output)
if match:
print(match.group(1))
if __name__ == '__main__':
DoMain(*sys.argv)

View file

@ -114,9 +114,11 @@
],
}],
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
'cflags': [ '-Wall', '-pthread', ],
'variables': {
'gcc_version%': '<!(python build/gcc_version.py)>)',
},
'cflags': [ '-Wall' ],
'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ],
'ldflags': [ '-pthread', ],
'conditions': [
[ 'host_arch != target_arch and target_arch=="ia32"', {
'cflags': [ '-m32' ],
@ -125,7 +127,14 @@
[ 'OS=="linux"', {
'cflags': [ '-ansi' ],
}],
[ 'visibility=="hidden"', {
[ 'OS=="solaris"', {
'cflags': [ '-pthreads' ],
'ldflags': [ '-pthreads' ],
}, {
'cflags': [ '-pthread' ],
'ldflags': [ '-pthread' ],
}],
[ 'visibility=="hidden" and gcc_version >= "4.0.0"', {
'cflags': [ '-fvisibility=hidden' ],
}],
],
@ -143,7 +152,6 @@
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics
'GCC_VERSION': '4.2',
'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof
'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4
'PREBINDING': 'NO', # No -Wl,-prebind

View file

@ -28,6 +28,7 @@ CPPFLAGS += -D_LARGEFILE_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64
OBJS += src/unix/core.o
OBJS += src/unix/dl.o
OBJS += src/unix/fs.o
OBJS += src/unix/cares.o
OBJS += src/unix/udp.o

View file

@ -43,6 +43,10 @@ typedef struct {
typedef int uv_file;
/* Platform-specific definitions for uv_dlopen support. */
typedef void* uv_lib_t;
#define UV_DYNAMIC /* empty */
#define UV_LOOP_PRIVATE_FIELDS \
ares_channel channel; \
/* \
@ -195,6 +199,16 @@ typedef int uv_file;
uv_fs_event_cb cb; \
int fflags; \
#elif defined(__sun)
#include <sys/port.h>
#include <port.h>
#define UV_FS_EVENT_PRIVATE_FIELDS \
ev_io event_watcher; \
uv_fs_event_cb cb; \
file_obj_t fo; \
#else
/* Stub for platforms where the file watcher isn't implemented yet. */

View file

@ -137,6 +137,10 @@ typedef struct uv_buf_t {
typedef int uv_file;
/* Platform-specific definitions for uv_dlopen support. */
typedef HMODULE uv_lib_t;
#define UV_DYNAMIC FAR WINAPI
RB_HEAD(uv_timer_tree_s, uv_timer_s);
#define UV_LOOP_PRIVATE_FIELDS \
@ -243,6 +247,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
#define uv_tcp_server_fields \
uv_tcp_accept_t* accept_reqs; \
unsigned int processed_accepts; \
uv_tcp_accept_t* pending_accepts; \
LPFN_ACCEPTEX func_acceptex;

View file

@ -27,10 +27,29 @@
extern "C" {
#endif
#ifdef _WIN32
/* Windows - set up dll import/export decorators. */
# if defined(BUILDING_UV_SHARED)
/* Building shared library. Export everything from c-ares as well. */
# define UV_EXTERN __declspec(dllexport)
# define CARES_BUILDING_LIBRARY 1
# elif defined(USING_UV_SHARED)
/* Using shared library. Use shared c-ares as well. */
# define UV_EXTERN __declspec(dllimport)
# else
/* Building static library. Build c-ares statically as well. */
# define UV_EXTERN /* nothing */
# define CARES_STATICLIB 1
# endif
#else
/* Unix. TODO: symbol hiding */
# define UV_EXTERN /* nothing */
#endif
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 1
#define CARES_STATICLIB 1
#include <stdint.h> /* int64_t */
#include <sys/types.h> /* size_t */
@ -52,7 +71,8 @@ typedef enum {
UV_UNKNOWN = -1,
UV_OK = 0,
UV_EOF,
UV_EACCESS,
UV_EADDRINFO,
UV_EACCES,
UV_EAGAIN,
UV_EADDRINUSE,
UV_EADDRNOTAVAIL,
@ -77,6 +97,7 @@ typedef enum {
UV_ENOBUFS,
UV_ENOMEM,
UV_ENOTDIR,
UV_EISDIR,
UV_ENONET,
UV_ENOPROTOOPT,
UV_ENOTCONN,
@ -170,30 +191,30 @@ typedef struct uv_work_s uv_work_t;
* All callbacks in libuv are made asynchronously. That is they are never
* made by the function that takes them as a parameter.
*/
uv_loop_t* uv_loop_new();
void uv_loop_delete(uv_loop_t*);
UV_EXTERN uv_loop_t* uv_loop_new(void);
UV_EXTERN void uv_loop_delete(uv_loop_t*);
/*
* Returns the default loop.
*/
uv_loop_t* uv_default_loop();
UV_EXTERN uv_loop_t* uv_default_loop(void);
/*
* This function starts the event loop. It blocks until the reference count
* of the loop drops to zero.
*/
int uv_run(uv_loop_t*);
UV_EXTERN int uv_run (uv_loop_t*);
/*
* Manually modify the event loop's reference count. Useful if the user wants
* to have a handle or timeout that doesn't keep the loop alive.
*/
void uv_ref(uv_loop_t*);
void uv_unref(uv_loop_t*);
UV_EXTERN void uv_ref(uv_loop_t*);
UV_EXTERN void uv_unref(uv_loop_t*);
void uv_update_time(uv_loop_t*);
int64_t uv_now(uv_loop_t*);
UV_EXTERN void uv_update_time(uv_loop_t*);
UV_EXTERN int64_t uv_now(uv_loop_t*);
/*
@ -260,9 +281,9 @@ struct uv_err_s {
* On error the user should then call uv_last_error() to determine
* the error code.
*/
uv_err_t uv_last_error(uv_loop_t*);
char* uv_strerror(uv_err_t err);
const char* uv_err_name(uv_err_t err);
UV_EXTERN uv_err_t uv_last_error(uv_loop_t*);
UV_EXTERN const char* uv_strerror(uv_err_t err);
UV_EXTERN const char* uv_err_name(uv_err_t err);
#define UV_REQ_FIELDS \
@ -291,7 +312,8 @@ UV_PRIVATE_REQ_TYPES
* initialized stream. req should be an uninitalized shutdown request
* struct. The cb is a called after shutdown is complete.
*/
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb);
UV_EXTERN int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle,
uv_shutdown_cb cb);
struct uv_shutdown_s {
UV_REQ_FIELDS
@ -320,7 +342,7 @@ struct uv_handle_s {
* Returns 1 if the prepare/check/idle handle has been started, 0 otherwise.
* For other handle types this always returns 1.
*/
int uv_is_active(uv_handle_t* handle);
UV_EXTERN int uv_is_active(uv_handle_t* handle);
/*
* Request handle to be closed. close_cb will be called asynchronously after
@ -330,7 +352,7 @@ int uv_is_active(uv_handle_t* handle);
* close_cb will still be deferred to the next iteration of the event loop.
* It gives you a chance to free up any resources associated with the handle.
*/
void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
/*
@ -339,7 +361,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
* base and len members of the uv_buf_t struct. The user is responsible for
* freeing base after the uv_buf_t is done. Return struct passed by value.
*/
uv_buf_t uv_buf_init(char* base, size_t len);
UV_EXTERN uv_buf_t uv_buf_init(char* base, size_t len);
#define UV_STREAM_FIELDS \
@ -364,7 +386,7 @@ struct uv_stream_s {
UV_STREAM_FIELDS
};
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
/*
* This call is used in conjunction with uv_listen() to accept incoming
@ -377,7 +399,7 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
* once, it may fail. It is suggested to only call uv_accept once per
* uv_connection_cb call.
*/
int uv_accept(uv_stream_t* server, uv_stream_t* client);
UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
/*
* Read data from an incoming stream. The callback will be made several
@ -389,15 +411,17 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client);
* eof; it happens when libuv requested a buffer through the alloc callback
* but then decided that it didn't need that buffer.
*/
int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb);
UV_EXTERN int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
int uv_read_stop(uv_stream_t*);
UV_EXTERN int uv_read_stop(uv_stream_t*);
/*
* Extended read methods for receiving handles over a pipe. The pipe must be
* initialized with ipc == 1.
*/
int uv_read2_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read2_cb read_cb);
UV_EXTERN int uv_read2_start(uv_stream_t*, uv_alloc_cb alloc_cb,
uv_read2_cb read_cb);
/*
@ -418,11 +442,11 @@ int uv_read2_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read2_cb read_cb);
* uv_write(req, stream, b, 2);
*
*/
int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
uv_write_cb cb);
UV_EXTERN int uv_write(uv_write_t* req, uv_stream_t* handle,
uv_buf_t bufs[], int bufcnt, uv_write_cb cb);
int uv_write2(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
uv_stream_t* send_handle, uv_write_cb cb);
UV_EXTERN int uv_write2(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[],
int bufcnt, uv_stream_t* send_handle, uv_write_cb cb);
/* uv_write_t is a subclass of uv_req_t */
struct uv_write_s {
@ -446,21 +470,34 @@ struct uv_tcp_s {
UV_TCP_PRIVATE_FIELDS
};
int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
/* Enable/disable Nagle's algorithm. */
int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
/* Enable/disable TCP keep-alive.
*
* `ms` is the initial delay in seconds, ignored when `enable` is zero.
*/
int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay);
UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, int enable,
unsigned int delay);
int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in);
int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6);
int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
/*
* This setting applies to Windows only.
* Enable/disable simultaneous asynchronous accept requests that are
* queued by the operating system when listening for new tcp connections.
* This setting is used to tune a tcp server for the desired performance.
* Having simultaneous accepts can significantly improve the rate of
* accepting connections (which is why it is enabled by default).
*/
UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in);
UV_EXTERN int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6);
UV_EXTERN int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name,
int* namelen);
UV_EXTERN int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name,
int* namelen);
/*
* uv_tcp_connect, uv_tcp_connect6
@ -468,9 +505,9 @@ int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
* initialized TCP handle and an uninitialized uv_connect_t*. The callback
* will be made when the connection is estabished.
*/
int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
UV_EXTERN int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
struct sockaddr_in address, uv_connect_cb cb);
int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
UV_EXTERN int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
struct sockaddr_in6 address, uv_connect_cb cb);
/* uv_connect_t is a subclass of uv_req_t */
@ -537,7 +574,7 @@ struct uv_udp_send_s {
* Initialize a new UDP handle. The actual socket is created lazily.
* Returns 0 on success.
*/
int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
/*
* Bind to a IPv4 address and port.
@ -550,7 +587,8 @@ int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
* Returns:
* 0 on success, -1 on error.
*/
int uv_udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned flags);
UV_EXTERN int uv_udp_bind(uv_udp_t* handle, struct sockaddr_in addr,
unsigned flags);
/*
* Bind to a IPv6 address and port.
@ -563,14 +601,17 @@ int uv_udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned flags);
* Returns:
* 0 on success, -1 on error.
*/
int uv_udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned flags);
int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen);
UV_EXTERN int uv_udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr,
unsigned flags);
UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name,
int* namelen);
/*
* Set membership for a multicast address
*
* Arguments:
* handle UDP handle. Should have been initialized with `uv_udp_init`.
* handle UDP handle. Should have been initialized with
* `uv_udp_init`.
* multicast_addr multicast address to set membership for
* interface_addr interface address
* membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP
@ -578,8 +619,9 @@ int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen);
* Returns:
* 0 on success, -1 on error.
*/
int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr,
const char* interface_addr, uv_membership membership);
UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
const char* multicast_addr, const char* interface_addr,
uv_membership membership);
/*
* Send data. If the socket has not previously been bound with `uv_udp_bind`
@ -597,8 +639,9 @@ int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr,
* Returns:
* 0 on success, -1 on error.
*/
int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
int bufcnt, struct sockaddr_in addr, uv_udp_send_cb send_cb);
UV_EXTERN int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle,
uv_buf_t bufs[], int bufcnt, struct sockaddr_in addr,
uv_udp_send_cb send_cb);
/*
* Send data. If the socket has not previously been bound with `uv_udp_bind6`,
@ -615,8 +658,9 @@ int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
* Returns:
* 0 on success, -1 on error.
*/
int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb send_cb);
UV_EXTERN int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle,
uv_buf_t bufs[], int bufcnt, struct sockaddr_in6 addr,
uv_udp_send_cb send_cb);
/*
* Receive data. If the socket has not previously been bound with `uv_udp_bind`
@ -631,7 +675,7 @@ int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
* Returns:
* 0 on success, -1 on error.
*/
int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
uv_udp_recv_cb recv_cb);
/*
@ -643,7 +687,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
* Returns:
* 0 on success, -1 on error.
*/
int uv_udp_recv_stop(uv_udp_t* handle);
UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
/*
@ -668,23 +712,23 @@ struct uv_tty_s {
*
* TTY streams which are not readable have blocking writes.
*/
int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
/*
* Set mode. 0 for normal, 1 for raw.
*/
int uv_tty_set_mode(uv_tty_t*, int mode);
UV_EXTERN int uv_tty_set_mode(uv_tty_t*, int mode);
/*
* To be called when the program exits. Resets TTY settings to default
* values for the next process to take over.
*/
void uv_tty_reset_mode();
UV_EXTERN void uv_tty_reset_mode();
/*
* Gets the current Window size. On success zero is returned.
*/
int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
/*
* Used to detect what type of stream should be used with a given file
@ -692,7 +736,7 @@ int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
* type of the stdio streams.
* For isatty() functionality use this function and test for UV_TTY.
*/
uv_handle_type uv_guess_handle(uv_file file);
UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
/*
* uv_pipe_t is a subclass of uv_stream_t
@ -711,16 +755,16 @@ struct uv_pipe_s {
* Initialize a pipe. The last argument is a boolean to indicate if
* this pipe will be used for handle passing between processes.
*/
int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
/*
* Opens an existing file descriptor or HANDLE as a pipe.
*/
void uv_pipe_open(uv_pipe_t*, uv_file file);
UV_EXTERN void uv_pipe_open(uv_pipe_t*, uv_file file);
int uv_pipe_bind(uv_pipe_t* handle, const char* name);
UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
const char* name, uv_connect_cb cb);
@ -736,11 +780,11 @@ struct uv_prepare_s {
UV_PREPARE_PRIVATE_FIELDS
};
int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare);
UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare);
int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb);
UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb);
int uv_prepare_stop(uv_prepare_t* prepare);
UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare);
/*
@ -754,11 +798,11 @@ struct uv_check_s {
UV_CHECK_PRIVATE_FIELDS
};
int uv_check_init(uv_loop_t*, uv_check_t* check);
UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check);
int uv_check_start(uv_check_t* check, uv_check_cb cb);
UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb);
int uv_check_stop(uv_check_t* check);
UV_EXTERN int uv_check_stop(uv_check_t* check);
/*
@ -774,11 +818,11 @@ struct uv_idle_s {
UV_IDLE_PRIVATE_FIELDS
};
int uv_idle_init(uv_loop_t*, uv_idle_t* idle);
UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle);
int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb);
UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb);
int uv_idle_stop(uv_idle_t* idle);
UV_EXTERN int uv_idle_stop(uv_idle_t* idle);
/*
@ -796,14 +840,15 @@ struct uv_async_s {
UV_ASYNC_PRIVATE_FIELDS
};
int uv_async_init(uv_loop_t*, uv_async_t* async, uv_async_cb async_cb);
UV_EXTERN int uv_async_init(uv_loop_t*, uv_async_t* async,
uv_async_cb async_cb);
/*
* This can be called from other threads to wake up a libuv thread.
*
* libuv is single threaded at the moment.
*/
int uv_async_send(uv_async_t* async);
UV_EXTERN int uv_async_send(uv_async_t* async);
/*
@ -817,19 +862,19 @@ struct uv_timer_s {
UV_TIMER_PRIVATE_FIELDS
};
int uv_timer_init(uv_loop_t*, uv_timer_t* timer);
UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* timer);
int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout,
int64_t repeat);
UV_EXTERN int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb,
int64_t timeout, int64_t repeat);
int uv_timer_stop(uv_timer_t* timer);
UV_EXTERN int uv_timer_stop(uv_timer_t* timer);
/*
* Stop the timer, and if it is repeating restart it using the repeat value
* as the timeout. If the timer has never been started before it returns -1 and
* sets the error to UV_EINVAL.
*/
int uv_timer_again(uv_timer_t* timer);
UV_EXTERN int uv_timer_again(uv_timer_t* timer);
/*
* Set the repeat value. Note that if the repeat value is set from a timer
@ -837,19 +882,17 @@ int uv_timer_again(uv_timer_t* timer);
* before, it will have been stopped. If it was repeating, then the old repeat
* value will have been used to schedule the next timeout.
*/
void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat);
UV_EXTERN void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat);
int64_t uv_timer_get_repeat(uv_timer_t* timer);
UV_EXTERN int64_t uv_timer_get_repeat(uv_timer_t* timer);
/* c-ares integration initialize and terminate */
int uv_ares_init_options(uv_loop_t*,
ares_channel *channelptr,
struct ares_options *options,
int optmask);
UV_EXTERN int uv_ares_init_options(uv_loop_t*,
ares_channel *channelptr, struct ares_options *options, int optmask);
/* TODO remove the loop argument from this function? */
void uv_ares_destroy(uv_loop_t*, ares_channel channel);
UV_EXTERN void uv_ares_destroy(uv_loop_t*, ares_channel channel);
/*
@ -877,14 +920,11 @@ struct uv_getaddrinfo_s {
*
* On error NXDOMAIN the status code will be non-zero and UV_ENOENT returned.
*/
int uv_getaddrinfo(uv_loop_t*,
uv_getaddrinfo_t* handle,
uv_getaddrinfo_cb getaddrinfo_cb,
const char* node,
const char* service,
const struct addrinfo* hints);
UV_EXTERN int uv_getaddrinfo(uv_loop_t*, uv_getaddrinfo_t* handle,
uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service,
const struct addrinfo* hints);
void uv_freeaddrinfo(struct addrinfo* ai);
UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
/* uv_spawn() options */
typedef struct uv_process_options_s {
@ -934,13 +974,18 @@ struct uv_process_s {
};
/* Initializes uv_process_t and starts the process. */
int uv_spawn(uv_loop_t*, uv_process_t*, uv_process_options_t options);
UV_EXTERN int uv_spawn(uv_loop_t*, uv_process_t*,
uv_process_options_t options);
/*
* Kills the process with the specified signal. The user must still
* call uv_close on the process.
*/
int uv_process_kill(uv_process_t*, int signum);
UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
/* Kills the process with the specified signal. */
UV_EXTERN uv_err_t uv_kill(int pid, int signum);
/*
@ -955,8 +1000,8 @@ struct uv_work_s {
};
/* Queues a work request to execute asynchronously on the thread pool. */
int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb,
uv_after_work_cb after_work_cb);
UV_EXTERN int uv_queue_work(uv_loop_t* loop, uv_work_t* req,
uv_work_cb work_cb, uv_after_work_cb after_work_cb);
@ -1018,58 +1063,66 @@ struct uv_fs_s {
UV_FS_PRIVATE_FIELDS
};
void uv_fs_req_cleanup(uv_fs_t* req);
UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
UV_EXTERN int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file,
uv_fs_cb cb);
int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
UV_EXTERN int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path,
int flags, int mode, uv_fs_cb cb);
UV_EXTERN int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file,
void* buf, size_t length, off_t offset, uv_fs_cb cb);
UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb);
UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file,
void* buf, size_t length, off_t offset, uv_fs_cb cb);
UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path,
int mode, uv_fs_cb cb);
int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
size_t length, off_t offset, uv_fs_cb cb);
int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
size_t length, off_t offset, uv_fs_cb cb);
int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb);
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
UV_EXTERN int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req,
const char* path, int flags, uv_fs_cb cb);
int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
UV_EXTERN int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb);
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
UV_EXTERN int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file,
uv_fs_cb cb);
int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
UV_EXTERN int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb);
int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file,
off_t offset, uv_fs_cb cb);
int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd,
uv_file in_fd, off_t in_offset, size_t length, uv_fs_cb cb);
int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
UV_EXTERN int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file,
uv_fs_cb cb);
int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
double mtime, uv_fs_cb cb);
UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file,
uv_fs_cb cb);
int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
double mtime, uv_fs_cb cb);
UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file,
off_t offset, uv_fs_cb cb);
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd,
uv_file in_fd, off_t in_offset, size_t length, uv_fs_cb cb);
int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path,
int mode, uv_fs_cb cb);
UV_EXTERN int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path,
double atime, double mtime, uv_fs_cb cb);
UV_EXTERN int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file,
double atime, double mtime, uv_fs_cb cb);
UV_EXTERN int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb);
UV_EXTERN int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb);
/*
@ -1078,20 +1131,20 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
*/
#define UV_FS_SYMLINK_DIR 0x0001
int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, int flags, uv_fs_cb cb);
int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb);
int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode,
uv_fs_cb cb);
UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file,
int mode, uv_fs_cb cb);
int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid,
int gid, uv_fs_cb cb);
UV_EXTERN int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path,
int uid, int gid, uv_fs_cb cb);
int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid,
int gid, uv_fs_cb cb);
UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file,
int uid, int gid, uv_fs_cb cb);
enum uv_fs_event {
@ -1112,32 +1165,52 @@ struct uv_fs_event_s {
* See: http://en.wikipedia.org/wiki/Load_(computing)
* (Returns [0,0,0] for windows and cygwin)
*/
void uv_loadavg(double avg[3]);
UV_EXTERN void uv_loadavg(double avg[3]);
/*
* If filename is a directory then we will watch for all events in that
* directory. If filename is a file - we will only get events from that
* file. Subdirectories are not watched.
*/
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
const char* filename, uv_fs_event_cb cb);
* Flags to be passed to uv_fs_event_init.
*/
enum uv_fs_event_flags {
/*
* By default, if the fs event watcher is given a directory name, we will
* watch for all events in that directory. This flags overrides this behavior
* and makes fs_event report only changes to the directory entry itself. This
* flag does not affect individual files watched.
* This flag is currently not implemented yet on any backend.
*/
UV_FS_EVENT_WATCH_ENTRY = 1,
/*
* By default uv_fs_event will try to use a kernel interface such as inotify
* or kqueue to detect events. This may not work on remote filesystems such
* as NFS mounts. This flag makes fs_event fall back to calling stat() on a
* regular interval.
* This flag is currently not implemented yet on any backend.
*/
UV_FS_EVENT_STAT = 2
};
UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
const char* filename, uv_fs_event_cb cb, int flags);
/* Utility */
/* Convert string ip addresses to binary structures */
struct sockaddr_in uv_ip4_addr(const char* ip, int port);
struct sockaddr_in6 uv_ip6_addr(const char* ip, int port);
UV_EXTERN struct sockaddr_in uv_ip4_addr(const char* ip, int port);
UV_EXTERN struct sockaddr_in6 uv_ip6_addr(const char* ip, int port);
/* Convert binary addresses to strings */
int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size);
int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size);
UV_EXTERN int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size);
UV_EXTERN int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size);
/* Gets the executable path */
int uv_exepath(char* buffer, size_t* size);
UV_EXTERN int uv_exepath(char* buffer, size_t* size);
/* Gets memory info in bytes */
uint64_t uv_get_free_memory(void);
uint64_t uv_get_total_memory(void);
UV_EXTERN uint64_t uv_get_free_memory(void);
UV_EXTERN uint64_t uv_get_total_memory(void);
/*
* Returns the current high-resolution real time. This is expressed in
@ -1148,7 +1221,20 @@ uint64_t uv_get_total_memory(void);
* Note not every platform can support nanosecond resolution; however, this
* value will always be in nanoseconds.
*/
extern uint64_t uv_hrtime(void);
UV_EXTERN extern uint64_t uv_hrtime(void);
/*
* Opens a shared library. The filename is in utf-8. On success, -1 is
* and the variable pointed by library receives a handle to the library.
*/
UV_EXTERN uv_err_t uv_dlopen(const char* filename, uv_lib_t* library);
UV_EXTERN uv_err_t uv_dlclose(uv_lib_t library);
/*
* Retrieves a data pointer from a dynamic library.
*/
UV_EXTERN uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr);
/* the presence of these unions force similar struct layout */

View file

@ -4,9 +4,6 @@
/* when building c-ares library */
#define CARES_BUILDING_LIBRARY 1
/* when not building a shared library */
#define CARES_STATICLIB 1
/* Copyright (C) 2004 - 2008 by Daniel Stenberg et al
*
* Permission to use, copy, modify, and distribute this software and its

View file

@ -38,18 +38,22 @@
#include <limits.h> /* PATH_MAX */
#include <sys/uio.h> /* writev */
#ifdef __linux__
# include <sys/ioctl.h>
#endif
#ifdef __sun
# include <sys/types.h>
# include <sys/wait.h>
#endif
#if defined(__APPLE__)
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
#ifdef __APPLE__
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
#endif
#if defined(__FreeBSD__)
#include <sys/sysctl.h>
#include <sys/wait.h>
#ifdef __FreeBSD__
# include <sys/sysctl.h>
# include <sys/wait.h>
#endif
static uv_loop_t default_loop_struct;
@ -154,7 +158,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
}
uv_loop_t* uv_loop_new() {
uv_loop_t* uv_loop_new(void) {
uv_loop_t* loop = calloc(1, sizeof(uv_loop_t));
loop->ev = ev_loop_new(0);
ev_set_userdata(loop->ev, loop);
@ -169,7 +173,7 @@ void uv_loop_delete(uv_loop_t* loop) {
}
uv_loop_t* uv_default_loop() {
uv_loop_t* uv_default_loop(void) {
if (!default_loop_ptr) {
default_loop_ptr = &default_loop_struct;
#if HAVE_KQUEUE
@ -593,9 +597,17 @@ static int uv_getaddrinfo_done(eio_req* req) {
free(handle->service);
free(handle->hostname);
if (handle->retcode != 0) {
/* TODO how to display gai error strings? */
uv__set_sys_error(handle->loop, handle->retcode);
if (handle->retcode == 0) {
/* OK */
#if EAI_NODATA /* FreeBSD deprecated EAI_NODATA */
} else if (handle->retcode == EAI_NONAME || handle->retcode == EAI_NODATA) {
#else
} else if (handle->retcode == EAI_NONAME) {
#endif
uv__set_sys_error(handle->loop, ENOENT); /* FIXME compatibility hack */
} else {
handle->loop->last_err.code = UV_EADDRINFO;
handle->loop->last_err.sys_errno_ = handle->retcode;
}
handle->cb(handle, handle->retcode, res);
@ -734,6 +746,9 @@ int uv__close(int fd) {
int uv__nonblock(int fd, int set) {
#if FIONBIO
return ioctl(fd, FIONBIO, &set);
#else
int flags;
if ((flags = fcntl(fd, F_GETFL)) == -1) {
@ -751,10 +766,17 @@ int uv__nonblock(int fd, int set) {
}
return 0;
#endif
}
int uv__cloexec(int fd, int set) {
#if __linux__
/* Linux knows only FD_CLOEXEC so we can safely omit the fcntl(F_GETFD)
* syscall. CHECKME: That's probably true for other Unices as well.
*/
return fcntl(fd, F_SETFD, set ? FD_CLOEXEC : 0);
#else
int flags;
if ((flags = fcntl(fd, F_GETFD)) == -1) {
@ -772,6 +794,7 @@ int uv__cloexec(int fd, int set) {
}
return 0;
#endif
}

View file

@ -69,7 +69,8 @@ uint64_t uv_get_total_memory(void) {
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb) {
uv_fs_event_cb cb,
int flags) {
uv__set_sys_error(loop, ENOSYS);
return -1;
}

View file

@ -0,0 +1,57 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <dlfcn.h>
#include <errno.h>
uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) {
void* handle = dlopen(filename, RTLD_LAZY);
if (handle == NULL) {
return uv__new_sys_error(errno);
}
*library = handle;
return uv_ok_;
}
uv_err_t uv_dlclose(uv_lib_t library) {
if (dlclose(library) != 0) {
return uv__new_sys_error(errno);
}
return uv_ok_;
}
uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) {
void* address = dlsym(library, name);
if (address == NULL) {
return uv__new_sys_error(errno);
}
*ptr = (void*) address;
return uv_ok_;
}

View file

@ -59,8 +59,10 @@ void uv_fatal_error(const int errorno, const char* syscall) {
static int uv__translate_lib_error(int code) {
switch (code) {
case UV_ENOSYS: return ENOSYS;
case UV_ENOTSOCK: return ENOTSOCK;
case UV_ENOENT: return ENOENT;
case UV_EACCESS: return EACCES;
case UV_EACCES: return EACCES;
case UV_EAFNOSUPPORT: return EAFNOSUPPORT;
case UV_EBADF: return EBADF;
case UV_EPIPE: return EPIPE;
case UV_EAGAIN: return EAGAIN;
@ -73,8 +75,10 @@ static int uv__translate_lib_error(int code) {
case UV_EADDRINUSE: return EADDRINUSE;
case UV_EADDRNOTAVAIL: return EADDRNOTAVAIL;
case UV_ENOTDIR: return ENOTDIR;
case UV_EISDIR: return EISDIR;
case UV_ENOTCONN: return ENOTCONN;
case UV_EEXIST: return EEXIST;
case UV_EHOSTUNREACH: return EHOSTUNREACH;
default: return -1;
}
@ -87,8 +91,10 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
switch (sys_errno) {
case 0: return UV_OK;
case ENOSYS: return UV_ENOSYS;
case ENOTSOCK: return UV_ENOTSOCK;
case ENOENT: return UV_ENOENT;
case EACCES: return UV_EACCESS;
case EACCES: return UV_EACCES;
case EAFNOSUPPORT: return UV_EAFNOSUPPORT;
case EBADF: return UV_EBADF;
case EPIPE: return UV_EPIPE;
case EAGAIN: return UV_EAGAIN;
@ -101,8 +107,10 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case EADDRINUSE: return UV_EADDRINUSE;
case EADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
case ENOTDIR: return UV_ENOTDIR;
case EISDIR: return UV_EISDIR;
case ENOTCONN: return UV_ENOTCONN;
case EEXIST: return UV_EEXIST;
case EHOSTUNREACH: return UV_EHOSTUNREACH;
case EAI_NONAME: return UV_ENOENT;
default: return UV_UNKNOWN;
}
@ -116,7 +124,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
* a) rely on what the system provides us
* b) reverse-map the error codes
*/
char* uv_strerror(uv_err_t err) {
const char* uv_strerror(uv_err_t err) {
int errorno;
if (err.sys_errno_)
@ -124,6 +132,9 @@ char* uv_strerror(uv_err_t err) {
else
errorno = uv__translate_lib_error(err.code);
if (err.code == UV_EADDRINFO)
return gai_strerror(errorno);
if (errorno == -1)
return "Unknown error";
else

View file

@ -225,7 +225,7 @@ epoll_init (EV_P_ int flags)
#ifdef EPOLL_CLOEXEC
backend_fd = epoll_create1 (EPOLL_CLOEXEC);
if (backend_fd <= 0)
if (backend_fd < 0)
#endif
backend_fd = epoll_create (256);

View file

@ -86,9 +86,13 @@ void uv__kqueue_hack(EV_P_ int fflags, ev_io *w) {
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb) {
uv_fs_event_cb cb,
int flags) {
int fd;
/* We don't support any flags yet. */
assert(!flags);
if (cb == NULL) {
uv__set_sys_error(loop, EINVAL);
return -1;
@ -122,7 +126,8 @@ void uv__fs_event_destroy(uv_fs_event_t* handle) {
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb) {
uv_fs_event_cb cb,
int flags) {
uv__set_sys_error(loop, ENOSYS);
return -1;
}

View file

@ -156,10 +156,14 @@ static void uv__inotify_read(EV_P_ ev_io* w, int revents) {
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb) {
int flags;
uv_fs_event_cb cb,
int flags) {
int events;
int fd;
/* We don't support any flags yet. */
assert(!flags);
/*
* TODO share a single inotify fd across the event loop?
* We'll run into fs.inotify.max_user_instances if we
@ -170,15 +174,15 @@ int uv_fs_event_init(uv_loop_t* loop,
return -1;
}
flags = IN_ATTRIB
| IN_CREATE
| IN_MODIFY
| IN_DELETE
| IN_DELETE_SELF
| IN_MOVED_FROM
| IN_MOVED_TO;
events = IN_ATTRIB
| IN_CREATE
| IN_MODIFY
| IN_DELETE
| IN_DELETE_SELF
| IN_MOVED_FROM
| IN_MOVED_TO;
if (inotify_add_watch(fd, filename, flags) == -1) {
if (inotify_add_watch(fd, filename, events) == -1) {
uv__set_sys_error(loop, errno);
uv__close(fd);
return -1;

View file

@ -177,7 +177,7 @@ void uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
}
int uv_pipe_connect(uv_connect_t* req,
void uv_pipe_connect(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
uv_connect_cb cb) {
@ -209,7 +209,7 @@ int uv_pipe_connect(uv_connect_t* req,
while (r == -1 && errno == EINTR);
if (r == -1) {
uv__set_sys_error(handle->loop, errno);
status = errno;
uv__close(sockfd);
goto out;
}
@ -237,7 +237,6 @@ out:
* return 0 and let the callback handle errors.
*/
errno = saved_errno;
return 0;
}

View file

@ -300,3 +300,14 @@ int uv_process_kill(uv_process_t* process, int signum) {
return 0;
}
}
uv_err_t uv_kill(int pid, int signum) {
int r = kill(pid, signum);
if (r) {
return uv__new_sys_error(errno);
} else {
return uv_ok_;
}
}

View file

@ -62,6 +62,7 @@ void uv__stream_init(uv_loop_t* loop,
stream->accepted_fd = -1;
stream->fd = -1;
stream->delayed_error = 0;
stream->blocking = 0;
ngx_queue_init(&stream->write_queue);
ngx_queue_init(&stream->write_completed_queue);
stream->write_queue_size = 0;
@ -340,9 +341,9 @@ static void uv__write(uv_stream_t* stream) {
int iovcnt;
ssize_t n;
assert(stream->fd >= 0);
start:
/* TODO: should probably while(1) here until EAGAIN */
assert(stream->fd >= 0);
/* Get the request at the head of the queue. */
req = uv_write_queue_head(stream);
@ -353,14 +354,16 @@ static void uv__write(uv_stream_t* stream) {
assert(req->handle == stream);
/* Cast to iovec. We had to have our own uv_buf_t instead of iovec
/*
* Cast to iovec. We had to have our own uv_buf_t instead of iovec
* because Windows's WSABUF is not an iovec.
*/
assert(sizeof(uv_buf_t) == sizeof(struct iovec));
iov = (struct iovec*) &(req->bufs[req->write_index]);
iovcnt = req->bufcnt - req->write_index;
/* Now do the actual writev. Note that we've been updating the pointers
/*
* Now do the actual writev. Note that we've been updating the pointers
* inside the iov each time we write. So there is no need to offset it.
*/
@ -409,6 +412,9 @@ static void uv__write(uv_stream_t* stream) {
stream->write_queue_size -= uv__write_req_size(req);
uv__write_req_finish(req);
return;
} else if (stream->blocking) {
/* If this is a blocking stream, try again. */
goto start;
}
} else {
/* Successful write */
@ -426,8 +432,17 @@ static void uv__write(uv_stream_t* stream) {
stream->write_queue_size -= n;
n = 0;
/* There is more to write. Break and ensure the watcher is pending. */
break;
/* There is more to write. */
if (stream->blocking) {
/*
* If we're blocking then we should not be enabling the write
* watcher - instead we need to try again.
*/
goto start;
} else {
/* Break loop and ensure the watcher is pending. */
break;
}
} else {
/* Finished writing the buf at index req->write_index. */
@ -453,6 +468,9 @@ static void uv__write(uv_stream_t* stream) {
/* Either we've counted n down to zero or we've got EAGAIN. */
assert(n == 0 || n == -1);
/* Only non-blocking streams should use the write_watcher. */
assert(!stream->blocking);
/* We're not done. */
ev_io_start(stream->loop->ev, &stream->write_watcher);
}
@ -862,6 +880,13 @@ int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
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);
}

View file

@ -23,13 +23,17 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/loadavg.h>
#include <sys/time.h>
#include <sys/port.h>
#include <unistd.h>
#include <kstat.h>
#include <port.h>
uint64_t uv_hrtime() {
@ -81,15 +85,91 @@ void uv_loadavg(double avg[3]) {
}
static void uv__fs_event_rearm(uv_fs_event_t *handle) {
if (port_associate(handle->fd,
PORT_SOURCE_FILE,
(uintptr_t) &handle->fo,
FILE_ATTRIB | FILE_MODIFIED,
NULL) == -1) {
uv__set_sys_error(handle->loop, errno);
}
}
static void uv__fs_event_read(EV_P_ ev_io* w, int revents) {
uv_fs_event_t *handle;
timespec_t timeout;
port_event_t pe;
int events;
int r;
handle = container_of(w, uv_fs_event_t, event_watcher);
do {
/* TODO use port_getn() */
do {
memset(&timeout, 0, sizeof timeout);
r = port_get(handle->fd, &pe, &timeout);
}
while (r == -1 && errno == EINTR);
if (r == -1 && errno == ETIME)
break;
assert((r == 0) && "unexpected port_get() error");
events = 0;
if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
events |= UV_CHANGE;
if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
events |= UV_RENAME;
assert(events != 0);
handle->cb(handle, NULL, events, 0);
}
while (handle->fd != -1);
if (handle->fd != -1)
uv__fs_event_rearm(handle);
}
int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_t* handle,
const char* filename,
uv_fs_event_cb cb) {
uv__set_sys_error(loop, ENOSYS);
return -1;
uv_fs_event_cb cb,
int flags) {
int portfd;
/* We don't support any flags yet. */
assert(!flags);
if ((portfd = port_create()) == -1) {
uv__set_sys_error(loop, errno);
return -1;
}
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
handle->filename = strdup(filename);
handle->fd = portfd;
handle->cb = cb;
memset(&handle->fo, 0, sizeof handle->fo);
handle->fo.fo_name = handle->filename;
uv__fs_event_rearm(handle);
ev_io_init(&handle->event_watcher, uv__fs_event_read, portfd, EV_READ);
ev_io_start(loop->ev, &handle->event_watcher);
return 0;
}
void uv__fs_event_destroy(uv_fs_event_t* handle) {
assert(0 && "implement me");
ev_io_stop(handle->loop->ev, &handle->event_watcher);
uv__close(handle->fd);
handle->fd = -1;
free(handle->filename);
handle->filename = NULL;
handle->fo.fo_name = NULL;
}

View file

@ -319,3 +319,8 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
return 0;
}
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
return 0;
}

View file

@ -41,7 +41,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
uv__stream_open((uv_stream_t*)tty, fd, UV_READABLE);
} else {
/* Note: writable tty we set to blocking mode. */
uv__nonblock(fd, 0);
uv__stream_open((uv_stream_t*)tty, fd, UV_WRITABLE);
tty->blocking = 1;
}

View file

@ -48,12 +48,16 @@ uv_buf_t uv_buf_init(char* base, size_t len) {
}
const uv_err_t uv_ok_ = { UV_OK, 0 };
const char* uv_err_name(uv_err_t err) {
switch (err.code) {
case UV_UNKNOWN: return "UNKNOWN";
case UV_OK: return "OK";
case UV_EOF: return "EOF";
case UV_EACCESS: return "EACCESS";
case UV_EADDRINFO: return "EADDRINFO";
case UV_EACCES: return "EACCES";
case UV_EAGAIN: return "EAGAIN";
case UV_EADDRINUSE: return "EADDRINUSE";
case UV_EADDRNOTAVAIL: return "EADDRNOTAVAIL";
@ -71,6 +75,7 @@ const char* uv_err_name(uv_err_t err) {
case UV_EINVAL: return "EINVAL";
case UV_EISCONN: return "EISCONN";
case UV_EMFILE: return "EMFILE";
case UV_EMSGSIZE: return "EMSGSIZE";
case UV_ENETDOWN: return "ENETDOWN";
case UV_ENETUNREACH: return "ENETUNREACH";
case UV_ENFILE: return "ENFILE";
@ -89,6 +94,12 @@ const char* uv_err_name(uv_err_t err) {
case UV_EPROTONOSUPPORT: return "EPROTONOSUPPORT";
case UV_EPROTOTYPE: return "EPROTOTYPE";
case UV_ETIMEDOUT: return "ETIMEDOUT";
case UV_ECHARSET: return "ECHARSET";
case UV_EAIFAMNOSUPPORT: return "EAIFAMNOSUPPORT";
case UV_EAINONAME: return "EAINONAME";
case UV_EAISERVICE: return "EAISERVICE";
case UV_EAISOCKTYPE: return "EAISOCKTYPE";
case UV_ESHUTDOWN: return "ESHUTDOWN";
case UV_EEXIST: return "EEXIST";
default:
assert(0);
@ -115,6 +126,14 @@ void uv__set_artificial_error(uv_loop_t* loop, uv_err_code code) {
}
uv_err_t uv__new_sys_error(int sys_error) {
uv_err_t error;
error.code = uv_translate_sys_error(sys_error);
error.sys_errno_ = sys_error;
return error;
}
uv_err_t uv_last_error(uv_loop_t* loop) {
return loop->last_err;
}

View file

@ -48,10 +48,13 @@ void uv_add_ares_handle(uv_loop_t* loop, uv_ares_task_t* handle);
int uv_ares_handles_empty(uv_loop_t* loop);
extern const uv_err_t uv_ok_;
uv_err_code uv_translate_sys_error(int sys_errno);
void uv__set_error(uv_loop_t* loop, uv_err_code code, int sys_error);
void uv__set_sys_error(uv_loop_t* loop, int sys_error);
void uv__set_artificial_error(uv_loop_t* loop, uv_err_code code);
uv_err_t uv__new_sys_error(int sys_error);
int uv__tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr);
int uv__tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr);

View file

@ -40,6 +40,10 @@ static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
static void uv_init(void) {
/* Tell Windows that we will handle critical errors. */
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
/* Initialize winsock */
uv_winsock_init();
@ -95,12 +99,23 @@ static void uv_default_loop_init(void) {
}
uv_loop_t* uv_default_loop() {
uv_loop_t* uv_default_loop(void) {
uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
return &uv_default_loop_;
}
uv_loop_t* uv_loop_new(void) {
assert(0 && "implement me");
return NULL;
}
void uv_loop_delete(uv_loop_t* loop) {
assert(0 && "implement me");
}
void uv_ref(uv_loop_t* loop) {
loop->refs++;
}
@ -147,7 +162,7 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
BOOL success;
DWORD timeout;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[64];
OVERLAPPED_ENTRY overlappeds[128];
ULONG count;
ULONG i;

63
src/rt/libuv/src/win/dl.c Normal file
View file

@ -0,0 +1,63 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) {
wchar_t filename_w[32768];
HMODULE handle;
if (!uv_utf8_to_utf16(filename,
filename_w,
sizeof(filename_w) / sizeof(wchar_t))) {
return uv__new_sys_error(GetLastError());
}
handle = LoadLibraryW(filename_w);
if (handle == NULL) {
return uv__new_sys_error(GetLastError());
}
*library = handle;
return uv_ok_;
}
uv_err_t uv_dlclose(uv_lib_t library) {
if (!FreeLibrary(library)) {
return uv__new_sys_error(GetLastError());
}
return uv_ok_;
}
uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) {
FARPROC proc = GetProcAddress(library, name);
if (proc == NULL) {
return uv__new_sys_error(GetLastError());
}
*ptr = (void*) proc;
return uv_ok_;
}

View file

@ -30,9 +30,6 @@
#include "internal.h"
const uv_err_t uv_ok_ = { UV_OK, ERROR_SUCCESS };
/*
* Display an error message and abort the event loop.
*/
@ -70,7 +67,7 @@ void uv_fatal_error(const int errorno, const char* syscall) {
/* TODO: thread safety */
static char* last_err_str_ = NULL;
char* uv_strerror(uv_err_t err) {
const char* uv_strerror(uv_err_t err) {
if (last_err_str_ != NULL) {
LocalFree(last_err_str_);
}
@ -93,8 +90,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case ERROR_SUCCESS: return UV_OK;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
case ERROR_NOACCESS: return UV_EACCESS;
case WSAEACCES: return UV_EACCESS;
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;

View file

@ -133,12 +133,15 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir,
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
const char* filename, uv_fs_event_cb cb) {
const char* filename, uv_fs_event_cb cb, int flags) {
int name_size;
DWORD attr, last_error;
wchar_t* dir = NULL, *dir_to_watch, *filenamew;
wchar_t short_path[MAX_PATH];
/* We don't support any flags yet. */
assert(!flags);
uv_fs_event_init_handle(loop, handle, filename, cb);
/* Convert name to UTF16. */
@ -353,7 +356,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
offset = file_info->NextEntryOffset;
} while(offset);
} else {
handle->cb(handle, NULL, UV_CHANGE, 0);
if (!(handle->flags & UV_HANDLE_CLOSING)) {
handle->cb(handle, NULL, UV_CHANGE, 0);
}
}
} else {
uv__set_sys_error(loop, GET_REQ_ERROR(req));

View file

@ -173,19 +173,24 @@ void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) {
/* convert flags and mode to CreateFile parameters */
switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
case _O_RDONLY:
access = GENERIC_READ;
access = FILE_GENERIC_READ;
break;
case _O_WRONLY:
access = GENERIC_WRITE;
access = FILE_GENERIC_WRITE;
break;
case _O_RDWR:
access = GENERIC_READ | GENERIC_WRITE;
access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
break;
default:
result = -1;
goto end;
}
if (flags & _O_APPEND) {
access &= ~FILE_WRITE_DATA;
access |= FILE_APPEND_DATA;
}
/*
* Here is where we deviate significantly from what CRT's _open()
* does. We indiscriminately use all the sharing modes, to match

View file

@ -44,30 +44,35 @@ void uv_process_timers(uv_loop_t* loop);
*/
/* Private uv_handle flags */
#define UV_HANDLE_CLOSING 0x000001
#define UV_HANDLE_CLOSED 0x000002
#define UV_HANDLE_BOUND 0x000004
#define UV_HANDLE_LISTENING 0x000008
#define UV_HANDLE_CONNECTION 0x000010
#define UV_HANDLE_CONNECTED 0x000020
#define UV_HANDLE_READING 0x000040
#define UV_HANDLE_ACTIVE 0x000040
#define UV_HANDLE_EOF 0x000080
#define UV_HANDLE_SHUTTING 0x000100
#define UV_HANDLE_SHUT 0x000200
#define UV_HANDLE_ENDGAME_QUEUED 0x000400
#define UV_HANDLE_BIND_ERROR 0x001000
#define UV_HANDLE_IPV6 0x002000
#define UV_HANDLE_PIPESERVER 0x004000
#define UV_HANDLE_READ_PENDING 0x008000
#define UV_HANDLE_UV_ALLOCED 0x010000
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x020000
#define UV_HANDLE_ZERO_READ 0x040000
#define UV_HANDLE_TTY_RAW 0x080000
#define UV_HANDLE_EMULATE_IOCP 0x100000
#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x200000
#define UV_HANDLE_TTY_SAVED_POSITION 0x400000
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x800000
#define UV_HANDLE_CLOSING 0x00000001
#define UV_HANDLE_CLOSED 0x00000002
#define UV_HANDLE_BOUND 0x00000004
#define UV_HANDLE_LISTENING 0x00000008
#define UV_HANDLE_CONNECTION 0x00000010
#define UV_HANDLE_CONNECTED 0x00000020
#define UV_HANDLE_READING 0x00000040
#define UV_HANDLE_ACTIVE 0x00000040
#define UV_HANDLE_EOF 0x00000080
#define UV_HANDLE_SHUTTING 0x00000100
#define UV_HANDLE_SHUT 0x00000200
#define UV_HANDLE_ENDGAME_QUEUED 0x00000400
#define UV_HANDLE_BIND_ERROR 0x00001000
#define UV_HANDLE_IPV6 0x00002000
#define UV_HANDLE_PIPESERVER 0x00004000
#define UV_HANDLE_READ_PENDING 0x00008000
#define UV_HANDLE_UV_ALLOCED 0x00010000
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00020000
#define UV_HANDLE_ZERO_READ 0x00040000
#define UV_HANDLE_TTY_RAW 0x00080000
#define UV_HANDLE_EMULATE_IOCP 0x00100000
#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x00200000
#define UV_HANDLE_TTY_SAVED_POSITION 0x00400000
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x00800000
#define UV_HANDLE_SHARED_TCP_SERVER 0x01000000
#define UV_HANDLE_TCP_NODELAY 0x02000000
#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle);
void uv_process_endgames(uv_loop_t* loop);
@ -140,6 +145,9 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info);
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
LPWSAPROTOCOL_INFOW protocol_info);
/*
* UDP
@ -278,11 +286,6 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
int uv_parent_pid();
/*
* Error handling
*/
extern const uv_err_t uv_ok_;
void uv_fatal_error(const int errorno, const char* syscall);
uv_err_code uv_translate_sys_error(int sys_errno);

View file

@ -362,7 +362,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
if (errno == ERROR_ACCESS_DENIED) {
uv__set_error(loop, UV_EADDRINUSE, errno);
} else if (errno == ERROR_PATH_NOT_FOUND || errno == ERROR_INVALID_NAME) {
uv__set_error(loop, UV_EACCESS, errno);
uv__set_error(loop, UV_EACCES, errno);
} else {
uv__set_sys_error(loop, errno);
}
@ -443,7 +443,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
}
int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
const char* name, uv_connect_cb cb) {
uv_loop_t* loop = handle->loop;
int errno, nameSize;
@ -488,7 +488,7 @@ int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
handle->reqs_pending++;
return 0;
return;
}
errno = GetLastError();
@ -505,7 +505,7 @@ int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
SET_REQ_SUCCESS(req);
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
return 0;
return;
error:
if (handle->name) {
@ -516,8 +516,12 @@ error:
if (pipeHandle != INVALID_HANDLE_VALUE) {
CloseHandle(pipeHandle);
}
uv__set_sys_error(loop, errno);
return -1;
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, errno);
uv_insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++;
return;
}
@ -956,7 +960,9 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
return -1;
}
if (send_handle && send_handle->type != UV_TCP) {
/* Only TCP server handles are supported for sharing. */
if (send_handle && (send_handle->type != UV_TCP ||
send_handle->flags & UV_HANDLE_CONNECTION)) {
uv__set_artificial_error(loop, UV_ENOTSUP);
return -1;
}
@ -989,9 +995,9 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
/* Use the IPC framing protocol. */
if (send_handle) {
tcp_send_handle = (uv_tcp_t*)send_handle;
if (WSADuplicateSocketW(tcp_send_handle->socket, handle->ipc_pid,
if (uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid,
&ipc_frame.socket_info)) {
uv__set_sys_error(loop, WSAGetLastError());
return -1;
}
ipc_frame.header.flags |= UV_IPC_UV_STREAM;

View file

@ -26,8 +26,11 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <signal.h>
#include <windows.h>
#define SIGKILL 9
typedef struct env_var {
const char* narrow;
const wchar_t* wide;
@ -265,6 +268,8 @@ static wchar_t* search_path(const wchar_t *file,
wchar_t* result = NULL;
wchar_t *file_name_start;
wchar_t *dot;
const wchar_t *dir_start, *dir_end, *dir_path;
int dir_len;
int name_has_ext;
int file_len = wcslen(file);
@ -302,8 +307,7 @@ static wchar_t* search_path(const wchar_t *file,
name_has_ext);
} else {
const wchar_t *dir_start,
*dir_end = path;
dir_end = path;
/* The file is really only a name; look in cwd first, then scan path */
result = path_search_walk_ext(L"", 0,
@ -335,7 +339,20 @@ static wchar_t* search_path(const wchar_t *file,
continue;
}
result = path_search_walk_ext(dir_start, dir_end - dir_start,
dir_path = dir_start;
dir_len = dir_end - dir_start;
/* Adjust if the path is quoted. */
if (dir_path[0] == '"' || dir_path[0] == '\'') {
++dir_path;
--dir_len;
}
if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
--dir_len;
}
result = path_search_walk_ext(dir_path, dir_len,
file, file_len,
cwd, cwd_len,
name_has_ext);
@ -1052,35 +1069,65 @@ done:
}
int uv_process_kill(uv_process_t* process, int signum) {
static uv_err_t uv__kill(HANDLE process_handle, int signum) {
DWORD status;
uv_err_t err;
if (signum == SIGTERM || signum == SIGKILL || signum == SIGINT) {
/* Kill the process. On Windows, killed processes normally return 1. */
if (TerminateProcess(process_handle, 1)) {
err = uv_ok_;
} else {
err = uv__new_sys_error(GetLastError());
}
} else if (signum == 0) {
/* Health check: is the process still alive? */
if (GetExitCodeProcess(process_handle, &status) &&
status == STILL_ACTIVE) {
err = uv_ok_;
} else {
err = uv__new_sys_error(GetLastError());
}
} else {
err.code = UV_ENOSYS;
}
return err;
}
int uv_process_kill(uv_process_t* process, int signum) {
uv_err_t err;
if (process->process_handle == INVALID_HANDLE_VALUE) {
uv__set_artificial_error(process->loop, UV_EINVAL);
return -1;
}
if (signum) {
/* Kill the process. On Windows, killed processes normally return 1. */
if (TerminateProcess(process->process_handle, 1)) {
process->exit_signal = signum;
return 0;
}
else {
uv__set_sys_error(process->loop, GetLastError());
return -1;
}
}
else {
/* Health check: is the process still alive? */
if (GetExitCodeProcess(process->process_handle, &status) && status == STILL_ACTIVE) {
return 0;
}
else {
uv__set_artificial_error(process->loop, UV_EINVAL);
return -1;
}
err = uv__kill(process->process_handle, signum);
if (err.code != UV_OK) {
uv__set_error(process->loop, err.code, err.sys_errno_);
return -1;
}
assert(0 && "unreachable");
process->exit_signal = signum;
return 0;
}
uv_err_t uv_kill(int pid, int signum) {
uv_err_t err;
HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
PROCESS_QUERY_INFORMATION, FALSE, pid);
if (process_handle == INVALID_HANDLE_VALUE) {
return uv__new_sys_error(GetLastError());
}
err = uv__kill(process_handle, signum);
CloseHandle(process_handle);
return err;
}

View file

@ -46,6 +46,42 @@ static char uv_zero_[] = "";
static unsigned int active_tcp_streams = 0;
static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) {
if (setsockopt(socket,
IPPROTO_TCP,
TCP_NODELAY,
(const char*)&enable,
sizeof enable) == -1) {
uv__set_sys_error(handle->loop, errno);
return -1;
}
return 0;
}
static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) {
if (setsockopt(socket,
SOL_SOCKET,
SO_KEEPALIVE,
(const char*)&enable,
sizeof enable) == -1) {
uv__set_sys_error(handle->loop, errno);
return -1;
}
if (enable && setsockopt(socket,
IPPROTO_TCP,
TCP_KEEPALIVE,
(const char*)&delay,
sizeof delay) == -1) {
uv__set_sys_error(handle->loop, errno);
return -1;
}
return 0;
}
static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle,
SOCKET socket, int imported) {
DWORD yes = 1;
@ -89,6 +125,17 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle,
}
}
if ((handle->flags & UV_HANDLE_TCP_NODELAY) &&
uv__tcp_nodelay(handle, socket, 1)) {
return -1;
}
/* TODO: Use stored delay. */
if ((handle->flags & UV_HANDLE_TCP_KEEPALIVE) &&
uv__tcp_keepalive(handle, socket, 1, 60)) {
return -1;
}
handle->socket = socket;
return 0;
@ -105,6 +152,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
handle->reqs_pending = 0;
handle->func_acceptex = NULL;
handle->func_connectex = NULL;
handle->processed_accepts = 0;
loop->counters.tcp_init++;
@ -392,7 +440,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
uv_loop_t* loop = handle->loop;
unsigned int i;
unsigned int i, simultaneous_accepts;
uv_tcp_accept_t* req;
assert(backlog > 0);
@ -402,13 +450,6 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
return -1;
}
if (handle->flags & UV_HANDLE_LISTENING ||
handle->flags & UV_HANDLE_READING) {
/* Already listening. */
uv__set_sys_error(loop, WSAEALREADY);
return -1;
}
if (!(handle->flags & UV_HANDLE_BOUND) &&
uv_tcp_bind(handle, uv_addr_ip4_any_) < 0)
return -1;
@ -420,7 +461,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
}
}
if (listen(handle->socket, backlog) == SOCKET_ERROR) {
if (!(handle->flags & UV_HANDLE_SHARED_TCP_SERVER) &&
listen(handle->socket, backlog) == SOCKET_ERROR) {
uv__set_sys_error(loop, WSAGetLastError());
return -1;
}
@ -428,31 +470,35 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
handle->flags |= UV_HANDLE_LISTENING;
handle->connection_cb = cb;
assert(!handle->accept_reqs);
handle->accept_reqs = (uv_tcp_accept_t*)
malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
if (!handle->accept_reqs) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
: uv_simultaneous_server_accepts;
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
req = &handle->accept_reqs[i];
uv_req_init(loop, (uv_req_t*)req);
req->type = UV_ACCEPT;
req->accept_socket = INVALID_SOCKET;
req->data = handle;
req->wait_handle = INVALID_HANDLE_VALUE;
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
if (!req->event_handle) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
} else {
req->event_handle = NULL;
if(!handle->accept_reqs) {
handle->accept_reqs = (uv_tcp_accept_t*)
malloc(simultaneous_accepts * sizeof(uv_tcp_accept_t));
if (!handle->accept_reqs) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
uv_tcp_queue_accept(handle, req);
for (i = 0; i < simultaneous_accepts; i++) {
req = &handle->accept_reqs[i];
uv_req_init(loop, (uv_req_t*)req);
req->type = UV_ACCEPT;
req->accept_socket = INVALID_SOCKET;
req->data = handle;
req->wait_handle = INVALID_HANDLE_VALUE;
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
if (!req->event_handle) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
} else {
req->event_handle = NULL;
}
uv_tcp_queue_accept(handle, req);
}
}
return 0;
@ -491,7 +537,26 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
req->accept_socket = INVALID_SOCKET;
if (!(server->flags & UV_HANDLE_CLOSING)) {
uv_tcp_queue_accept(server, req);
/* Check if we're in a middle of changing the number of pending accepts. */
if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
uv_tcp_queue_accept(server, req);
} else {
/* We better be switching to a single pending accept. */
assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
server->processed_accepts++;
if (server->processed_accepts >= uv_simultaneous_server_accepts) {
server->processed_accepts = 0;
/*
* All previously queued accept requests are now processed.
* We now switch to queueing just a single accept.
*/
uv_tcp_queue_accept(server, &server->accept_reqs[0]);
server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
}
}
}
active_tcp_streams++;
@ -759,9 +824,19 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
/* An error occurred doing the read. */
if ((handle->flags & UV_HANDLE_READING)) {
handle->flags &= ~UV_HANDLE_READING;
uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req));
buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
uv_buf_init(NULL, 0) : handle->read_buffer;
err = GET_REQ_SOCK_ERROR(req);
if (err == WSAECONNABORTED) {
/* Treat WSAECONNABORTED as connection closed. */
handle->flags |= UV_HANDLE_EOF;
uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
} else {
uv__set_sys_error(loop, err);
}
handle->read_cb((uv_stream_t*)handle, -1, buf);
}
} else {
@ -822,8 +897,14 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
uv__set_sys_error(loop, WSAEWOULDBLOCK);
handle->read_cb((uv_stream_t*)handle, 0, buf);
} else {
/* Ouch! serious error. */
uv__set_sys_error(loop, err);
if (err == WSAECONNABORTED) {
/* Treat WSAECONNABORTED as connection closed. */
handle->flags |= UV_HANDLE_EOF;
uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
} else {
/* Ouch! serious error. */
uv__set_sys_error(loop, err);
}
handle->flags &= ~UV_HANDLE_READING;
handle->read_cb((uv_stream_t*)handle, -1, buf);
}
@ -953,18 +1034,111 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info) {
}
tcp->flags |= UV_HANDLE_BOUND;
tcp->flags |= UV_HANDLE_SHARED_TCP_SERVER;
return uv_tcp_set_socket(tcp->loop, tcp, socket, 1);
}
int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
uv__set_artificial_error(handle->loop, UV_ENOSYS);
return -1;
if (handle->socket != INVALID_SOCKET &&
uv__tcp_nodelay(handle, handle->socket, enable)) {
return -1;
}
if (enable) {
handle->flags |= UV_HANDLE_TCP_NODELAY;
} else {
handle->flags &= ~UV_HANDLE_TCP_NODELAY;
}
return 0;
}
int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
uv__set_artificial_error(handle->loop, UV_ENOSYS);
return -1;
if (handle->socket != INVALID_SOCKET &&
uv__tcp_keepalive(handle, handle->socket, enable, delay)) {
return -1;
}
if (enable) {
handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
} else {
handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
}
/* TODO: Store delay if handle->socket isn't created yet. */
return 0;
}
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
LPWSAPROTOCOL_INFOW protocol_info) {
assert(!(handle->flags & UV_HANDLE_CONNECTION));
/*
* We're about to share the socket with another process. Because
* this is a listening socket, we assume that the other process will
* be accepting conections on it. So, before sharing the socket
* with another process, we call listen here in the parent process.
* This needs to be modified if the socket is shared with
* another process for anything other than accepting connections.
*/
if (!(handle->flags & UV_HANDLE_LISTENING)) {
if (!(handle->flags & UV_HANDLE_BOUND)) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
uv__set_sys_error(handle->loop, WSAGetLastError());
return -1;
}
handle->flags |= UV_HANDLE_SHARED_TCP_SERVER;
}
if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) {
uv__set_sys_error(handle->loop, WSAGetLastError());
return -1;
}
return 0;
}
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
if (handle->flags & UV_HANDLE_CONNECTION) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
/* Check if we're already in the desired mode. */
if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) ||
(!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
return 0;
}
/* Don't allow switching from single pending accept to many. */
if (enable) {
uv__set_artificial_error(handle->loop, UV_ENOTSUP);
return -1;
}
/* Check if we're in a middle of changing the number of pending accepts. */
if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) {
return 0;
}
handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
/* Flip the changing flag if we have already queueed multiple accepts. */
if (handle->flags & UV_HANDLE_LISTENING) {
handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
}
return 0;
}

View file

@ -37,6 +37,10 @@
# define SO_UPDATE_CONNECT_CONTEXT 0x7010
#endif
#ifndef TCP_KEEPALIVE
# define TCP_KEEPALIVE 3
#endif
#ifndef IPV6_V6ONLY
#define IPV6_V6ONLY 27
#endif

View file

@ -225,12 +225,7 @@ static void pipe_make_connect(conn_rec* p) {
r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0);
ASSERT(r == 0);
r = uv_pipe_connect(&((pipe_conn_rec*)p)->conn_req, (uv_pipe_t*)&p->stream, TEST_PIPENAME, connect_cb);
if (r) {
fprintf(stderr, "uv_tcp_connect error %s\n",
uv_err_name(uv_last_error(loop)));
ASSERT(0);
}
uv_pipe_connect(&((pipe_conn_rec*)p)->conn_req, (uv_pipe_t*)&p->stream, TEST_PIPENAME, connect_cb);
#if DEBUG
printf("make connect %d\n", p->i);

View file

@ -257,8 +257,7 @@ static void maybe_connect_some() {
ASSERT(r == 0);
req = (uv_connect_t*) req_alloc();
r = uv_pipe_connect(req, pipe, TEST_PIPENAME, connect_cb);
ASSERT(r == 0);
uv_pipe_connect(req, pipe, TEST_PIPENAME, connect_cb);
}
}
}

View file

@ -112,7 +112,7 @@ static void ipc_on_connection(uv_stream_t* server, int status) {
}
static int ipc_helper() {
static int ipc_helper(int listen_after_write) {
/*
* This is launched from test-ipc.c. stdin is a duplex channel that we
* over which a handle will be transmitted. In this initial version only
@ -135,14 +135,21 @@ static int ipc_helper() {
r = uv_tcp_bind(&tcp_server, uv_ip4_addr("0.0.0.0", TEST_PORT));
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection);
ASSERT(r == 0);
if (!listen_after_write) {
r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection);
ASSERT(r == 0);
}
buf = uv_buf_init("hello\n", 6);
r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
(uv_stream_t*)&tcp_server, NULL);
ASSERT(r == 0);
if (listen_after_write) {
r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection);
ASSERT(r == 0);
}
r = uv_run(uv_default_loop());
ASSERT(r == 0);
@ -251,8 +258,12 @@ static int maybe_run_test(int argc, char **argv) {
return 0;
}
if (strcmp(argv[1], "ipc_helper") == 0) {
return ipc_helper();
if (strcmp(argv[1], "ipc_helper_listen_before_write") == 0) {
return ipc_helper(0);
}
if (strcmp(argv[1], "ipc_helper_listen_after_write") == 0) {
return ipc_helper(1);
}
if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {

View file

@ -144,7 +144,7 @@ TEST_IMPL(fs_event_watch_dir) {
uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL);
create_dir(loop, "watch_dir");
r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_cb_dir);
r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_cb_dir, 0);
ASSERT(r != -1);
r = uv_timer_init(loop, &timer);
ASSERT(r != -1);
@ -178,7 +178,7 @@ TEST_IMPL(fs_event_watch_file) {
create_file(loop, "watch_dir/file1");
create_file(loop, "watch_dir/file2");
r = uv_fs_event_init(loop, &fs_event, "watch_dir/file2", fs_event_cb_file);
r = uv_fs_event_init(loop, &fs_event, "watch_dir/file2", fs_event_cb_file, 0);
ASSERT(r != -1);
r = uv_timer_init(loop, &timer);
ASSERT(r != -1);
@ -212,7 +212,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) {
create_file(loop, "watch_file");
r = uv_fs_event_init(loop, &fs_event, "watch_file",
fs_event_cb_file_current_dir);
fs_event_cb_file_current_dir, 0);
ASSERT(r != -1);
r = uv_timer_init(loop, &timer);
@ -235,3 +235,36 @@ TEST_IMPL(fs_event_watch_file_current_dir) {
r = uv_fs_unlink(loop, &fs_req, "watch_file", NULL);
return 0;
}
TEST_IMPL(fs_event_no_callback_on_close) {
uv_fs_t fs_req;
uv_loop_t* loop = uv_default_loop();
int r;
/* Setup */
uv_fs_unlink(loop, &fs_req, "watch_dir/file1", NULL);
uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL);
create_dir(loop, "watch_dir");
create_file(loop, "watch_dir/file1");
r = uv_fs_event_init(loop,
&fs_event,
"watch_dir/file1",
fs_event_cb_file,
0);
ASSERT(r != -1);
uv_close((uv_handle_t*)&fs_event, close_cb);
uv_run(loop);
ASSERT(fs_event_cb_called == 0);
ASSERT(close_cb_called == 1);
/* Cleanup */
r = uv_fs_unlink(loop, &fs_req, "watch_dir/file1", NULL);
r = uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL);
return 0;
}

View file

@ -1408,3 +1408,71 @@ TEST_IMPL(fs_open_dir) {
return 0;
}
TEST_IMPL(fs_file_open_append) {
int r;
/* Setup. */
unlink("test_file");
loop = uv_default_loop();
r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
S_IWRITE | S_IREAD, NULL);
ASSERT(r != -1);
ASSERT(open_req1.result != -1);
uv_fs_req_cleanup(&open_req1);
r = uv_fs_write(loop, &write_req, open_req1.result, test_buf,
sizeof(test_buf), -1, NULL);
ASSERT(r != -1);
ASSERT(write_req.result != -1);
uv_fs_req_cleanup(&write_req);
r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
ASSERT(r != -1);
ASSERT(close_req.result != -1);
uv_fs_req_cleanup(&close_req);
r = uv_fs_open(loop, &open_req1, "test_file", O_RDWR | O_APPEND, 0, NULL);
ASSERT(r != -1);
ASSERT(open_req1.result != -1);
uv_fs_req_cleanup(&open_req1);
r = uv_fs_write(loop, &write_req, open_req1.result, test_buf,
sizeof(test_buf), -1, NULL);
ASSERT(r != -1);
ASSERT(write_req.result != -1);
uv_fs_req_cleanup(&write_req);
r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
ASSERT(r != -1);
ASSERT(close_req.result != -1);
uv_fs_req_cleanup(&close_req);
r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, S_IREAD, NULL);
ASSERT(r != -1);
ASSERT(open_req1.result != -1);
uv_fs_req_cleanup(&open_req1);
r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1,
NULL);
printf("read = %d\n", r);
ASSERT(r == 26);
ASSERT(read_req.result == 26);
ASSERT(memcmp(buf,
"test-buffer\n\0test-buffer\n\0",
sizeof("test-buffer\n\0test-buffer\n\0") - 1) == 0);
uv_fs_req_cleanup(&read_req);
r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
ASSERT(r != -1);
ASSERT(close_req.result != -1);
uv_fs_req_cleanup(&close_req);
/* Cleanup */
unlink("test_file");
return 0;
}

View file

@ -184,7 +184,7 @@ static void on_read(uv_pipe_t* pipe, ssize_t nread, uv_buf_t buf,
}
TEST_IMPL(ipc) {
int run_ipc_test(const char* helper) {
int r;
uv_process_options_t options;
uv_process_t process;
@ -199,7 +199,7 @@ TEST_IMPL(ipc) {
ASSERT(r == 0);
exepath[exepath_size] = '\0';
args[0] = exepath;
args[1] = "ipc_helper";
args[1] = (char*)helper;
args[2] = NULL;
options.file = exepath;
options.args = args;
@ -220,3 +220,59 @@ TEST_IMPL(ipc) {
ASSERT(exit_cb_called == 1);
return 0;
}
TEST_IMPL(ipc_listen_before_write) {
return run_ipc_test("ipc_helper_listen_before_write");
}
TEST_IMPL(ipc_listen_after_write) {
return run_ipc_test("ipc_helper_listen_after_write");
}
#ifdef _WIN32
TEST_IMPL(listen_with_simultaneous_accepts) {
uv_tcp_t server;
int r;
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT);
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, addr);
ASSERT(r == 0);
r = uv_tcp_simultaneous_accepts(&server, 1);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
ASSERT(r == 0);
ASSERT(server.reqs_pending == 32);
return 0;
}
TEST_IMPL(listen_no_simultaneous_accepts) {
uv_tcp_t server;
int r;
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT);
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, addr);
ASSERT(r == 0);
r = uv_tcp_simultaneous_accepts(&server, 0);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
ASSERT(r == 0);
ASSERT(server.reqs_pending == 1);
return 0;
}
#endif

View file

@ -21,13 +21,15 @@
TEST_DECLARE (tty)
TEST_DECLARE (stdio_over_pipes)
TEST_DECLARE (ipc)
TEST_DECLARE (ipc_listen_before_write)
TEST_DECLARE (ipc_listen_after_write)
TEST_DECLARE (tcp_ping_pong)
TEST_DECLARE (tcp_ping_pong_v6)
TEST_DECLARE (tcp_ref)
TEST_DECLARE (tcp_ref2)
TEST_DECLARE (pipe_ping_pong)
TEST_DECLARE (delayed_accept)
TEST_DECLARE (multiple_listen)
TEST_DECLARE (tcp_writealot)
TEST_DECLARE (tcp_bind_error_addrinuse)
TEST_DECLARE (tcp_bind_error_addrnotavail_1)
@ -39,6 +41,7 @@ TEST_DECLARE (tcp_listen_without_bind)
TEST_DECLARE (tcp_close)
TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_error)
TEST_DECLARE (tcp_write_to_half_open_connection)
TEST_DECLARE (tcp_bind6_error_addrinuse)
TEST_DECLARE (tcp_bind6_error_addrnotavail)
TEST_DECLARE (tcp_bind6_error_fault)
@ -53,6 +56,7 @@ TEST_DECLARE (pipe_bind_error_addrinuse)
TEST_DECLARE (pipe_bind_error_addrnotavail)
TEST_DECLARE (pipe_bind_error_inval)
TEST_DECLARE (pipe_listen_without_bind)
TEST_DECLARE (pipe_connect_bad_name)
TEST_DECLARE (connection_fail)
TEST_DECLARE (connection_fail_doesnt_auto_close)
TEST_DECLARE (shutdown_eof)
@ -87,6 +91,7 @@ TEST_DECLARE (spawn_stdout)
TEST_DECLARE (spawn_stdin)
TEST_DECLARE (spawn_and_kill)
TEST_DECLARE (spawn_and_ping)
TEST_DECLARE (kill)
TEST_DECLARE (fs_file_noent)
TEST_DECLARE (fs_file_async)
TEST_DECLARE (fs_file_sync)
@ -99,10 +104,12 @@ TEST_DECLARE (fs_link)
TEST_DECLARE (fs_symlink)
TEST_DECLARE (fs_utime)
TEST_DECLARE (fs_futime)
TEST_DECLARE (fs_file_open_append)
TEST_DECLARE (fs_stat_missing_path)
TEST_DECLARE (fs_event_watch_dir)
TEST_DECLARE (fs_event_watch_file)
TEST_DECLARE (fs_event_watch_file_current_dir)
TEST_DECLARE (fs_event_no_callback_on_close)
TEST_DECLARE (fs_readdir_empty_dir)
TEST_DECLARE (fs_readdir_file)
TEST_DECLARE (fs_open_dir)
@ -111,6 +118,8 @@ TEST_DECLARE (threadpool_queue_work_simple)
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (argument_escaping)
TEST_DECLARE (environment_creation)
TEST_DECLARE (listen_with_simultaneous_accepts)
TEST_DECLARE (listen_no_simultaneous_accepts)
#endif
HELPER_DECLARE (tcp4_echo_server)
HELPER_DECLARE (tcp6_echo_server)
@ -118,10 +127,12 @@ HELPER_DECLARE (pipe_echo_server)
TASK_LIST_START
TEST_ENTRY (pipe_connect_bad_name)
TEST_ENTRY (tty)
TEST_ENTRY (stdio_over_pipes)
TEST_ENTRY (ipc)
TEST_ENTRY (ipc_listen_before_write)
TEST_ENTRY (ipc_listen_after_write)
TEST_ENTRY (tcp_ref)
@ -138,6 +149,7 @@ TASK_LIST_START
TEST_HELPER (pipe_ping_pong, pipe_echo_server)
TEST_ENTRY (delayed_accept)
TEST_ENTRY (multiple_listen)
TEST_ENTRY (tcp_writealot)
TEST_HELPER (tcp_writealot, tcp4_echo_server)
@ -152,6 +164,7 @@ TASK_LIST_START
TEST_ENTRY (tcp_close)
TEST_ENTRY (tcp_flags)
TEST_ENTRY (tcp_write_error)
TEST_ENTRY (tcp_write_to_half_open_connection)
TEST_ENTRY (tcp_bind6_error_addrinuse)
TEST_ENTRY (tcp_bind6_error_addrnotavail)
@ -222,10 +235,13 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdin)
TEST_ENTRY (spawn_and_kill)
TEST_ENTRY (spawn_and_ping)
TEST_ENTRY (kill)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
TEST_ENTRY (argument_escaping)
TEST_ENTRY (environment_creation)
TEST_ENTRY (listen_with_simultaneous_accepts)
TEST_ENTRY (listen_no_simultaneous_accepts)
#endif
TEST_ENTRY (fs_file_noent)
@ -240,9 +256,11 @@ TASK_LIST_START
TEST_ENTRY (fs_futime)
TEST_ENTRY (fs_symlink)
TEST_ENTRY (fs_stat_missing_path)
TEST_ENTRY (fs_file_open_append)
TEST_ENTRY (fs_event_watch_dir)
TEST_ENTRY (fs_event_watch_file)
TEST_ENTRY (fs_event_watch_file_current_dir)
TEST_ENTRY (fs_event_no_callback_on_close)
TEST_ENTRY (fs_readdir_empty_dir)
TEST_ENTRY (fs_readdir_file)
TEST_ENTRY (fs_open_dir)

View file

@ -0,0 +1,102 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
static int connection_cb_called = 0;
static int close_cb_called = 0;
static int connect_cb_called = 0;
static uv_tcp_t server;
static uv_tcp_t client;
static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
}
static void connection_cb(uv_stream_t* tcp, int status) {
ASSERT(status == 0);
uv_close((uv_handle_t*)&server, close_cb);
connection_cb_called++;
}
static void start_server() {
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT);
int r;
r = uv_tcp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_tcp_bind(&server, addr);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
ASSERT(r == 0);
}
static void connect_cb(uv_connect_t* req, int status) {
ASSERT(req != NULL);
ASSERT(status == 0);
free(req);
uv_close((uv_handle_t*)&client, close_cb);
connect_cb_called++;
}
static void client_connect() {
struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
uv_connect_t* connect_req = malloc(sizeof *connect_req);
int r;
ASSERT(connect_req != NULL);
r = uv_tcp_init(uv_default_loop(), &client);
ASSERT(r == 0);
r = uv_tcp_connect(connect_req, &client, addr, connect_cb);
ASSERT(r == 0);
}
TEST_IMPL(multiple_listen) {
start_server();
client_connect();
uv_run(uv_default_loop());
ASSERT(connection_cb_called == 1);
ASSERT(connect_cb_called == 1);
ASSERT(close_cb_called == 2);
return 0;
}

View file

@ -211,9 +211,8 @@ static void pipe_pinger_new() {
/* We are never doing multiple reads/connects at a time anyway. */
/* so these handles can be pre-initialized. */
r = uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME,
uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME,
pinger_on_connect);
ASSERT(!r);
/* Synchronous connect callbacks are not allowed. */
ASSERT(pinger_on_connect_count == 0);

View file

@ -84,7 +84,7 @@ TEST_IMPL(pipe_bind_error_addrnotavail) {
r = uv_pipe_bind(&server, BAD_PIPENAME);
ASSERT(r == -1);
ASSERT(uv_last_error(uv_default_loop()).code == UV_EACCESS);
ASSERT(uv_last_error(uv_default_loop()).code == UV_EACCES);
uv_close((uv_handle_t*)&server, close_cb);

View file

@ -0,0 +1,68 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
# define BAD_PIPENAME "bad-pipe"
#else
# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
#endif
static int close_cb_called = 0;
static int connect_cb_called = 0;
static void close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
}
static void connect_cb(uv_connect_t* connect_req, int status) {
ASSERT(status == -1);
ASSERT(uv_last_error(uv_default_loop()).code == UV_ENOENT);
uv_close((uv_handle_t*)connect_req->handle, close_cb);
connect_cb_called++;
}
TEST_IMPL(pipe_connect_bad_name) {
uv_pipe_t client;
uv_connect_t req;
int r;
r = uv_pipe_init(uv_default_loop(), &client, 0);
ASSERT(r == 0);
uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb);
uv_run(uv_default_loop());
ASSERT(close_cb_called == 1);
ASSERT(connect_cb_called == 1);
return 0;
}

View file

@ -33,6 +33,7 @@ static uv_process_options_t options;
static char exepath[1024];
static size_t exepath_size = 1024;
static char* args[3];
static int no_term_signal;
#define OUTPUT_SIZE 1024
static char output[OUTPUT_SIZE];
@ -55,6 +56,8 @@ static void exit_cb(uv_process_t* process, int exit_status, int term_signal) {
static void kill_cb(uv_process_t* process, int exit_status, int term_signal) {
uv_err_t err;
printf("exit_cb\n");
exit_cb_called++;
#ifdef _WIN32
@ -62,8 +65,14 @@ static void kill_cb(uv_process_t* process, int exit_status, int term_signal) {
#else
ASSERT(exit_status == 0);
#endif
ASSERT(term_signal == 15);
ASSERT(no_term_signal || term_signal == 15);
uv_close((uv_handle_t*)process, close_cb);
/* Sending signum == 0 should check if the
* child process is still alive, not kill it.
*/
err = uv_kill(process->pid, 0);
ASSERT(err.code != UV_OK);
}
@ -261,6 +270,39 @@ TEST_IMPL(spawn_and_ping) {
}
TEST_IMPL(kill) {
int r;
uv_err_t err;
#ifdef _WIN32
no_term_signal = 1;
#endif
init_process_options("spawn_helper4", kill_cb);
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
/* Sending signum == 0 should check if the
* child process is still alive, not kill it.
*/
err = uv_kill(process.pid, 0);
ASSERT(err.code == UV_OK);
/* Kill the process. */
err = uv_kill(process.pid, /* SIGTERM */ 15);
ASSERT(err.code == UV_OK);
r = uv_run(uv_default_loop());
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);
return 0;
}
#ifdef _WIN32
TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
int r;

View file

@ -22,6 +22,9 @@
#include "uv.h"
#include "task.h"
#include <stdlib.h>
#include <string.h>
static char exepath[1024];
static size_t exepath_size = 1024;

View file

@ -0,0 +1,139 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void connection_cb(uv_stream_t* server, int status);
static void connect_cb(uv_connect_t* req, int status);
static void write_cb(uv_write_t* req, int status);
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf);
static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size);
static uv_tcp_t tcp_server;
static uv_tcp_t tcp_client;
static uv_tcp_t tcp_peer; /* client socket as accept()-ed by server */
static uv_connect_t connect_req;
static uv_write_t write_req;
static int write_cb_called;
static int read_cb_called;
static int read_eof_cb_called;
static void connection_cb(uv_stream_t* server, int status) {
int r;
uv_buf_t buf;
ASSERT(server == (uv_stream_t*)&tcp_server);
ASSERT(status == 0);
r = uv_tcp_init(server->loop, &tcp_peer);
ASSERT(r == 0);
r = uv_accept(server, (uv_stream_t*)&tcp_peer);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*)&tcp_peer, alloc_cb, read_cb);
ASSERT(r == 0);
buf.base = "hello\n";
buf.len = 6;
r = uv_write(&write_req, (uv_stream_t*)&tcp_peer, &buf, 1, write_cb);
ASSERT(r == 0);
}
static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
static char slab[1024];
return uv_buf_init(slab, sizeof slab);
}
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
if (nread == -1) {
fprintf(stderr, "read_cb error: %s\n", uv_err_name(uv_last_error(stream->loop)));
ASSERT(uv_last_error(stream->loop).code == UV_EOF);
uv_close((uv_handle_t*)&tcp_server, NULL);
uv_close((uv_handle_t*)&tcp_peer, NULL);
read_eof_cb_called++;
}
read_cb_called++;
}
static void connect_cb(uv_connect_t* req, int status) {
ASSERT(req == &connect_req);
ASSERT(status == 0);
/* Close the client. */
uv_close((uv_handle_t*)&tcp_client, NULL);
}
static void write_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
write_cb_called++;
}
TEST_IMPL(tcp_write_to_half_open_connection) {
uv_loop_t* loop;
int r;
loop = uv_default_loop();
ASSERT(loop != NULL);
r = uv_tcp_init(loop, &tcp_server);
ASSERT(r == 0);
r = uv_tcp_bind(&tcp_server, uv_ip4_addr("127.0.0.1", TEST_PORT));
ASSERT(r == 0);
r = uv_listen((uv_stream_t*)&tcp_server, 1, connection_cb);
ASSERT(r == 0);
r = uv_tcp_init(loop, &tcp_client);
ASSERT(r == 0);
r = uv_tcp_connect(&connect_req,
&tcp_client,
uv_ip4_addr("127.0.0.1", TEST_PORT),
connect_cb);
ASSERT(r == 0);
r = uv_run(loop);
ASSERT(r == 0);
ASSERT(write_cb_called > 0);
ASSERT(read_cb_called > 0);
ASSERT(read_eof_cb_called > 0);
return 0;
}

View file

@ -8,6 +8,15 @@
'_GNU_SOURCE',
'EIO_STACKSIZE=262144'
],
'conditions': [
['OS=="solaris"', {
'cflags': ['-pthreads'],
'ldlags': ['-pthreads'],
}, {
'cflags': ['-pthread'],
'ldlags': ['-pthread'],
}],
],
}],
],
},
@ -29,6 +38,7 @@
'HAVE_CONFIG_H'
],
'sources': [
'common.gypi',
'include/ares.h',
'include/ares_version.h',
'include/uv.h',
@ -120,6 +130,7 @@
'src/win/async.c',
'src/win/cares.c',
'src/win/core.c',
'src/win/dl.c',
'src/win/error.c',
'src/win/fs.c',
'src/win/fs-event.c',
@ -172,6 +183,7 @@
'src/unix/tty.c',
'src/unix/stream.c',
'src/unix/cares.c',
'src/unix/dl.c',
'src/unix/error.c',
'src/unix/process.c',
'src/unix/internal.h',
@ -280,9 +292,11 @@
'test/test-ipc.c',
'test/test-list.h',
'test/test-loop-handles.c',
'test/test-multiple-listen.c',
'test/test-pass-always.c',
'test/test-ping-pong.c',
'test/test-pipe-bind-error.c',
'test/test-pipe-connect-error.c',
'test/test-ref.c',
'test/test-shutdown-eof.c',
'test/test-spawn.c',
@ -294,6 +308,7 @@
'test/test-tcp-connect-error.c',
'test/test-tcp-connect6-error.c',
'test/test-tcp-write-error.c',
'test/test-tcp-write-to-half-open-connection.c',
'test/test-tcp-writealot.c',
'test/test-threadpool.c',
'test/test-timer-again.c',
@ -313,11 +328,10 @@
'libraries': [ 'ws2_32.lib' ]
}, { # POSIX
'defines': [ '_GNU_SOURCE' ],
'ldflags': [ '-pthread' ],
'sources': [
'test/runner-unix.c',
'test/runner-unix.h',
]
],
}],
[ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE
'defines': [
@ -365,7 +379,6 @@
'libraries': [ 'ws2_32.lib' ]
}, { # POSIX
'defines': [ '_GNU_SOURCE' ],
'ldflags': [ '-pthread' ],
'sources': [
'test/runner-unix.c',
'test/runner-unix.h',