Merge branch 'v0.6'
Conflicts: src/unix/core.c src/win/winapi.h
This commit is contained in:
commit
f5c2a4a1ae
1
.mailmap
1
.mailmap
@ -9,3 +9,4 @@ Isaac Z. Schlueter <i@izs.me>
|
||||
Saúl Ibarra Corretgé <saghul@gmail.com>
|
||||
Yuki OKUMURA <mjt@cltn.org>
|
||||
Frank Denis <github@pureftpd.org>
|
||||
Ryan Emery <seebees@gmail.com>
|
||||
|
||||
3
AUTHORS
3
AUTHORS
@ -33,3 +33,6 @@ Roman Shtylman <shtylman@gmail.com>
|
||||
Frank Denis <github@pureftpd.org>
|
||||
Carter Allen <CarterA@opt-6.com>
|
||||
Tj Holowaychuk <tj@vision-media.ca>
|
||||
Shimon Doodkin <helpmepro1@gmail.com>
|
||||
Ryan Emery <seebees@gmail.com>
|
||||
Bruce Mitchener <bruce.mitchener@gmail.com>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# libuv
|
||||
|
||||
libuv is a new platform layer for Node. Its purpose is to abstract IOCP on
|
||||
windows and libev on Unix systems. We intend to eventually contain all
|
||||
Windows and libev on Unix systems. We intend to eventually contain all
|
||||
platform differences in this library.
|
||||
|
||||
http://nodejs.org/
|
||||
|
||||
@ -51,7 +51,6 @@ endif
|
||||
ifeq (Darwin,$(uname_S))
|
||||
EV_CONFIG=config_darwin.h
|
||||
EIO_CONFIG=config_darwin.h
|
||||
CPPFLAGS += -D__DARWIN_64_BIT_INO_T=1
|
||||
CPPFLAGS += -Isrc/ares/config_darwin
|
||||
LINKFLAGS+=-framework CoreServices
|
||||
OBJS += src/unix/darwin.o
|
||||
|
||||
@ -291,7 +291,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
LPFN_WSARECVFROM func_wsarecvfrom;
|
||||
|
||||
#define uv_pipe_server_fields \
|
||||
uv_pipe_accept_t accept_reqs[4]; \
|
||||
int pending_instances; \
|
||||
uv_pipe_accept_t* accept_reqs; \
|
||||
uv_pipe_accept_t* pending_accepts;
|
||||
|
||||
#define uv_pipe_connection_fields \
|
||||
|
||||
36
include/uv.h
36
include/uv.h
@ -106,7 +106,7 @@ typedef intptr_t ssize_t;
|
||||
XX( 35, ENOSYS, "function not implemented") \
|
||||
XX( 36, EPIPE, "broken pipe") \
|
||||
XX( 37, EPROTO, "protocol error") \
|
||||
XX( 38, EPROTONOSUPPORT, "protocol not suppored") \
|
||||
XX( 38, EPROTONOSUPPORT, "protocol not supported") \
|
||||
XX( 39, EPROTOTYPE, "protocol wrong type for socket") \
|
||||
XX( 40, ETIMEDOUT, "connection timed out") \
|
||||
XX( 41, ECHARSET, "") \
|
||||
@ -226,7 +226,6 @@ UV_EXTERN int64_t uv_now(uv_loop_t*);
|
||||
/*
|
||||
* The status parameter is 0 if the request completed successfully,
|
||||
* and should be -1 if the request was cancelled or failed.
|
||||
* For uv_close_cb, -1 means that the handle was closed due to an error.
|
||||
* Error details can be obtained by calling uv_last_error().
|
||||
*
|
||||
* In the case of uv_read_cb the uv_buf_t returned should be freed by the
|
||||
@ -263,7 +262,7 @@ typedef void (*uv_after_work_cb)(uv_work_t* req);
|
||||
* This will be called repeatedly after the uv_fs_event_t is initialized.
|
||||
* If uv_fs_event_t was initialized with a directory the filename parameter
|
||||
* will be a relative path to a file contained in the directory.
|
||||
* The events paramenter is an ORed mask of enum uv_fs_event elements.
|
||||
* The events parameter is an ORed mask of enum uv_fs_event elements.
|
||||
*/
|
||||
typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename,
|
||||
int events, int status);
|
||||
@ -315,8 +314,8 @@ UV_PRIVATE_REQ_TYPES
|
||||
*
|
||||
* Shutdown the outgoing (write) side of a duplex stream. It waits for
|
||||
* pending write requests to complete. The handle should refer to a
|
||||
* initialized stream. req should be an uninitalized shutdown request
|
||||
* struct. The cb is a called after shutdown is complete.
|
||||
* initialized stream. req should be an uninitialized shutdown request
|
||||
* struct. The cb is called after shutdown is complete.
|
||||
*/
|
||||
UV_EXTERN int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle,
|
||||
uv_shutdown_cb cb);
|
||||
@ -345,8 +344,8 @@ 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.
|
||||
* Returns 1 if the prepare/check/idle/timer handle has been started, 0
|
||||
* otherwise. For other handle types this always returns 1.
|
||||
*/
|
||||
UV_EXTERN int uv_is_active(uv_handle_t* handle);
|
||||
|
||||
@ -524,7 +523,7 @@ UV_EXTERN int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name,
|
||||
* uv_tcp_connect, uv_tcp_connect6
|
||||
* These functions establish IPv4 and IPv6 TCP connections. Provide an
|
||||
* initialized TCP handle and an uninitialized uv_connect_t*. The callback
|
||||
* will be made when the connection is estabished.
|
||||
* will be made when the connection is established.
|
||||
*/
|
||||
UV_EXTERN int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
|
||||
struct sockaddr_in address, uv_connect_cb cb);
|
||||
@ -788,6 +787,13 @@ UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
|
||||
UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
||||
const char* name, uv_connect_cb cb);
|
||||
|
||||
/*
|
||||
* This setting applies to Windows only.
|
||||
* Set the number of pending pipe instance handles when the pipe server
|
||||
* is waiting for connections.
|
||||
*/
|
||||
UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
|
||||
|
||||
|
||||
/*
|
||||
* uv_prepare_t is a subclass of uv_handle_t.
|
||||
@ -899,7 +905,7 @@ 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
|
||||
* callback it does not immediately take effect. If the timer was nonrepeating
|
||||
* callback it does not immediately take effect. If the timer was non-repeating
|
||||
* before, it will have been stopped. If it was repeating, then the old repeat
|
||||
* value will have been used to schedule the next timeout.
|
||||
*/
|
||||
@ -953,7 +959,7 @@ typedef struct uv_process_options_s {
|
||||
const char* file; /* Path to program to execute. */
|
||||
/*
|
||||
* Command line arguments. args[0] should be the path to the program. On
|
||||
* Windows this uses CreateProcess which concatinates the arguments into a
|
||||
* Windows this uses CreateProcess which concatenates the arguments into a
|
||||
* string this can cause some strange errors. See the note at
|
||||
* windows_verbatim_arguments.
|
||||
*/
|
||||
@ -977,7 +983,7 @@ typedef struct uv_process_options_s {
|
||||
/*
|
||||
* The user should supply pointers to initialized uv_pipe_t structs for
|
||||
* stdio. This is used to to send or receive input from the subprocess.
|
||||
* The user is reponsible for calling uv_close on them.
|
||||
* The user is responsible for calling uv_close on them.
|
||||
*/
|
||||
uv_pipe_t* stdin_stream;
|
||||
uv_pipe_t* stdout_stream;
|
||||
@ -1037,7 +1043,7 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop, uv_work_t* req,
|
||||
* uninitialized uv_fs_t object.
|
||||
*
|
||||
* uv_fs_req_cleanup() must be called after completion of the uv_fs_
|
||||
* function to free any internal memory allocations associted with the
|
||||
* function to free any internal memory allocations associated with the
|
||||
* request.
|
||||
*/
|
||||
|
||||
@ -1229,6 +1235,12 @@ UV_EXTERN int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size);
|
||||
/* Gets the executable path */
|
||||
UV_EXTERN int uv_exepath(char* buffer, size_t* size);
|
||||
|
||||
/* Gets the current working directory */
|
||||
UV_EXTERN uv_err_t uv_cwd(char* buffer, size_t size);
|
||||
|
||||
/* Changes the current working directory */
|
||||
UV_EXTERN uv_err_t uv_chdir(const char* dir);
|
||||
|
||||
/* Gets memory info in bytes */
|
||||
UV_EXTERN uint64_t uv_get_free_memory(void);
|
||||
UV_EXTERN uint64_t uv_get_total_memory(void);
|
||||
|
||||
@ -827,3 +827,43 @@ int uv__cloexec(int fd, int set) {
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* TODO move to uv-common.c? */
|
||||
size_t uv__strlcpy(char* dst, const char* src, size_t size) {
|
||||
const char *org;
|
||||
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
org = src;
|
||||
while (--size && *src) {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
|
||||
return src - org;
|
||||
}
|
||||
|
||||
|
||||
uv_err_t uv_cwd(char* buffer, size_t size) {
|
||||
if (!buffer || !size) {
|
||||
return uv__new_artificial_error(UV_EINVAL);
|
||||
}
|
||||
|
||||
if (getcwd(buffer, size)) {
|
||||
return uv_ok_;
|
||||
} else {
|
||||
return uv__new_sys_error(errno);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uv_err_t uv_chdir(const char* dir) {
|
||||
if (chdir(dir) == 0) {
|
||||
return uv_ok_;
|
||||
} else {
|
||||
return uv__new_sys_error(errno);
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,3 +271,8 @@ void uv__pipe_accept(EV_P_ ev_io* watcher, int revents) {
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ static void CALLBACK uv_ares_socksignal_tp(void* parameter,
|
||||
/* do not fail if error, thread may run after socket close */
|
||||
/* The code assumes that c-ares will write all pending data in the */
|
||||
/* callback, unless the socket would block. We can clear the state here */
|
||||
/* to avoid unecessary signals. */
|
||||
/* to avoid unnecessary signals. */
|
||||
WSAEnumNetworkEvents(sockhandle->sock,
|
||||
sockhandle->h_event,
|
||||
&network_events);
|
||||
@ -113,7 +113,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read,
|
||||
if (read == 0 && write == 0) {
|
||||
/* if read and write are 0, cleanup existing data */
|
||||
/* The code assumes that c-ares does a callback with read = 0 and */
|
||||
/* write = 0 when the socket is closed. After we recieve this we stop */
|
||||
/* write = 0 when the socket is closed. After we receive this we stop */
|
||||
/* monitoring the socket. */
|
||||
if (uv_handle_ares != NULL) {
|
||||
uv_req_t* uv_ares_req;
|
||||
@ -244,7 +244,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* stil busy - repost and try again */
|
||||
/* still busy - repost and try again */
|
||||
POST_COMPLETION_FOR_REQ(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ static void uv_loop_init(uv_loop_t* loop) {
|
||||
|
||||
|
||||
static void uv_default_loop_init(void) {
|
||||
/* Intialize libuv itself first */
|
||||
/* Initialize libuv itself first */
|
||||
uv_once(&uv_init_guard_, uv_init);
|
||||
|
||||
/* Initialize the main loop */
|
||||
@ -204,13 +204,8 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
|
||||
uv_idle_invoke((loop)); \
|
||||
} \
|
||||
\
|
||||
/* Completely flush all pending reqs and endgames. */ \
|
||||
/* We do even when we just called the idle callbacks because those may */ \
|
||||
/* have closed handles or started requests that short-circuited. */ \
|
||||
while ((loop)->pending_reqs_tail || (loop)->endgame_handles) { \
|
||||
uv_process_endgames((loop)); \
|
||||
uv_process_reqs((loop)); \
|
||||
} \
|
||||
uv_process_reqs((loop)); \
|
||||
uv_process_endgames((loop)); \
|
||||
\
|
||||
if ((loop)->refs <= 0) { \
|
||||
break; \
|
||||
@ -218,7 +213,10 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
|
||||
\
|
||||
uv_prepare_invoke((loop)); \
|
||||
\
|
||||
poll((loop), (loop)->idle_handles == NULL && (loop)->refs > 0); \
|
||||
poll((loop), (loop)->idle_handles == NULL && \
|
||||
(loop)->pending_reqs_tail == NULL && \
|
||||
(loop)->endgame_handles == NULL && \
|
||||
(loop)->refs > 0); \
|
||||
\
|
||||
uv_check_invoke((loop)); \
|
||||
}
|
||||
|
||||
@ -39,6 +39,8 @@ static const uv_buf_t uv_null_buf_ = { 0, NULL };
|
||||
/* when the local ends wants to shut it down. */
|
||||
static const int64_t eof_timeout = 50; /* ms */
|
||||
|
||||
static const int default_pending_pipe_instances = 4;
|
||||
|
||||
/* IPC protocol flags. */
|
||||
#define UV_IPC_RAW_DATA 0x0001
|
||||
#define UV_IPC_UV_STREAM 0x0002
|
||||
@ -249,7 +251,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Run FlushFileBuffers in the thhead pool. */
|
||||
/* Run FlushFileBuffers in the thread pool. */
|
||||
result = QueueUserWorkItem(pipe_shutdown_thread_proc,
|
||||
req,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
@ -293,6 +295,12 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER) {
|
||||
assert(handle->accept_reqs);
|
||||
free(handle->accept_reqs);
|
||||
handle->accept_reqs = NULL;
|
||||
}
|
||||
|
||||
/* Remember the state of this flag because the close callback is */
|
||||
/* allowed to clobber or free the handle's memory */
|
||||
uv_alloced = handle->flags & UV_HANDLE_UV_ALLOCED;
|
||||
@ -310,6 +318,12 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
|
||||
handle->pending_instances = count;
|
||||
handle->flags |= UV_HANDLE_PIPESERVER;
|
||||
}
|
||||
|
||||
|
||||
/* Creates a pipe server. */
|
||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
@ -326,7 +340,17 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
|
||||
if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
|
||||
handle->pending_instances = default_pending_pipe_instances;
|
||||
}
|
||||
|
||||
handle->accept_reqs = (uv_pipe_accept_t*)
|
||||
malloc(sizeof(uv_pipe_accept_t) * handle->pending_instances);
|
||||
if (!handle->accept_reqs) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
}
|
||||
|
||||
for (i = 0; i < handle->pending_instances; i++) {
|
||||
req = &handle->accept_reqs[i];
|
||||
uv_req_init(loop, (uv_req_t*) req);
|
||||
req->type = UV_ACCEPT;
|
||||
@ -537,14 +561,13 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) {
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER) {
|
||||
for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
|
||||
for (i = 0; i < handle->pending_instances; i++) {
|
||||
pipeHandle = handle->accept_reqs[i].pipeHandle;
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(pipeHandle);
|
||||
handle->accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
@ -686,7 +709,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
/* First pipe handle should have already been created in uv_pipe_bind */
|
||||
assert(handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
|
||||
|
||||
for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
|
||||
for (i = 0; i < handle->pending_instances; i++) {
|
||||
uv_pipe_queue_accept(loop, handle, &handle->accept_reqs[i], i == 0);
|
||||
}
|
||||
|
||||
|
||||
@ -254,7 +254,7 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
|
||||
* - CMD does not trim leading/trailing whitespace from path/pathex entries
|
||||
* nor from the environment variables as a whole.
|
||||
*
|
||||
* - When cmd.exe cannot read a directory, it wil just skip it and go on
|
||||
* - When cmd.exe cannot read a directory, it will just skip it and go on
|
||||
* searching. However, unlike posix-y systems, it will happily try to run a
|
||||
* file that is not readable/executable; if the spawn fails it will not
|
||||
* continue searching.
|
||||
@ -400,7 +400,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Expected intput/output:
|
||||
* Expected input/output:
|
||||
* input : hello"world
|
||||
* output: "hello\"world"
|
||||
* input : hello""world
|
||||
@ -1018,7 +1018,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
|
||||
|
||||
} else {
|
||||
/* CreateProcessW failed, but this failure should be delivered */
|
||||
/* asynchronously to retain unix compatibility. So pretent spawn */
|
||||
/* asynchronously to retain unix compatibility. So pretend spawn */
|
||||
/* succeeded, and start a thread instead that prints an error */
|
||||
/* to the child's intended stderr. */
|
||||
process->spawn_errno = GetLastError();
|
||||
@ -1046,7 +1046,7 @@ done:
|
||||
close_child_stdio(process);
|
||||
} else {
|
||||
/* We're keeping the handles open, the thread pool is going to have */
|
||||
/* it's way with them. But at least make them noninheritable. */
|
||||
/* it's way with them. But at least make them non-inheritable. */
|
||||
int i;
|
||||
for (i = 0; i < COUNTOF(process->child_stdio); i++) {
|
||||
SetHandleInformation(child_stdio[i], HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
@ -51,27 +51,6 @@ void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static uv_req_t* uv_remove_pending_req(uv_loop_t* loop) {
|
||||
uv_req_t* req;
|
||||
|
||||
if (loop->pending_reqs_tail) {
|
||||
req = loop->pending_reqs_tail->next_req;
|
||||
|
||||
if (req == loop->pending_reqs_tail) {
|
||||
loop->pending_reqs_tail = NULL;
|
||||
} else {
|
||||
loop->pending_reqs_tail->next_req = req->next_req;
|
||||
}
|
||||
|
||||
return req;
|
||||
|
||||
} else {
|
||||
/* queue empty */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
|
||||
do { \
|
||||
switch (((uv_handle_t*) (req)->handle_at)->type) { \
|
||||
@ -101,8 +80,21 @@ static uv_req_t* uv_remove_pending_req(uv_loop_t* loop) {
|
||||
|
||||
void uv_process_reqs(uv_loop_t* loop) {
|
||||
uv_req_t* req;
|
||||
uv_req_t* first;
|
||||
uv_req_t* next;
|
||||
|
||||
if (loop->pending_reqs_tail == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
first = loop->pending_reqs_tail->next_req;
|
||||
next = first;
|
||||
loop->pending_reqs_tail = NULL;
|
||||
|
||||
while (next != NULL) {
|
||||
req = next;
|
||||
next = req->next_req != first ? req->next_req : NULL;
|
||||
|
||||
while (req = uv_remove_pending_req(loop)) {
|
||||
switch (req->type) {
|
||||
case UV_READ:
|
||||
DELEGATE_STREAM_REQ(loop, req, read, data);
|
||||
|
||||
@ -1084,7 +1084,7 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
|
||||
/*
|
||||
* 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
|
||||
* be accepting connections 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.
|
||||
@ -1137,7 +1137,7 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
|
||||
handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
|
||||
/* Flip the changing flag if we have already queueed multiple accepts. */
|
||||
/* Flip the changing flag if we have already queued multiple accepts. */
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ uint64_t uv_hrtime(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Because we have no guarantee about the order of magniture of the */
|
||||
/* Because we have no guarantee about the order of magnitude of the */
|
||||
/* performance counter frequency, and there may not be much headroom to */
|
||||
/* multiply by NANOSEC without overflowing, we use 128-bit math instead. */
|
||||
return ((uint64_t) counter.LowPart * NANOSEC / uv_hrtime_frequency_) +
|
||||
|
||||
@ -739,7 +739,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
handle->read_cb = read_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
|
||||
/* If reading was stopped and then started again, there could stell be a */
|
||||
/* If reading was stopped and then started again, there could still be a */
|
||||
/* read request pending. */
|
||||
if (handle->flags & UV_HANDLE_READ_PENDING) {
|
||||
return 0;
|
||||
|
||||
@ -362,7 +362,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
handle->recv_cb = recv_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
|
||||
/* If reading was stopped and then started again, there could stell be a */
|
||||
/* If reading was stopped and then started again, there could still be a */
|
||||
/* recv request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||
uv_udp_queue_recv(loop, handle);
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <direct.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -97,6 +98,91 @@ done:
|
||||
}
|
||||
|
||||
|
||||
uv_err_t uv_cwd(char* buffer, size_t size) {
|
||||
uv_err_t err;
|
||||
size_t utf8Size;
|
||||
wchar_t* utf16Buffer = NULL;
|
||||
|
||||
if (!buffer || !size) {
|
||||
err.code = UV_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * size);
|
||||
if (!utf16Buffer) {
|
||||
err.code = UV_ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!_wgetcwd(utf16Buffer, size - 1)) {
|
||||
err = uv__new_sys_error(_doserrno);
|
||||
goto done;
|
||||
}
|
||||
|
||||
utf16Buffer[size - 1] = L'\0';
|
||||
|
||||
/* Convert to UTF-8 */
|
||||
utf8Size = uv_utf16_to_utf8(utf16Buffer, -1, buffer, size);
|
||||
if (utf8Size == 0) {
|
||||
err = uv__new_sys_error(GetLastError());
|
||||
goto done;
|
||||
}
|
||||
|
||||
buffer[utf8Size] = '\0';
|
||||
err = uv_ok_;
|
||||
|
||||
done:
|
||||
if (utf16Buffer) {
|
||||
free(utf16Buffer);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
uv_err_t uv_chdir(const char* dir) {
|
||||
uv_err_t err;
|
||||
wchar_t* utf16Buffer = NULL;
|
||||
size_t utf16Size;
|
||||
|
||||
if (!dir) {
|
||||
err.code = UV_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
utf16Size = uv_utf8_to_utf16(dir, NULL, 0);
|
||||
if (!utf16Size) {
|
||||
err = uv__new_sys_error(GetLastError());
|
||||
goto done;
|
||||
}
|
||||
|
||||
utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * utf16Size);
|
||||
if (!utf16Buffer) {
|
||||
err.code = UV_ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!uv_utf8_to_utf16(dir, utf16Buffer, utf16Size)) {
|
||||
err = uv__new_sys_error(GetLastError());
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (_wchdir(utf16Buffer) == -1) {
|
||||
err = uv__new_sys_error(_doserrno);
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = uv_ok_;
|
||||
|
||||
done:
|
||||
if (utf16Buffer) {
|
||||
free(utf16Buffer);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
/* Can't be implemented */
|
||||
avg[0] = avg[1] = avg[2] = 0;
|
||||
|
||||
@ -4394,6 +4394,7 @@ typedef VOID (WINAPI* sReleaseSRWLockExclusive)
|
||||
(PSRWLOCK SRWLock);
|
||||
|
||||
|
||||
|
||||
/* Ntapi function pointers */
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
|
||||
@ -186,7 +186,7 @@ static void pinger_new() {
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connec to the server and do NUM_PINGS ping-pongs. */
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(loop, &pinger->tcp);
|
||||
ASSERT(!r);
|
||||
|
||||
|
||||
@ -156,7 +156,7 @@ int process_wait(process_info_t *vec, int n, int timeout) {
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||
DWORD timeout_api, result;
|
||||
|
||||
/* If there's nothing to wait for, return immedately. */
|
||||
/* If there's nothing to wait for, return immediately. */
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
@ -19,10 +19,10 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Don't complain about _snprintf being unsecure. */
|
||||
/* Don't complain about _snprintf being insecure. */
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
/* Dont complain about write(), fileno() etc. being deprecated. */
|
||||
/* Don't complain about write(), fileno() etc. being deprecated. */
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
|
||||
|
||||
@ -218,7 +218,7 @@ out:
|
||||
} else if (benchmark_output) {
|
||||
switch (process_output_size(main_proc)) {
|
||||
case -1:
|
||||
LOGF("%s: (unavailabe)\n", test);
|
||||
LOGF("%s: (unavailable)\n", test);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
|
||||
@ -138,7 +138,7 @@ static void write_cb(uv_write_t* req, int status) {
|
||||
/* After the data has been sent, we're going to wait for a while, then */
|
||||
/* start reading. This makes us certain that the message has been echoed */
|
||||
/* back to our receive buffer when we start reading. This maximizes the */
|
||||
/* tempation for the backend to use dirty stack for calling read_cb. */
|
||||
/* temptation for the backend to use dirty stack for calling read_cb. */
|
||||
nested++;
|
||||
r = uv_timer_init(uv_default_loop(), &timer);
|
||||
ASSERT(r == 0);
|
||||
|
||||
@ -97,7 +97,7 @@ void connection_fail(uv_connect_cb connect_cb) {
|
||||
/* There should be no servers listening on this port. */
|
||||
server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
|
||||
|
||||
/* Try to connec to the server and do NUM_PINGS ping-pongs. */
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(uv_default_loop(), &tcp);
|
||||
ASSERT(!r);
|
||||
|
||||
|
||||
61
test/test-cwd-and-chdir.c
Normal file
61
test/test-cwd-and-chdir.c
Normal file
@ -0,0 +1,61 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
#define PATHMAX 1024
|
||||
extern char executable_path[];
|
||||
|
||||
TEST_IMPL(cwd_and_chdir) {
|
||||
char buffer_orig[PATHMAX];
|
||||
char buffer_new[PATHMAX];
|
||||
size_t size;
|
||||
char* last_slash;
|
||||
uv_err_t err;
|
||||
|
||||
size = sizeof(buffer_orig) / sizeof(buffer_orig[0]);
|
||||
err = uv_cwd(buffer_orig, size);
|
||||
ASSERT(err.code == UV_OK);
|
||||
|
||||
last_slash = strrchr(buffer_orig,
|
||||
#ifdef _WIN32
|
||||
'\\'
|
||||
#else
|
||||
'/'
|
||||
#endif
|
||||
);
|
||||
|
||||
ASSERT(last_slash);
|
||||
|
||||
*last_slash = '\0';
|
||||
|
||||
err = uv_chdir(buffer_orig);
|
||||
ASSERT(err.code == UV_OK);
|
||||
|
||||
err = uv_cwd(buffer_new, size);
|
||||
ASSERT(err.code == UV_OK);
|
||||
|
||||
ASSERT(strcmp(buffer_orig, buffer_new) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -152,7 +152,7 @@ static void connect_cb(uv_connect_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
|
||||
/* Not that the server will send anything, but otherwise we'll never know */
|
||||
/* when te server closes the connection. */
|
||||
/* when the server closes the connection. */
|
||||
r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* FIXME we shouldnt need to branch in this file */
|
||||
/* FIXME we shouldn't need to branch in this file */
|
||||
#define UNIX (defined(__unix__) || defined(__POSIX__) || defined(__APPLE__))
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
@ -83,7 +83,7 @@ static void check_sockname(struct sockaddr* addr, const char* compare_ip,
|
||||
char check_ip[17];
|
||||
int r;
|
||||
|
||||
/* Both adresses should be ipv4 */
|
||||
/* Both addresses should be ipv4 */
|
||||
ASSERT(check_addr.sin_family == AF_INET);
|
||||
ASSERT(compare_addr.sin_family == AF_INET);
|
||||
|
||||
|
||||
@ -77,6 +77,7 @@ TEST_DECLARE (check_ref)
|
||||
TEST_DECLARE (unref_in_prepare_cb)
|
||||
TEST_DECLARE (async)
|
||||
TEST_DECLARE (get_currentexe)
|
||||
TEST_DECLARE (cwd_and_chdir)
|
||||
TEST_DECLARE (get_memory)
|
||||
TEST_DECLARE (hrtime)
|
||||
TEST_DECLARE (getaddrinfo_basic)
|
||||
@ -223,6 +224,8 @@ TASK_LIST_START
|
||||
|
||||
TEST_ENTRY (get_currentexe)
|
||||
|
||||
TEST_ENTRY (cwd_and_chdir)
|
||||
|
||||
TEST_ENTRY (get_memory)
|
||||
|
||||
TEST_ENTRY (get_loadavg)
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
* being started by a check_1 watcher. It verifies that a watcher is
|
||||
* implicitly stopped when closed, and that a watcher can close itself
|
||||
* safely.
|
||||
* - There is a repeating timer. It does not keep te event loop alive
|
||||
* - There is a repeating timer. It does not keep the event loop alive
|
||||
* (ev_unref) but makes sure that the loop keeps polling the system for
|
||||
* events.
|
||||
*/
|
||||
|
||||
@ -154,7 +154,7 @@ static void tcp_pinger_v6_new() {
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connec to the server and do NUM_PINGS ping-pongs. */
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
|
||||
pinger->stream.tcp.data = pinger;
|
||||
ASSERT(!r);
|
||||
@ -179,7 +179,7 @@ static void tcp_pinger_new() {
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connec to the server and do NUM_PINGS ping-pongs. */
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
|
||||
pinger->stream.tcp.data = pinger;
|
||||
ASSERT(!r);
|
||||
@ -203,7 +203,7 @@ static void pipe_pinger_new() {
|
||||
pinger->state = 0;
|
||||
pinger->pongs = 0;
|
||||
|
||||
/* Try to connec to the server and do NUM_PINGS ping-pongs. */
|
||||
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
|
||||
r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);
|
||||
pinger->stream.pipe.data = pinger;
|
||||
ASSERT(!r);
|
||||
|
||||
@ -28,7 +28,7 @@ TEST_IMPL(tty) {
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
|
||||
/*
|
||||
* Not necessarally a problem if this assert goes off. E.G you are piping
|
||||
* Not necessarily a problem if this assert goes off. E.G you are piping
|
||||
* this test to a file. 0 == stdin.
|
||||
*/
|
||||
ASSERT(UV_TTY == uv_guess_handle(0));
|
||||
|
||||
4
uv.gyp
4
uv.gyp
@ -9,9 +9,6 @@
|
||||
'EIO_STACKSIZE=262144'
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'defines': ['__DARWIN_64_BIT_INO_T=1'],
|
||||
}],
|
||||
['OS=="solaris"', {
|
||||
'cflags': ['-pthreads'],
|
||||
'ldlags': ['-pthreads'],
|
||||
@ -283,6 +280,7 @@
|
||||
'test/test-error.c',
|
||||
'test/test-callback-stack.c',
|
||||
'test/test-connection-fail.c',
|
||||
'test/test-cwd-and-chdir.c',
|
||||
'test/test-delayed-accept.c',
|
||||
'test/test-fail-always.c',
|
||||
'test/test-fs.c',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user