uv: upgrade to 8073a26

This commit is contained in:
Bert Belder
2012-08-20 18:41:07 +02:00
parent 772b3bf4c8
commit 6bec5440eb
72 changed files with 2659 additions and 1559 deletions

View File

@@ -37,6 +37,7 @@ OBJS += src/unix/loop-watcher.o
OBJS += src/unix/pipe.o
OBJS += src/unix/poll.o
OBJS += src/unix/process.o
OBJS += src/unix/signal.o
OBJS += src/unix/stream.o
OBJS += src/unix/tcp.o
OBJS += src/unix/thread.o

4
deps/uv/gyp_uv vendored
View File

@@ -22,7 +22,9 @@ def compiler_version():
proc = subprocess.Popen(CC.split() + ['--version'], stdout=subprocess.PIPE)
is_clang = 'clang' in proc.communicate()[0].split('\n')[0]
proc = subprocess.Popen(CC.split() + ['-dumpversion'], stdout=subprocess.PIPE)
version = tuple(map(int, proc.communicate()[0].split('.')))
version = proc.communicate()[0].split('.')
version = map(int, version[:2])
version = tuple(version)
return (version, is_clang)

View File

@@ -251,7 +251,7 @@ struct eio_req
eio_channel *channel; /* data used to direct poll callbacks arising from this req */
#if __i386 || __amd64
#if defined(__i386) || defined(__amd64)
unsigned char cancelled;
#else
sig_atomic_t cancelled;

View File

@@ -62,7 +62,7 @@ struct ngx_queue_s {
(q)->prev
#if (NGX_DEBUG)
#if defined(NGX_DEBUG)
#define ngx_queue_remove(x) \
(x)->next->prev = (x)->prev; \

30
deps/uv/include/uv-private/uv-bsd.h vendored Normal file
View File

@@ -0,0 +1,30 @@
/* 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.
*/
#ifndef UV_BSD_H
#define UV_BSD_H
#define UV_PLATFORM_FS_EVENT_FIELDS \
uv__io_t event_watcher; \
int fflags; \
int fd; \
#endif /* UV_BSD_H */

37
deps/uv/include/uv-private/uv-darwin.h vendored Normal file
View File

@@ -0,0 +1,37 @@
/* 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.
*/
#ifndef UV_DARWIN_H
#define UV_DARWIN_H
#if defined(__APPLE__) && defined(__MACH__)
# include <mach/mach.h>
# include <mach/task.h>
# include <mach/semaphore.h>
# define UV_PLATFORM_SEM_T semaphore_t
#endif
#define UV_PLATFORM_FS_EVENT_FIELDS \
ev_io event_watcher; \
int fflags; \
int fd; \
#endif /* UV_DARWIN_H */

34
deps/uv/include/uv-private/uv-linux.h vendored Normal file
View File

@@ -0,0 +1,34 @@
/* 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.
*/
#ifndef UV_LINUX_H
#define UV_LINUX_H
#define UV_PLATFORM_LOOP_FIELDS \
uv__io_t inotify_read_watcher; \
void* inotify_watchers; \
int inotify_fd; \
#define UV_PLATFORM_FS_EVENT_FIELDS \
ngx_queue_t watchers; \
int wd; \
#endif /* UV_LINUX_H */

40
deps/uv/include/uv-private/uv-sunos.h vendored Normal file
View File

@@ -0,0 +1,40 @@
/* 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.
*/
#ifndef UV_SUNOS_H
#define UV_SUNOS_H
#include <sys/port.h>
#include <port.h>
#if defined(PORT_SOURCE_FILE)
# define UV_PLATFORM_LOOP_FIELDS \
uv__io_t fs_event_watcher; \
int fs_fd; \
# define UV_PLATFORM_FS_EVENT_FIELDS \
file_obj_t fo; \
int fd; \
#endif /* defined(PORT_SOURCE_FILE) */
#endif /* UV_SUNOS_H */

View File

@@ -40,57 +40,10 @@
#include <termios.h>
#include <pwd.h>
#include <semaphore.h>
#include <pthread.h>
#include <signal.h>
#if defined(__APPLE__) && defined(__MACH__)
# include <mach/mach.h>
# include <mach/task.h>
# include <mach/semaphore.h>
#else
# include <semaphore.h>
#endif
#if __sun
# include <sys/port.h>
# include <port.h>
#endif
/* Note: May be cast to struct iovec. See writev(2). */
typedef struct {
char* base;
size_t len;
} uv_buf_t;
typedef int uv_file;
typedef int uv_os_sock_t;
typedef struct stat uv_statbuf_t;
#define UV_ONCE_INIT PTHREAD_ONCE_INIT
typedef pthread_once_t uv_once_t;
typedef pthread_t uv_thread_t;
typedef pthread_mutex_t uv_mutex_t;
typedef pthread_rwlock_t uv_rwlock_t;
#if defined(__APPLE__) && defined(__MACH__)
typedef semaphore_t uv_sem_t;
#else
typedef sem_t uv_sem_t;
#endif
/* Platform-specific definitions for uv_spawn support. */
typedef gid_t uv_gid_t;
typedef uid_t uv_uid_t;
/* Platform-specific definitions for uv_dlopen support. */
#define UV_DYNAMIC /* empty */
typedef struct {
void* handle;
char* errmsg;
} uv_lib_t;
struct uv__io_s;
struct uv_loop_s;
@@ -101,22 +54,63 @@ struct uv__io_s {
ev_io io_watcher;
};
#define UV_REQ_TYPE_PRIVATE /* empty */
#if __linux__
# define UV_LOOP_PRIVATE_PLATFORM_FIELDS \
uv__io_t inotify_read_watcher; \
void* inotify_watchers; \
int inotify_fd;
#elif defined(PORT_SOURCE_FILE)
# define UV_LOOP_PRIVATE_PLATFORM_FIELDS \
uv__io_t fs_event_watcher; \
int fs_fd;
#else
# define UV_LOOP_PRIVATE_PLATFORM_FIELDS
#if defined(__linux__)
# include "uv-linux.h"
#elif defined(__sun)
# include "uv-sunos.h"
#elif defined(__APPLE__)
# include "uv-darwin.h"
#elif defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__)
# include "uv-bsd.h"
#endif
#ifndef UV_PLATFORM_SEM_T
# define UV_PLATFORM_SEM_T sem_t
#endif
#ifndef UV_PLATFORM_LOOP_FIELDS
# define UV_PLATFORM_LOOP_FIELDS /* empty */
#endif
#ifndef UV_PLATFORM_FS_EVENT_FIELDS
# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */
#endif
/* Note: May be cast to struct iovec. See writev(2). */
typedef struct {
char* base;
size_t len;
} uv_buf_t;
typedef int uv_file;
typedef int uv_os_sock_t;
typedef struct stat uv_statbuf_t;
#define UV_ONCE_INIT PTHREAD_ONCE_INIT
typedef pthread_once_t uv_once_t;
typedef pthread_t uv_thread_t;
typedef pthread_mutex_t uv_mutex_t;
typedef pthread_rwlock_t uv_rwlock_t;
typedef UV_PLATFORM_SEM_T uv_sem_t;
/* Platform-specific definitions for uv_spawn support. */
typedef gid_t uv_gid_t;
typedef uid_t uv_uid_t;
/* Platform-specific definitions for uv_dlopen support. */
#define UV_DYNAMIC /* empty */
typedef struct {
void* handle;
char* errmsg;
} uv_lib_t;
#define UV_LOOP_PRIVATE_FIELDS \
unsigned long flags; \
/* Poll result queue */ \
eio_channel uv_eio_channel; \
struct ev_loop* ev; \
@@ -125,6 +119,7 @@ struct uv__io_s {
uv_async_t uv_eio_done_poll_notifier; \
uv_idle_t uv_eio_poller; \
uv_handle_t* closing_handles; \
ngx_queue_t process_handles[1]; \
ngx_queue_t prepare_handles; \
ngx_queue_t check_handles; \
ngx_queue_t idle_handles; \
@@ -132,111 +127,94 @@ struct uv__io_s {
uv__io_t async_watcher; \
int async_pipefd[2]; \
/* RB_HEAD(uv__timers, uv_timer_s) */ \
struct uv__timers { struct uv_timer_s* rbh_root; } timer_handles; \
struct uv__timers { \
struct uv_timer_s* rbh_root; \
} timer_handles; \
uint64_t time; \
UV_LOOP_PRIVATE_PLATFORM_FIELDS
void* signal_ctx; \
uv_signal_t child_watcher; \
UV_PLATFORM_LOOP_FIELDS \
#define UV_REQ_BUFSML_SIZE (4)
#define UV_REQ_TYPE_PRIVATE /* empty */
#define UV_REQ_PRIVATE_FIELDS /* empty */
#define UV_WRITE_PRIVATE_FIELDS \
ngx_queue_t queue; \
int write_index; \
uv_buf_t* bufs; \
int bufcnt; \
int error; \
uv_buf_t bufsml[UV_REQ_BUFSML_SIZE];
#define UV_PRIVATE_REQ_TYPES /* empty */
#define UV_WRITE_PRIVATE_FIELDS \
ngx_queue_t queue; \
int write_index; \
uv_buf_t* bufs; \
int bufcnt; \
int error; \
uv_buf_t bufsml[4]; \
#define UV_CONNECT_PRIVATE_FIELDS \
ngx_queue_t queue; \
#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
#define UV_CONNECT_PRIVATE_FIELDS \
ngx_queue_t queue;
#define UV_UDP_SEND_PRIVATE_FIELDS \
ngx_queue_t queue; \
struct sockaddr_in6 addr; \
int bufcnt; \
uv_buf_t* bufs; \
ssize_t status; \
uv_udp_send_cb send_cb; \
uv_buf_t bufsml[4]; \
#define UV_UDP_SEND_PRIVATE_FIELDS \
ngx_queue_t queue; \
struct sockaddr_in6 addr; \
int bufcnt; \
uv_buf_t* bufs; \
ssize_t status; \
uv_udp_send_cb send_cb; \
uv_buf_t bufsml[UV_REQ_BUFSML_SIZE]; \
#define UV_HANDLE_PRIVATE_FIELDS \
int flags; \
uv_handle_t* next_closing; \
#define UV_PRIVATE_REQ_TYPES /* empty */
#define UV_STREAM_PRIVATE_FIELDS \
uv_connect_t *connect_req; \
uv_shutdown_t *shutdown_req; \
uv__io_t read_watcher; \
uv__io_t write_watcher; \
ngx_queue_t write_queue; \
ngx_queue_t write_completed_queue; \
uv_connection_cb connection_cb; \
int delayed_error; \
int accepted_fd; \
int fd; \
#define UV_TCP_PRIVATE_FIELDS \
uv_idle_t* idle_handle; /* for UV_TCP_SINGLE_ACCEPT handles */ \
/* TODO: union or classes please! */
#define UV_HANDLE_PRIVATE_FIELDS \
int flags; \
uv_handle_t* next_closing; \
#define UV_UDP_PRIVATE_FIELDS \
int fd; \
uv_alloc_cb alloc_cb; \
uv_udp_recv_cb recv_cb; \
uv__io_t read_watcher; \
uv__io_t write_watcher; \
ngx_queue_t write_queue; \
ngx_queue_t write_completed_queue; \
#define UV_STREAM_PRIVATE_FIELDS \
uv_connect_t *connect_req; \
uv_shutdown_t *shutdown_req; \
uv__io_t read_watcher; \
uv__io_t write_watcher; \
ngx_queue_t write_queue; \
ngx_queue_t write_completed_queue; \
uv_connection_cb connection_cb; \
int delayed_error; \
int accepted_fd; \
int fd; \
/* UV_TCP, idle_handle is for UV_TCP_SINGLE_ACCEPT handles */
#define UV_TCP_PRIVATE_FIELDS \
uv_idle_t* idle_handle; \
/* UV_UDP */
#define UV_UDP_PRIVATE_FIELDS \
int fd; \
uv_alloc_cb alloc_cb; \
uv_udp_recv_cb recv_cb; \
uv__io_t read_watcher; \
uv__io_t write_watcher; \
ngx_queue_t write_queue; \
ngx_queue_t write_completed_queue; \
/* UV_NAMED_PIPE */
#define UV_PIPE_PRIVATE_FIELDS \
#define UV_PIPE_PRIVATE_FIELDS \
const char* pipe_fname; /* strdup'ed */
/* UV_POLL */
#define UV_POLL_PRIVATE_FIELDS \
int fd; \
#define UV_POLL_PRIVATE_FIELDS \
int fd; \
uv__io_t io_watcher;
/* UV_PREPARE */
#define UV_PREPARE_PRIVATE_FIELDS \
uv_prepare_cb prepare_cb; \
#define UV_PREPARE_PRIVATE_FIELDS \
uv_prepare_cb prepare_cb; \
ngx_queue_t queue;
/* UV_CHECK */
#define UV_CHECK_PRIVATE_FIELDS \
uv_check_cb check_cb; \
#define UV_CHECK_PRIVATE_FIELDS \
uv_check_cb check_cb; \
ngx_queue_t queue;
/* UV_IDLE */
#define UV_IDLE_PRIVATE_FIELDS \
uv_idle_cb idle_cb; \
#define UV_IDLE_PRIVATE_FIELDS \
uv_idle_cb idle_cb; \
ngx_queue_t queue;
/* UV_ASYNC */
#define UV_ASYNC_PRIVATE_FIELDS \
volatile sig_atomic_t pending; \
uv_async_cb async_cb; \
ngx_queue_t queue;
/* UV_TIMER */
#define UV_TIMER_PRIVATE_FIELDS \
/* RB_ENTRY(uv_timer_s) node; */ \
struct { \
@@ -249,66 +227,35 @@ struct uv__io_s {
uint64_t timeout; \
uint64_t repeat;
#define UV_GETADDRINFO_PRIVATE_FIELDS \
uv_getaddrinfo_cb cb; \
struct addrinfo* hints; \
char* hostname; \
char* service; \
struct addrinfo* res; \
#define UV_GETADDRINFO_PRIVATE_FIELDS \
uv_getaddrinfo_cb cb; \
struct addrinfo* hints; \
char* hostname; \
char* service; \
struct addrinfo* res; \
int retcode;
#define UV_PROCESS_PRIVATE_FIELDS \
ev_child child_watcher;
#define UV_PROCESS_PRIVATE_FIELDS \
ngx_queue_t queue; \
int errorno; \
#define UV_FS_PRIVATE_FIELDS \
struct stat statbuf; \
#define UV_FS_PRIVATE_FIELDS \
struct stat statbuf; \
uv_file file; \
eio_req* eio; \
#define UV_WORK_PRIVATE_FIELDS \
eio_req* eio;
#define UV_WORK_PRIVATE_FIELDS \
eio_req* eio;
#define UV_TTY_PRIVATE_FIELDS \
struct termios orig_termios; \
#define UV_TTY_PRIVATE_FIELDS \
struct termios orig_termios; \
int mode;
/* UV_FS_EVENT_PRIVATE_FIELDS */
#if defined(__linux__)
#define UV_SIGNAL_PRIVATE_FIELDS \
ngx_queue_t queue;
#define UV_FS_EVENT_PRIVATE_FIELDS \
ngx_queue_t watchers; \
uv_fs_event_cb cb; \
int wd; \
void* pad0; \
void* pad1; \
#elif defined(__APPLE__) \
|| defined(__FreeBSD__) \
|| defined(__DragonFly__) \
|| defined(__OpenBSD__) \
|| defined(__NetBSD__)
#define UV_FS_EVENT_PRIVATE_FIELDS \
ev_io event_watcher; \
uv_fs_event_cb cb; \
int fflags; \
int fd;
#elif defined(__sun)
#ifdef PORT_SOURCE_FILE
# define UV_FS_EVENT_PRIVATE_FIELDS \
uv_fs_event_cb cb; \
file_obj_t fo; \
int fd;
#else /* !PORT_SOURCE_FILE */
# define UV_FS_EVENT_PRIVATE_FIELDS
#endif
#else
/* Stub for platforms where the file watcher isn't implemented yet. */
#define UV_FS_EVENT_PRIVATE_FIELDS
#endif
#define UV_FS_EVENT_PRIVATE_FIELDS \
uv_fs_event_cb cb; \
UV_PLATFORM_FS_EVENT_FIELDS \
#endif /* UV_UNIX_H */

View File

@@ -29,12 +29,14 @@ typedef intptr_t ssize_t;
# define _SSIZE_T_DEFINED
#endif
#include <process.h>
#include <stdint.h>
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <process.h>
#include <signal.h>
#include <stdint.h>
#include <sys/stat.h>
#include "tree.h"
@@ -43,32 +45,50 @@ typedef intptr_t ssize_t;
#define MAX_PIPENAME_LEN 256
#ifndef S_IFLNK
# define S_IFLNK 0xA000
# define S_IFLNK 0xA000
#endif
/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
* the following signals already:
*
* #define SIGINT 2
* #define SIGILL 4
* #define SIGABRT_COMPAT 6
* #define SIGFPE 8
* #define SIGSEGV 11
* #define SIGTERM 15
* #define SIGBREAK 21
* #define SIGABRT 22
*
* The additional signals have values that are common on other Unix
* variants (Linux and Darwin)
*/
#define SIGHUP 1
#define SIGKILL 9
/*
* Guids and typedefs for winsock extension functions
* Mingw32 doesn't have these :-(
*/
#ifndef WSAID_ACCEPTEX
# define WSAID_ACCEPTEX \
{0xb5367df1, 0xcbac, 0x11cf, \
# define WSAID_ACCEPTEX \
{0xb5367df1, 0xcbac, 0x11cf, \
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
# define WSAID_CONNECTEX \
{0x25a207b9, 0xddf3, 0x4660, \
# define WSAID_CONNECTEX \
{0x25a207b9, 0xddf3, 0x4660, \
{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
# define WSAID_GETACCEPTEXSOCKADDRS \
{0xb5367df2, 0xcbac, 0x11cf, \
# define WSAID_GETACCEPTEXSOCKADDRS \
{0xb5367df2, 0xcbac, 0x11cf, \
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
# define WSAID_DISCONNECTEX \
{0x7fda2e11, 0x8630, 0x436f, \
# define WSAID_DISCONNECTEX \
{0x7fda2e11, 0x8630, 0x436f, \
{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
# define WSAID_TRANSMITFILE \
{0xb5367df0, 0xcbac, 0x11cf, \
# define WSAID_TRANSMITFILE \
{0xb5367df0, 0xcbac, 0x11cf, \
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
typedef BOOL PASCAL (*LPFN_ACCEPTEX)
@@ -246,272 +266,281 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
/* Counter to keep track of active udp streams */ \
unsigned int active_udp_streams;
#define UV_REQ_TYPE_PRIVATE \
/* TODO: remove the req suffix */ \
UV_ACCEPT, \
UV_FS_EVENT_REQ, \
UV_POLL_REQ, \
UV_PROCESS_EXIT, \
UV_PROCESS_CLOSE, \
UV_READ, \
UV_UDP_RECV, \
UV_WAKEUP,
#define UV_REQ_TYPE_PRIVATE \
/* TODO: remove the req suffix */ \
UV_ACCEPT, \
UV_FS_EVENT_REQ, \
UV_POLL_REQ, \
UV_PROCESS_EXIT, \
UV_READ, \
UV_UDP_RECV, \
UV_WAKEUP, \
UV_SIGNAL_REQ,
#define UV_REQ_PRIVATE_FIELDS \
union { \
/* Used by I/O operations */ \
struct { \
OVERLAPPED overlapped; \
size_t queued_bytes; \
}; \
}; \
#define UV_REQ_PRIVATE_FIELDS \
union { \
/* Used by I/O operations */ \
struct { \
OVERLAPPED overlapped; \
size_t queued_bytes; \
}; \
}; \
struct uv_req_s* next_req;
#define UV_WRITE_PRIVATE_FIELDS \
int ipc_header; \
uv_buf_t write_buffer; \
HANDLE event_handle; \
#define UV_WRITE_PRIVATE_FIELDS \
int ipc_header; \
uv_buf_t write_buffer; \
HANDLE event_handle; \
HANDLE wait_handle;
#define UV_CONNECT_PRIVATE_FIELDS \
#define UV_CONNECT_PRIVATE_FIELDS \
/* empty */
#define UV_SHUTDOWN_PRIVATE_FIELDS \
#define UV_SHUTDOWN_PRIVATE_FIELDS \
/* empty */
#define UV_UDP_SEND_PRIVATE_FIELDS \
#define UV_UDP_SEND_PRIVATE_FIELDS \
/* empty */
#define UV_PRIVATE_REQ_TYPES \
typedef struct uv_pipe_accept_s { \
UV_REQ_FIELDS \
HANDLE pipeHandle; \
struct uv_pipe_accept_s* next_pending; \
} uv_pipe_accept_t; \
\
typedef struct uv_tcp_accept_s { \
UV_REQ_FIELDS \
SOCKET accept_socket; \
char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
HANDLE event_handle; \
HANDLE wait_handle; \
struct uv_tcp_accept_s* next_pending; \
} uv_tcp_accept_t; \
\
typedef struct uv_read_s { \
UV_REQ_FIELDS \
HANDLE event_handle; \
HANDLE wait_handle; \
#define UV_PRIVATE_REQ_TYPES \
typedef struct uv_pipe_accept_s { \
UV_REQ_FIELDS \
HANDLE pipeHandle; \
struct uv_pipe_accept_s* next_pending; \
} uv_pipe_accept_t; \
\
typedef struct uv_tcp_accept_s { \
UV_REQ_FIELDS \
SOCKET accept_socket; \
char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
HANDLE event_handle; \
HANDLE wait_handle; \
struct uv_tcp_accept_s* next_pending; \
} uv_tcp_accept_t; \
\
typedef struct uv_read_s { \
UV_REQ_FIELDS \
HANDLE event_handle; \
HANDLE wait_handle; \
} uv_read_t;
#define uv_stream_connection_fields \
unsigned int write_reqs_pending; \
#define uv_stream_connection_fields \
unsigned int write_reqs_pending; \
uv_shutdown_t* shutdown_req;
#define uv_stream_server_fields \
#define uv_stream_server_fields \
uv_connection_cb connection_cb;
#define UV_STREAM_PRIVATE_FIELDS \
unsigned int reqs_pending; \
int activecnt; \
uv_read_t read_req; \
union { \
struct { uv_stream_connection_fields }; \
struct { uv_stream_server_fields }; \
#define UV_STREAM_PRIVATE_FIELDS \
unsigned int reqs_pending; \
int activecnt; \
uv_read_t read_req; \
union { \
struct { uv_stream_connection_fields }; \
struct { uv_stream_server_fields }; \
};
#define uv_tcp_server_fields \
uv_tcp_accept_t* accept_reqs; \
unsigned int processed_accepts; \
uv_tcp_accept_t* pending_accepts; \
#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;
#define uv_tcp_connection_fields \
uv_buf_t read_buffer; \
#define uv_tcp_connection_fields \
uv_buf_t read_buffer; \
LPFN_CONNECTEX func_connectex;
#define UV_TCP_PRIVATE_FIELDS \
SOCKET socket; \
int bind_error; \
union { \
struct { uv_tcp_server_fields }; \
struct { uv_tcp_connection_fields }; \
#define UV_TCP_PRIVATE_FIELDS \
SOCKET socket; \
int bind_error; \
union { \
struct { uv_tcp_server_fields }; \
struct { uv_tcp_connection_fields }; \
};
#define UV_UDP_PRIVATE_FIELDS \
SOCKET socket; \
unsigned int reqs_pending; \
int activecnt; \
uv_req_t recv_req; \
uv_buf_t recv_buffer; \
struct sockaddr_storage recv_from; \
int recv_from_len; \
uv_udp_recv_cb recv_cb; \
uv_alloc_cb alloc_cb; \
LPFN_WSARECV func_wsarecv; \
#define UV_UDP_PRIVATE_FIELDS \
SOCKET socket; \
unsigned int reqs_pending; \
int activecnt; \
uv_req_t recv_req; \
uv_buf_t recv_buffer; \
struct sockaddr_storage recv_from; \
int recv_from_len; \
uv_udp_recv_cb recv_cb; \
uv_alloc_cb alloc_cb; \
LPFN_WSARECV func_wsarecv; \
LPFN_WSARECVFROM func_wsarecvfrom;
#define uv_pipe_server_fields \
int pending_instances; \
uv_pipe_accept_t* accept_reqs; \
#define uv_pipe_server_fields \
int pending_instances; \
uv_pipe_accept_t* accept_reqs; \
uv_pipe_accept_t* pending_accepts;
#define uv_pipe_connection_fields \
uv_timer_t* eof_timer; \
uv_write_t ipc_header_write_req; \
int ipc_pid; \
uint64_t remaining_ipc_rawdata_bytes; \
unsigned char reserved[sizeof(void*)]; \
struct { \
WSAPROTOCOL_INFOW* socket_info; \
int tcp_connection; \
} pending_ipc_info; \
#define uv_pipe_connection_fields \
uv_timer_t* eof_timer; \
uv_write_t ipc_header_write_req; \
int ipc_pid; \
uint64_t remaining_ipc_rawdata_bytes; \
unsigned char reserved[sizeof(void*)]; \
struct { \
WSAPROTOCOL_INFOW* socket_info; \
int tcp_connection; \
} pending_ipc_info; \
uv_write_t* non_overlapped_writes_tail;
#define UV_PIPE_PRIVATE_FIELDS \
HANDLE handle; \
wchar_t* name; \
union { \
struct { uv_pipe_server_fields }; \
struct { uv_pipe_connection_fields }; \
#define UV_PIPE_PRIVATE_FIELDS \
HANDLE handle; \
WCHAR* name; \
union { \
struct { uv_pipe_server_fields }; \
struct { uv_pipe_connection_fields }; \
};
/* TODO: put the parser states in an union - TTY handles are always */
/* half-duplex so read-state can safely overlap write-state. */
#define UV_TTY_PRIVATE_FIELDS \
HANDLE handle; \
HANDLE read_line_handle; \
uv_buf_t read_line_buffer; \
HANDLE read_raw_wait; \
DWORD original_console_mode; \
/* Fields used for translating win */ \
/* keystrokes into vt100 characters */ \
char last_key[8]; \
unsigned char last_key_offset; \
unsigned char last_key_len; \
INPUT_RECORD last_input_record; \
WCHAR last_utf16_high_surrogate; \
/* utf8-to-utf16 conversion state */ \
unsigned char utf8_bytes_left; \
unsigned int utf8_codepoint; \
/* eol conversion state */ \
unsigned char previous_eol; \
/* ansi parser state */ \
unsigned char ansi_parser_state; \
unsigned char ansi_csi_argc; \
unsigned short ansi_csi_argv[4]; \
COORD saved_position; \
WORD saved_attributes;
#define UV_POLL_PRIVATE_FIELDS \
SOCKET socket; \
/* Used in fast mode */ \
SOCKET peer_socket; \
AFD_POLL_INFO afd_poll_info_1; \
AFD_POLL_INFO afd_poll_info_2; \
/* Used in fast and slow mode. */ \
uv_req_t poll_req_1; \
uv_req_t poll_req_2; \
unsigned char submitted_events_1; \
unsigned char submitted_events_2; \
unsigned char mask_events_1; \
unsigned char mask_events_2; \
unsigned char events;
#define UV_TIMER_PRIVATE_FIELDS \
RB_ENTRY(uv_timer_s) tree_entry; \
int64_t due; \
int64_t repeat; \
uv_timer_cb timer_cb;
#define UV_ASYNC_PRIVATE_FIELDS \
struct uv_req_s async_req; \
uv_async_cb async_cb; \
/* char to avoid alignment issues */ \
char volatile async_sent;
#define UV_PREPARE_PRIVATE_FIELDS \
uv_prepare_t* prepare_prev; \
uv_prepare_t* prepare_next; \
uv_prepare_cb prepare_cb;
#define UV_CHECK_PRIVATE_FIELDS \
uv_check_t* check_prev; \
uv_check_t* check_next; \
uv_check_cb check_cb;
#define UV_IDLE_PRIVATE_FIELDS \
uv_idle_t* idle_prev; \
uv_idle_t* idle_next; \
uv_idle_cb idle_cb;
#define UV_HANDLE_PRIVATE_FIELDS \
uv_handle_t* endgame_next; \
unsigned int flags;
#define UV_GETADDRINFO_PRIVATE_FIELDS \
uv_getaddrinfo_cb getaddrinfo_cb; \
void* alloc; \
wchar_t* node; \
wchar_t* service; \
struct addrinfoW* hints; \
struct addrinfoW* res; \
int retcode;
#define UV_PROCESS_PRIVATE_FIELDS \
struct uv_process_exit_s { \
UV_REQ_FIELDS \
} exit_req; \
struct uv_process_close_s { \
UV_REQ_FIELDS \
} close_req; \
BYTE* child_stdio_buffer; \
int exit_signal; \
DWORD spawn_errno; \
HANDLE wait_handle; \
HANDLE process_handle; \
HANDLE close_handle;
#define UV_FS_PRIVATE_FIELDS \
int flags; \
DWORD sys_errno_; \
union { \
/* TODO: remove me in 0.9. */ \
WCHAR* pathw; \
int fd; \
}; \
union { \
struct { \
int mode; \
WCHAR* new_pathw; \
int file_flags; \
int fd_out; \
void* buf; \
size_t length; \
int64_t offset; \
}; \
struct _stati64 stat; \
struct { \
double atime; \
double mtime; \
}; \
#define UV_TTY_PRIVATE_FIELDS \
HANDLE handle; \
union { \
struct { \
/* Used for readable TTY handles */ \
HANDLE read_line_handle; \
uv_buf_t read_line_buffer; \
HANDLE read_raw_wait; \
DWORD original_console_mode; \
/* Fields used for translating win keystrokes into vt100 characters */ \
char last_key[8]; \
unsigned char last_key_offset; \
unsigned char last_key_len; \
WCHAR last_utf16_high_surrogate; \
INPUT_RECORD last_input_record; \
}; \
struct { \
/* Used for writable TTY handles */ \
/* utf8-to-utf16 conversion state */ \
unsigned int utf8_codepoint; \
unsigned char utf8_bytes_left; \
/* eol conversion state */ \
unsigned char previous_eol; \
/* ansi parser state */ \
unsigned char ansi_parser_state; \
unsigned char ansi_csi_argc; \
unsigned short ansi_csi_argv[4]; \
COORD saved_position; \
WORD saved_attributes; \
}; \
};
#define UV_WORK_PRIVATE_FIELDS \
#define UV_POLL_PRIVATE_FIELDS \
SOCKET socket; \
/* Used in fast mode */ \
SOCKET peer_socket; \
AFD_POLL_INFO afd_poll_info_1; \
AFD_POLL_INFO afd_poll_info_2; \
/* Used in fast and slow mode. */ \
uv_req_t poll_req_1; \
uv_req_t poll_req_2; \
unsigned char submitted_events_1; \
unsigned char submitted_events_2; \
unsigned char mask_events_1; \
unsigned char mask_events_2; \
unsigned char events;
#define UV_FS_EVENT_PRIVATE_FIELDS \
struct uv_fs_event_req_s { \
UV_REQ_FIELDS \
} req; \
HANDLE dir_handle; \
int req_pending; \
uv_fs_event_cb cb; \
wchar_t* filew; \
wchar_t* short_filew; \
wchar_t* dirw; \
#define UV_TIMER_PRIVATE_FIELDS \
RB_ENTRY(uv_timer_s) tree_entry; \
int64_t due; \
int64_t repeat; \
uv_timer_cb timer_cb;
#define UV_ASYNC_PRIVATE_FIELDS \
struct uv_req_s async_req; \
uv_async_cb async_cb; \
/* char to avoid alignment issues */ \
char volatile async_sent;
#define UV_PREPARE_PRIVATE_FIELDS \
uv_prepare_t* prepare_prev; \
uv_prepare_t* prepare_next; \
uv_prepare_cb prepare_cb;
#define UV_CHECK_PRIVATE_FIELDS \
uv_check_t* check_prev; \
uv_check_t* check_next; \
uv_check_cb check_cb;
#define UV_IDLE_PRIVATE_FIELDS \
uv_idle_t* idle_prev; \
uv_idle_t* idle_next; \
uv_idle_cb idle_cb;
#define UV_HANDLE_PRIVATE_FIELDS \
uv_handle_t* endgame_next; \
unsigned int flags;
#define UV_GETADDRINFO_PRIVATE_FIELDS \
uv_getaddrinfo_cb getaddrinfo_cb; \
void* alloc; \
WCHAR* node; \
WCHAR* service; \
struct addrinfoW* hints; \
struct addrinfoW* res; \
int retcode;
#define UV_PROCESS_PRIVATE_FIELDS \
struct uv_process_exit_s { \
UV_REQ_FIELDS \
} exit_req; \
BYTE* child_stdio_buffer; \
uv_err_t spawn_error; \
int exit_signal; \
HANDLE wait_handle; \
HANDLE process_handle; \
volatile char exit_cb_pending;
#define UV_FS_PRIVATE_FIELDS \
int flags; \
DWORD sys_errno_; \
union { \
/* TODO: remove me in 0.9. */ \
WCHAR* pathw; \
int fd; \
}; \
union { \
struct { \
int mode; \
WCHAR* new_pathw; \
int file_flags; \
int fd_out; \
void* buf; \
size_t length; \
int64_t offset; \
}; \
struct _stati64 stat; \
struct { \
double atime; \
double mtime; \
}; \
};
#define UV_WORK_PRIVATE_FIELDS \
#define UV_FS_EVENT_PRIVATE_FIELDS \
struct uv_fs_event_req_s { \
UV_REQ_FIELDS \
} req; \
HANDLE dir_handle; \
int req_pending; \
uv_fs_event_cb cb; \
WCHAR* filew; \
WCHAR* short_filew; \
WCHAR* dirw; \
char* buffer;
int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size,
#define UV_SIGNAL_PRIVATE_FIELDS \
RB_ENTRY(uv_signal_s) tree_entry; \
struct uv_req_s signal_req; \
unsigned long pending_signum;
int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
char* utf8Buffer, size_t utf8Size);
int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer,
int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
size_t utf16Size);

292
deps/uv/include/uv.h vendored
View File

@@ -19,7 +19,7 @@
* IN THE SOFTWARE.
*/
/* See uv_loop_new for an introduction. */
/* See http://nikhilm.github.com/uvbook/ for an introduction. */
#ifndef UV_H
#define UV_H
@@ -53,6 +53,10 @@ extern "C" {
#include <stdint.h> /* int64_t */
#include <sys/types.h> /* size_t */
#if defined(__SVR4) && !defined(__unix__)
# define __unix__
#endif
#if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)
# include "uv-private/uv-unix.h"
#else
@@ -60,64 +64,64 @@ extern "C" {
#endif
/* Expand this list if necessary. */
#define UV_ERRNO_MAP(XX) \
XX( -1, UNKNOWN, "unknown error") \
XX( 0, OK, "success") \
XX( 1, EOF, "end of file") \
XX( 2, EADDRINFO, "getaddrinfo error") \
XX( 3, EACCES, "permission denied") \
XX( 4, EAGAIN, "no more processes") \
XX( 5, EADDRINUSE, "address already in use") \
XX( 6, EADDRNOTAVAIL, "") \
XX( 7, EAFNOSUPPORT, "") \
XX( 8, EALREADY, "") \
XX( 9, EBADF, "bad file descriptor") \
XX( 10, EBUSY, "resource busy or locked") \
XX( 11, ECONNABORTED, "software caused connection abort") \
XX( 12, ECONNREFUSED, "connection refused") \
XX( 13, ECONNRESET, "connection reset by peer") \
XX( 14, EDESTADDRREQ, "destination address required") \
XX( 15, EFAULT, "bad address in system call argument") \
XX( 16, EHOSTUNREACH, "host is unreachable") \
XX( 17, EINTR, "interrupted system call") \
XX( 18, EINVAL, "invalid argument") \
XX( 19, EISCONN, "socket is already connected") \
XX( 20, EMFILE, "too many open files") \
XX( 21, EMSGSIZE, "message too long") \
XX( 22, ENETDOWN, "network is down") \
XX( 23, ENETUNREACH, "network is unreachable") \
XX( 24, ENFILE, "file table overflow") \
XX( 25, ENOBUFS, "no buffer space available") \
XX( 26, ENOMEM, "not enough memory") \
XX( 27, ENOTDIR, "not a directory") \
XX( 28, EISDIR, "illegal operation on a directory") \
XX( 29, ENONET, "machine is not on the network") \
XX( 31, ENOTCONN, "socket is not connected") \
XX( 32, ENOTSOCK, "socket operation on non-socket") \
XX( 33, ENOTSUP, "operation not supported on socket") \
XX( 34, ENOENT, "no such file or directory") \
XX( 35, ENOSYS, "function not implemented") \
XX( 36, EPIPE, "broken pipe") \
XX( 37, EPROTO, "protocol error") \
XX( 38, EPROTONOSUPPORT, "protocol not supported") \
XX( 39, EPROTOTYPE, "protocol wrong type for socket") \
XX( 40, ETIMEDOUT, "connection timed out") \
XX( 41, ECHARSET, "") \
XX( 42, EAIFAMNOSUPPORT, "") \
XX( 44, EAISERVICE, "") \
XX( 45, EAISOCKTYPE, "") \
XX( 46, ESHUTDOWN, "") \
XX( 47, EEXIST, "file already exists") \
XX( 48, ESRCH, "no such process") \
XX( 49, ENAMETOOLONG, "name too long") \
XX( 50, EPERM, "operation not permitted") \
XX( 51, ELOOP, "too many symbolic links encountered") \
XX( 52, EXDEV, "cross-device link not permitted") \
XX( 53, ENOTEMPTY, "directory not empty") \
XX( 54, ENOSPC, "no space left on device") \
XX( 55, EIO, "i/o error") \
XX( 56, EROFS, "read-only file system" ) \
XX( 57, ENODEV, "no such device" ) \
#define UV_ERRNO_MAP(XX) \
XX( -1, UNKNOWN, "unknown error") \
XX( 0, OK, "success") \
XX( 1, EOF, "end of file") \
XX( 2, EADDRINFO, "getaddrinfo error") \
XX( 3, EACCES, "permission denied") \
XX( 4, EAGAIN, "no more processes") \
XX( 5, EADDRINUSE, "address already in use") \
XX( 6, EADDRNOTAVAIL, "") \
XX( 7, EAFNOSUPPORT, "") \
XX( 8, EALREADY, "") \
XX( 9, EBADF, "bad file descriptor") \
XX( 10, EBUSY, "resource busy or locked") \
XX( 11, ECONNABORTED, "software caused connection abort") \
XX( 12, ECONNREFUSED, "connection refused") \
XX( 13, ECONNRESET, "connection reset by peer") \
XX( 14, EDESTADDRREQ, "destination address required") \
XX( 15, EFAULT, "bad address in system call argument") \
XX( 16, EHOSTUNREACH, "host is unreachable") \
XX( 17, EINTR, "interrupted system call") \
XX( 18, EINVAL, "invalid argument") \
XX( 19, EISCONN, "socket is already connected") \
XX( 20, EMFILE, "too many open files") \
XX( 21, EMSGSIZE, "message too long") \
XX( 22, ENETDOWN, "network is down") \
XX( 23, ENETUNREACH, "network is unreachable") \
XX( 24, ENFILE, "file table overflow") \
XX( 25, ENOBUFS, "no buffer space available") \
XX( 26, ENOMEM, "not enough memory") \
XX( 27, ENOTDIR, "not a directory") \
XX( 28, EISDIR, "illegal operation on a directory") \
XX( 29, ENONET, "machine is not on the network") \
XX( 31, ENOTCONN, "socket is not connected") \
XX( 32, ENOTSOCK, "socket operation on non-socket") \
XX( 33, ENOTSUP, "operation not supported on socket") \
XX( 34, ENOENT, "no such file or directory") \
XX( 35, ENOSYS, "function not implemented") \
XX( 36, EPIPE, "broken pipe") \
XX( 37, EPROTO, "protocol error") \
XX( 38, EPROTONOSUPPORT, "protocol not supported") \
XX( 39, EPROTOTYPE, "protocol wrong type for socket") \
XX( 40, ETIMEDOUT, "connection timed out") \
XX( 41, ECHARSET, "") \
XX( 42, EAIFAMNOSUPPORT, "") \
XX( 44, EAISERVICE, "") \
XX( 45, EAISOCKTYPE, "") \
XX( 46, ESHUTDOWN, "") \
XX( 47, EEXIST, "file already exists") \
XX( 48, ESRCH, "no such process") \
XX( 49, ENAMETOOLONG, "name too long") \
XX( 50, EPERM, "operation not permitted") \
XX( 51, ELOOP, "too many symbolic links encountered") \
XX( 52, EXDEV, "cross-device link not permitted") \
XX( 53, ENOTEMPTY, "directory not empty") \
XX( 54, ENOSPC, "no space left on device") \
XX( 55, EIO, "i/o error") \
XX( 56, EROFS, "read-only file system" ) \
XX( 57, ENODEV, "no such device" ) \
XX( 58, ECANCELED, "operation canceled" )
@@ -128,29 +132,30 @@ typedef enum {
} uv_err_code;
#undef UV_ERRNO_GEN
#define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \
XX(CHECK, check) \
XX(FS_EVENT, fs_event) \
XX(FS_POLL, fs_poll) \
XX(IDLE, idle) \
XX(NAMED_PIPE, pipe) \
XX(POLL, poll) \
XX(PREPARE, prepare) \
XX(PROCESS, process) \
XX(TCP, tcp) \
XX(TIMER, timer) \
XX(TTY, tty) \
XX(UDP, udp) \
#define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \
XX(CHECK, check) \
XX(FS_EVENT, fs_event) \
XX(FS_POLL, fs_poll) \
XX(IDLE, idle) \
XX(NAMED_PIPE, pipe) \
XX(POLL, poll) \
XX(PREPARE, prepare) \
XX(PROCESS, process) \
XX(TCP, tcp) \
XX(TIMER, timer) \
XX(TTY, tty) \
XX(UDP, udp) \
XX(SIGNAL, signal) \
#define UV_REQ_TYPE_MAP(XX) \
XX(CONNECT, connect) \
XX(WRITE, write) \
XX(SHUTDOWN, shutdown) \
XX(UDP_SEND, udp_send) \
XX(FS, fs) \
XX(WORK, work) \
XX(GETADDRINFO, getaddrinfo) \
#define UV_REQ_TYPE_MAP(XX) \
XX(CONNECT, connect) \
XX(WRITE, write) \
XX(SHUTDOWN, shutdown) \
XX(UDP_SEND, udp_send) \
XX(FS, fs) \
XX(WORK, work) \
XX(GETADDRINFO, getaddrinfo) \
typedef enum {
UV_UNKNOWN_HANDLE = 0,
@@ -189,6 +194,7 @@ typedef struct uv_async_s uv_async_t;
typedef struct uv_process_s uv_process_t;
typedef struct uv_fs_event_s uv_fs_event_t;
typedef struct uv_fs_poll_s uv_fs_poll_t;
typedef struct uv_signal_s uv_signal_t;
/* Request types. */
typedef struct uv_req_s uv_req_t;
@@ -312,6 +318,9 @@ typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle,
const uv_statbuf_t* prev,
const uv_statbuf_t* curr);
typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum);
typedef enum {
UV_LEAVE_GROUP = 0,
UV_JOIN_GROUP
@@ -336,14 +345,14 @@ 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 \
/* public */ \
void* data; \
/* private */ \
ngx_queue_t active_queue; \
UV_REQ_PRIVATE_FIELDS \
/* read-only */ \
uv_req_type type; \
#define UV_REQ_FIELDS \
/* public */ \
void* data; \
/* private */ \
ngx_queue_t active_queue; \
UV_REQ_PRIVATE_FIELDS \
/* read-only */ \
uv_req_type type; \
/* Abstract base class of all requests. */
struct uv_req_s {
@@ -454,13 +463,13 @@ UV_EXTERN size_t uv_strlcpy(char* dst, const char* src, size_t size);
UV_EXTERN size_t uv_strlcat(char* dst, const char* src, size_t size);
#define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \
size_t write_queue_size; \
uv_alloc_cb alloc_cb; \
uv_read_cb read_cb; \
uv_read2_cb read2_cb; \
/* private */ \
#define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \
size_t write_queue_size; \
uv_alloc_cb alloc_cb; \
uv_read_cb read_cb; \
uv_read2_cb read2_cb; \
/* private */ \
UV_STREAM_PRIVATE_FIELDS
/*
@@ -1098,8 +1107,7 @@ UV_EXTERN int uv_async_send(uv_async_t* async);
/*
* uv_timer_t is a subclass of uv_handle_t.
*
* Wraps libev's ev_timer watcher. Used to get woken up at a specified time
* in the future.
* Used to get woken up at a specified time in the future.
*/
struct uv_timer_s {
UV_HANDLE_FIELDS
@@ -1108,8 +1116,22 @@ struct uv_timer_s {
UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* timer);
UV_EXTERN int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb,
int64_t timeout, int64_t repeat);
/*
* Start the timer. `timeout` and `repeat` are in milliseconds.
*
* If timeout is zero, the callback fires on the next tick of the event loop.
*
* If repeat is non-zero, the callback fires first after timeout milliseconds
* and then repeatedly after repeat milliseconds.
*
* timeout and repeat are signed integers but that will change in a future
* version of libuv. Don't pass in negative values, you'll get a nasty surprise
* when that change becomes effective.
*/
UV_EXTERN int uv_timer_start(uv_timer_t* timer,
uv_timer_cb cb,
int64_t timeout,
int64_t repeat);
UV_EXTERN int uv_timer_stop(uv_timer_t* timer);
@@ -1121,10 +1143,10 @@ UV_EXTERN int uv_timer_stop(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
* 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.
* Set the repeat value in milliseconds. Note that if the repeat value is set
* from a timer 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.
*/
UV_EXTERN void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat);
@@ -1529,14 +1551,17 @@ struct uv_fs_event_s {
struct uv_fs_poll_s {
UV_HANDLE_FIELDS
/* Private, don't touch. */
int busy_polling; /* TODO(bnoordhuis) Fold into flags field. */
unsigned int interval;
uint64_t start_time;
char* path;
uv_fs_poll_cb poll_cb;
uv_timer_t timer_handle;
uv_fs_t* fs_req;
uv_statbuf_t statbuf;
void* poll_ctx;
/* v0.8 ABI compatibility */
char padding[sizeof(int)
+ sizeof(unsigned int)
+ sizeof(uint64_t)
+ sizeof(char*)
+ sizeof(uv_fs_poll_cb)
+ sizeof(uv_timer_t)
+ sizeof(uv_fs_t*)
+ sizeof(uv_statbuf_t)
- sizeof(void*)];
};
UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle);
@@ -1563,6 +1588,46 @@ UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle,
UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle);
/*
* UNIX signal handling on a per-event loop basis. The implementation is not
* ultra efficient so don't go creating a million event loops with a million
* signal watchers.
*
* TODO(bnoordhuis) As of 2012-08-10 only the default event loop supports
* signals. That will be fixed.
*
* Some signal support is available on Windows:
*
* SIGINT is normally delivered when the user presses CTRL+C. However, like
* on Unix, it is not generated when terminal raw mode is enabled.
*
* SIGBREAK is delivered when the user pressed CTRL+BREAK.
*
* SIGHUP is generated when the user closes the console window. On SIGHUP the
* program is given approximately 10 seconds to perform cleanup. After that
* Windows will unconditionally terminate it.
*
* Watchers for other signals can be successfully created, but these signals
* are never generated. These signals are: SIGILL, SIGABRT, SIGFPE, SIGSEGV,
* SIGTERM and SIGKILL.
*
* Note that calls to raise() or abort() to programmatically raise a signal are
* not detected by libuv; these will not trigger a signal watcher.
*/
struct uv_signal_s {
UV_HANDLE_FIELDS
uv_signal_cb signal_cb;
UV_SIGNAL_PRIVATE_FIELDS
int signum;
};
/* These functions are no-ops on Windows. */
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum);
int uv_signal_stop(uv_signal_t* handle);
/*
* Gets load avg
* See: http://en.wikipedia.org/wiki/Load_(computing)
@@ -1772,8 +1837,6 @@ struct uv_counters_s {
struct uv_loop_s {
UV_LOOP_PRIVATE_FIELDS
/* Diagnostic counters */
uv_counters_t counters;
/* The last error */
uv_err_t last_err;
/* Loop reference counting */
@@ -1800,6 +1863,7 @@ struct uv_loop_s {
#undef UV_FS_REQ_PRIVATE_FIELDS
#undef UV_WORK_PRIVATE_FIELDS
#undef UV_FS_EVENT_PRIVATE_FIELDS
#undef UV_SIGNAL_PRIVATE_FIELDS
#undef UV_LOOP_PRIVATE_FIELDS
#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS

150
deps/uv/src/fs-poll.c vendored
View File

@@ -26,24 +26,29 @@
#include <stdlib.h>
#include <string.h>
struct poll_ctx {
uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
int busy_polling;
unsigned int interval;
uint64_t start_time;
uv_loop_t* loop;
uv_fs_poll_cb poll_cb;
uv_timer_t timer_handle;
uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
uv_statbuf_t statbuf;
char path[1]; /* variable length */
};
static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b);
static void timer_cb(uv_timer_t* timer, int status);
static void poll_cb(uv_fs_t* req);
static void timer_cb(uv_timer_t* timer, int status);
static void timer_close_cb(uv_handle_t* handle);
static uv_statbuf_t zero_statbuf;
int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
/* TODO(bnoordhuis) Mark fs_req internal. */
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
loop->counters.fs_poll_init++;
if (uv_timer_init(loop, &handle->timer_handle))
return -1;
handle->timer_handle.flags |= UV__HANDLE_INTERNAL;
uv__handle_unref(&handle->timer_handle);
return 0;
}
@@ -52,30 +57,37 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
uv_fs_poll_cb cb,
const char* path,
unsigned int interval) {
uv_fs_t* req;
struct poll_ctx* ctx;
uv_loop_t* loop;
size_t len;
if (uv__is_active(handle))
return 0;
len = strlen(path) + 1;
req = malloc(sizeof(*req) + len);
loop = handle->loop;
len = strlen(path);
ctx = calloc(1, sizeof(*ctx) + len);
if (req == NULL)
return uv__set_artificial_error(handle->loop, UV_ENOMEM);
if (ctx == NULL)
return uv__set_artificial_error(loop, UV_ENOMEM);
req->data = handle;
handle->path = memcpy(req + 1, path, len);
handle->fs_req = req;
handle->poll_cb = cb;
handle->interval = interval ? interval : 1;
handle->start_time = uv_now(handle->loop);
handle->busy_polling = 0;
memset(&handle->statbuf, 0, sizeof(handle->statbuf));
ctx->loop = loop;
ctx->poll_cb = cb;
ctx->interval = interval ? interval : 1;
ctx->start_time = uv_now(loop);
ctx->parent_handle = handle;
memcpy(ctx->path, path, len + 1);
if (uv_fs_stat(handle->loop, handle->fs_req, handle->path, poll_cb))
if (uv_timer_init(loop, &ctx->timer_handle))
abort();
ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
uv__handle_unref(&ctx->timer_handle);
if (uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb))
abort();
handle->poll_ctx = ctx;
uv__handle_start(handle);
return 0;
@@ -83,25 +95,19 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
int uv_fs_poll_stop(uv_fs_poll_t* handle) {
struct poll_ctx* ctx;
if (!uv__is_active(handle))
return 0;
/* Don't free the fs req if it's active. Signal poll_cb that it needs to free
* the req by removing the handle backlink.
*
* TODO(bnoordhuis) Have uv-unix postpone the close callback until the req
* finishes so we don't need this pointer / lifecycle hackery. The callback
* always runs on the next tick now.
*/
if (handle->fs_req->data)
handle->fs_req->data = NULL;
else
free(handle->fs_req);
ctx = handle->poll_ctx;
assert(ctx != NULL);
assert(ctx->parent_handle != NULL);
handle->fs_req = NULL;
handle->path = NULL;
ctx->parent_handle = NULL;
uv_timer_stop(&ctx->timer_handle);
uv_timer_stop(&handle->timer_handle);
handle->poll_ctx = NULL;
uv__handle_stop(handle);
return 0;
@@ -110,73 +116,75 @@ int uv_fs_poll_stop(uv_fs_poll_t* handle) {
void uv__fs_poll_close(uv_fs_poll_t* handle) {
uv_fs_poll_stop(handle);
uv_close((uv_handle_t*)&handle->timer_handle, NULL);
}
static void timer_cb(uv_timer_t* timer, int status) {
uv_fs_poll_t* handle;
struct poll_ctx* ctx;
handle = container_of(timer, uv_fs_poll_t, timer_handle);
handle->start_time = uv_now(handle->loop);
handle->fs_req->data = handle;
ctx = container_of(timer, struct poll_ctx, timer_handle);
if (uv_fs_stat(handle->loop, handle->fs_req, handle->path, poll_cb))
if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
return;
}
assert(ctx->parent_handle->poll_ctx == ctx);
ctx->start_time = uv_now(ctx->loop);
if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
abort();
assert(uv__is_active(handle));
}
static void poll_cb(uv_fs_t* req) {
uv_statbuf_t* statbuf;
uv_fs_poll_t* handle;
struct poll_ctx* ctx;
uint64_t interval;
handle = req->data;
ctx = container_of(req, struct poll_ctx, fs_req);
if (handle == NULL) /* Handle has been stopped or closed. */
goto out;
assert(req == handle->fs_req);
if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
uv_fs_req_cleanup(req);
return;
}
if (req->result != 0) {
if (handle->busy_polling != -req->errorno) {
uv__set_artificial_error(handle->loop, req->errorno);
handle->poll_cb(handle, -1, &handle->statbuf, &zero_statbuf);
handle->busy_polling = -req->errorno;
if (ctx->busy_polling != -req->errorno) {
uv__set_artificial_error(ctx->loop, req->errorno);
ctx->poll_cb(ctx->parent_handle, -1, &ctx->statbuf, &zero_statbuf);
ctx->busy_polling = -req->errorno;
}
goto out;
}
statbuf = req->ptr;
if (handle->busy_polling != 0)
if (handle->busy_polling < 0 || !statbuf_eq(&handle->statbuf, statbuf))
handle->poll_cb(handle, 0, &handle->statbuf, statbuf);
if (ctx->busy_polling != 0)
if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
handle->statbuf = *statbuf;
handle->busy_polling = 1;
ctx->statbuf = *statbuf;
ctx->busy_polling = 1;
out:
uv_fs_req_cleanup(req);
if (req->data == NULL) { /* Handle has been stopped or closed. */
free(req);
return;
}
req->data = NULL; /* Tell uv_fs_poll_stop() it's safe to free the req. */
/* Reschedule timer, subtract the delay from doing the stat(). */
interval = handle->interval;
interval -= (uv_now(handle->loop) - handle->start_time) % interval;
interval = ctx->interval;
interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
if (uv_timer_start(&handle->timer_handle, timer_cb, interval, 0))
if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
abort();
}
static void timer_close_cb(uv_handle_t* handle) {
free(container_of(handle, struct poll_ctx, timer_handle));
}
static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b) {
#ifdef _WIN32
return a->st_mtime == b->st_mtime

View File

@@ -65,8 +65,6 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
return uv__set_sys_error(loop, errno);
uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
loop->counters.async_init++;
handle->async_cb = async_cb;
handle->pending = 0;

View File

@@ -116,6 +116,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
uv__fs_poll_close((uv_fs_poll_t*)handle);
break;
case UV_SIGNAL:
uv__signal_close((uv_signal_t*)handle);
break;
default:
assert(0);
}
@@ -143,6 +147,7 @@ static void uv__finish_close(uv_handle_t* handle) {
case UV_FS_EVENT:
case UV_FS_POLL:
case UV_POLL:
case UV_SIGNAL:
break;
case UV_NAMED_PIPE:

View File

@@ -32,10 +32,19 @@
#define NANOSEC ((uint64_t) 1e9)
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv_hrtime() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
void uv_loadavg(double avg[3]) {
@@ -73,7 +82,6 @@ int uv_fs_event_init(uv_loop_t* loop,
const char* filename,
uv_fs_event_cb cb,
int flags) {
loop->counters.fs_event_init++;
uv__set_sys_error(loop, ENOSYS);
return -1;
}

View File

@@ -43,6 +43,16 @@
static char *process_title;
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
#if TARGET_OS_IPHONE
/* see: http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
uint64_t uv_hrtime() {

View File

@@ -54,10 +54,19 @@
static char *process_title;
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}

42
deps/uv/src/unix/fs.c vendored
View File

@@ -72,6 +72,7 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type,
req->result = 0;
req->ptr = NULL;
req->path = path ? strdup(path) : NULL;
req->file = -1;
req->errorno = 0;
req->eio = NULL;
@@ -85,7 +86,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
if (req->cb)
uv__req_unregister(req->loop, req);
free(req->path);
free((void*)req->path);
req->path = NULL;
switch (req->fs_type) {
@@ -445,6 +446,20 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
}
#if defined(__APPLE__) && defined(F_FULLFSYNC)
ssize_t uv__fs_fdatasync(uv_file file) {
return fcntl(file, F_FULLFSYNC);
}
void uv__fs_fdatasync_work(eio_req* eio) {
uv_fs_t* req = eio->data;
eio->result = uv__fs_fdatasync(req->file);
}
#endif
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
char* path = NULL;
#if defined(__FreeBSD__) \
@@ -453,6 +468,31 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
* do a full fsync instead.
*/
WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fsync, ARGS1(file))
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
/* OSX >= 10.6 does have fdatasync, but better use fcntl anyway */
uv_fs_req_init(loop, req, UV_FS_FDATASYNC, path, cb);
req->file = file;
if (cb) {
/* async */
req->eio = eio_custom(uv__fs_fdatasync_work,
EIO_PRI_DEFAULT,
uv__fs_after,
req,
&loop->uv_eio_channel);
if (req->eio == NULL) {
uv__set_sys_error(loop, ENOMEM);
return -1;
}
} else {
/* sync */
req->result = uv__fs_fdatasync(file);
if (req->result) {
uv__set_sys_error(loop, errno);
}
return req->result;
}
return 0;
#else
WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fdatasync, ARGS1(file))
#endif

View File

@@ -82,7 +82,7 @@
#define UV__IO_WRITE EV_WRITE
#define UV__IO_ERROR EV_ERROR
/* flags */
/* handle flags */
enum {
UV_CLOSING = 0x01, /* uv_close() called but not finished. */
UV_CLOSED = 0x02, /* close(2) finished. */
@@ -97,10 +97,14 @@ enum {
UV_TCP_SINGLE_ACCEPT = 0x400 /* Only accept() when idle. */
};
/* loop flags */
enum {
UV_LOOP_EIO_INITIALIZED = 1
};
inline static void uv__req_init(uv_loop_t* loop,
uv_req_t* req,
uv_req_type type) {
loop->counters.req_init++;
req->type = type;
uv__req_register(loop, req);
}
@@ -153,6 +157,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
void uv__run_timers(uv_loop_t* loop);
unsigned int uv__next_timeout(uv_loop_t* loop);
/* signal */
void uv__signal_close(uv_signal_t* handle);
void uv__signal_unregister(uv_loop_t* loop);
/* platform specific */
int uv__platform_loop_init(uv_loop_t* loop, int default_loop);
void uv__platform_loop_delete(uv_loop_t* loop);
/* various */
void uv__async_close(uv_async_t* handle);
void uv__check_close(uv_check_t* handle);

View File

@@ -90,8 +90,6 @@ int uv_fs_event_init(uv_loop_t* loop,
int flags) {
int fd;
loop->counters.fs_event_init++;
/* We don't support any flags yet. */
assert(!flags);

View File

@@ -176,8 +176,6 @@ int uv_fs_event_init(uv_loop_t* loop,
int events;
int wd;
loop->counters.fs_event_init++;
/* We don't support any flags yet. */
assert(!flags);

View File

@@ -63,15 +63,31 @@ static struct {
size_t len;
} process_title;
static void read_models(unsigned int numcpus, uv_cpu_info_t* ci);
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
static void read_times(unsigned int numcpus, uv_cpu_info_t* ci);
static unsigned long read_cpufreq(unsigned int cpunum);
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
loop->inotify_watchers = NULL;
loop->inotify_fd = -1;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->inotify_fd == -1) return;
uv__io_stop(loop, &loop->inotify_read_watcher);
close(loop->inotify_fd);
loop->inotify_fd = -1;
}
/*
* There's probably some way to get time from Linux than gettimeofday(). What
* it is, I don't know.
*/
uint64_t uv_hrtime() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
@@ -301,84 +317,166 @@ uv_err_t uv_uptime(double* uptime) {
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
int numcpus = 0, i = 0;
unsigned long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr;
char line[512], speedPath[256], model[512];
FILE *fpStat = fopen("/proc/stat", "r");
FILE *fpModel = fopen("/proc/cpuinfo", "r");
FILE *fpSpeed;
uv_cpu_info_t* cpu_info;
unsigned int numcpus;
uv_cpu_info_t* ci;
if (fpModel) {
while (fgets(line, 511, fpModel) != NULL) {
if (strncmp(line, "model name", 10) == 0) {
numcpus++;
if (numcpus == 1) {
char *p = strchr(line, ':') + 2;
strcpy(model, p);
model[strlen(model)-1] = 0;
}
} else if (strncmp(line, "cpu MHz", 7) == 0) {
if (numcpus == 1) {
sscanf(line, "%*s %*s : %u", &cpuspeed);
}
}
}
fclose(fpModel);
}
*cpu_infos = NULL;
*count = 0;
*cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t));
if (!(*cpu_infos)) {
return uv__new_artificial_error(UV_ENOMEM);
}
numcpus = sysconf(_SC_NPROCESSORS_ONLN);
assert(numcpus != (unsigned int) -1);
assert(numcpus != 0);
ci = calloc(numcpus, sizeof(*ci));
if (ci == NULL)
return uv__new_sys_error(ENOMEM);
read_speeds(numcpus, ci);
read_models(numcpus, ci);
read_times(numcpus, ci);
*cpu_infos = ci;
*count = numcpus;
cpu_info = *cpu_infos;
if (fpStat) {
while (fgets(line, 511, fpStat) != NULL) {
if (strncmp(line, "cpu ", 4) == 0) {
continue;
} else if (strncmp(line, "cpu", 3) != 0) {
break;
}
sscanf(line, "%*s %lu %lu %lu %lu %*s %lu",
&ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr);
snprintf(speedPath, sizeof(speedPath),
"/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i);
fpSpeed = fopen(speedPath, "r");
if (fpSpeed) {
if (fgets(line, 511, fpSpeed) != NULL) {
sscanf(line, "%u", &cpuspeed);
cpuspeed /= 1000;
}
fclose(fpSpeed);
}
cpu_info->cpu_times.user = ticks_user * multiplier;
cpu_info->cpu_times.nice = ticks_nice * multiplier;
cpu_info->cpu_times.sys = ticks_sys * multiplier;
cpu_info->cpu_times.idle = ticks_idle * multiplier;
cpu_info->cpu_times.irq = ticks_intr * multiplier;
cpu_info->model = strdup(model);
cpu_info->speed = cpuspeed;
cpu_info++;
}
fclose(fpStat);
}
return uv_ok_;
}
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
unsigned int num;
for (num = 0; num < numcpus; num++)
ci[num].speed = read_cpufreq(num) / 1000;
}
static void read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
#if defined(__i386__) || defined(__x86_64__)
static const char marker[] = "model name\t: ";
#elif defined(__arm__)
static const char marker[] = "Processor\t: ";
#elif defined(__mips__)
static const char marker[] = "cpu model\t\t: ";
#else
# warning uv_cpu_info() is not supported on this architecture.
static const char marker[] = "(dummy)";
#endif
unsigned int num;
char buf[1024];
char* model;
FILE* fp;
fp = fopen("/proc/cpuinfo", "r");
if (fp == NULL)
return;
num = 0;
while (fgets(buf, sizeof(buf), fp)) {
if (num >= numcpus)
break;
if (strncmp(buf, marker, sizeof(marker) - 1))
continue;
model = buf + sizeof(marker) - 1;
model = strndup(model, strlen(model) - 1); /* strip newline */
ci[num++].model = model;
}
fclose(fp);
}
static void read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
unsigned long clock_ticks;
struct uv_cpu_times_s ts;
unsigned long user;
unsigned long nice;
unsigned long sys;
unsigned long idle;
unsigned long dummy;
unsigned long irq;
unsigned int num;
unsigned int len;
char buf[1024];
FILE* fp;
clock_ticks = sysconf(_SC_CLK_TCK);
assert(clock_ticks != (unsigned long) -1);
assert(clock_ticks != 0);
fp = fopen("/proc/stat", "r");
if (fp == NULL)
return;
if (!fgets(buf, sizeof(buf), fp))
abort();
num = 0;
while (fgets(buf, sizeof(buf), fp)) {
if (num >= numcpus)
break;
if (strncmp(buf, "cpu", 3))
break;
/* skip "cpu<num> " marker */
{
unsigned int n = num;
for (len = sizeof("cpu0"); n /= 10; len++);
assert(sscanf(buf, "cpu%u ", &n) == 1 && n == num);
}
/* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
* guest, guest_nice but we're only interested in the first four + irq.
*
* Don't use %*s to skip fields or %ll to read straight into the uint64_t
* fields, they're not allowed in C89 mode.
*/
if (6 != sscanf(buf + len,
"%lu %lu %lu %lu %lu %lu",
&user,
&nice,
&sys,
&idle,
&dummy,
&irq))
abort();
ts.user = clock_ticks * user;
ts.nice = clock_ticks * nice;
ts.sys = clock_ticks * sys;
ts.idle = clock_ticks * idle;
ts.irq = clock_ticks * irq;
ci[num++].cpu_times = ts;
}
fclose(fp);
}
static unsigned long read_cpufreq(unsigned int cpunum) {
unsigned long val;
char buf[1024];
FILE* fp;
snprintf(buf,
sizeof(buf),
"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
cpunum);
fp = fopen(buf, "r");
if (fp == NULL)
return 0;
val = 0;
fscanf(fp, "%lu", &val);
fclose(fp);
return val;
}
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
int i;

View File

@@ -25,7 +25,6 @@
#define UV_LOOP_WATCHER_DEFINE(name, type) \
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
loop->counters.name##_init++; \
handle->name##_cb = NULL; \
return 0; \
} \

View File

@@ -28,10 +28,13 @@
int uv__loop_init(uv_loop_t* loop, int default_loop) {
unsigned int i;
int flags;
#if HAVE_KQUEUE
int flags = EVBACKEND_KQUEUE;
flags = EVBACKEND_KQUEUE;
#else
int flags = EVFLAG_AUTO;
flags = EVFLAG_AUTO;
#endif
memset(loop, 0, sizeof(*loop));
@@ -44,6 +47,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
ngx_queue_init(&loop->prepare_handles);
ngx_queue_init(&loop->handle_queue);
loop->closing_handles = NULL;
loop->signal_ctx = NULL;
loop->time = uv_hrtime() / 1000000;
loop->async_pipefd[0] = -1;
loop->async_pipefd[1] = -1;
@@ -51,28 +55,22 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
ev_set_userdata(loop->ev, loop);
eio_channel_init(&loop->uv_eio_channel, loop);
#if __linux__
loop->inotify_watchers = NULL;
loop->inotify_fd = -1;
#endif
#if HAVE_PORTS_FS
loop->fs_fd = -1;
#endif
uv_signal_init(loop, &loop->child_watcher);
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++)
ngx_queue_init(loop->process_handles + i);
if (uv__platform_loop_init(loop, default_loop))
return -1;
return 0;
}
void uv__loop_delete(uv_loop_t* loop) {
uv__platform_loop_delete(loop);
uv__signal_unregister(loop);
ev_loop_destroy(loop->ev);
#if __linux__
if (loop->inotify_fd != -1) {
uv__io_stop(loop, &loop->inotify_read_watcher);
close(loop->inotify_fd);
loop->inotify_fd = -1;
}
#endif
#if HAVE_PORTS_FS
if (loop->fs_fd != -1)
close(loop->fs_fd);
#endif
}

View File

@@ -35,10 +35,19 @@
#define NANOSEC ((uint64_t) 1e9)
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
void uv_loadavg(double avg[3]) {

View File

@@ -43,10 +43,19 @@
static char *process_title;
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
}
uint64_t uv_hrtime(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * NANOSEC + ts.tv_nsec);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}

View File

@@ -34,7 +34,6 @@ static void uv__pipe_accept(uv_loop_t* loop, uv__io_t* w, int events);
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
loop->counters.pipe_init++;
handle->shutdown_req = NULL;
handle->connect_req = NULL;
handle->pipe_fname = NULL;

View File

@@ -54,8 +54,6 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, int events) {
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
loop->counters.poll_init++;
handle->fd = fd;
handle->poll_cb = NULL;
uv__io_init(&handle->io_watcher, uv__poll_io, fd, 0);

View File

@@ -22,13 +22,16 @@
#include "uv.h"
#include "internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#ifdef __APPLE__
# include <TargetConditionals.h>
@@ -42,26 +45,71 @@ extern char **environ;
#endif
static void uv__chld(EV_P_ ev_child* watcher, int revents) {
int status = watcher->rstatus;
int exit_status = 0;
int term_signal = 0;
uv_process_t *process = watcher->data;
static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) {
assert(pid > 0);
return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles);
}
assert(&process->child_watcher == watcher);
assert(revents & EV_CHILD);
ev_child_stop(EV_A_ &process->child_watcher);
static uv_process_t* uv__process_find(uv_loop_t* loop, int pid) {
uv_process_t* handle;
ngx_queue_t* h;
ngx_queue_t* q;
if (WIFEXITED(status)) {
exit_status = WEXITSTATUS(status);
h = uv__process_queue(loop, pid);
ngx_queue_foreach(q, h) {
handle = ngx_queue_data(q, uv_process_t, queue);
if (handle->pid == pid) return handle;
}
if (WIFSIGNALED(status)) {
term_signal = WTERMSIG(status);
}
return NULL;
}
static void uv__chld(uv_signal_t* handle, int signum) {
uv_process_t* process;
int exit_status;
int term_signal;
int status;
pid_t pid;
assert(signum == SIGCHLD);
for (;;) {
pid = waitpid(-1, &status, WNOHANG);
if (pid == 0)
return;
if (pid == -1) {
if (errno == ECHILD)
return; /* XXX stop signal watcher? */
else
abort();
}
process = uv__process_find(handle->loop, pid);
if (process == NULL)
continue; /* XXX bug? abort? */
if (process->exit_cb == NULL)
continue;
exit_status = 0;
term_signal = 0;
if (WIFEXITED(status))
exit_status = WEXITSTATUS(status);
if (WIFSIGNALED(status))
term_signal = WTERMSIG(status);
if (process->errorno) {
uv__set_sys_error(process->loop, process->errorno);
exit_status = -1; /* execve() failed */
}
if (process->exit_cb) {
process->exit_cb(process, exit_status, term_signal);
}
}
@@ -122,8 +170,7 @@ int uv__make_pipe(int fds[2], int flags) {
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success.
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2],
int writable) {
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
int fd = -1;
switch (container->flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
UV_INHERIT_STREAM)) {
@@ -151,7 +198,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2],
return -1;
}
fds[writable ? 1 : 0] = fd;
fds[1] = fd;
return 0;
default:
@@ -174,16 +221,19 @@ static int uv__process_stdio_flags(uv_stdio_container_t* container,
}
static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2],
static int uv__process_open_stream(uv_stdio_container_t* container,
int fds[2],
int writable) {
int fd = fds[writable ? 1 : 0];
int child_fd = fds[writable ? 0 : 1];
int child_fd;
int flags;
int fd;
fd = fds[0];
child_fd = fds[1];
/* No need to create stream */
if (!(container->flags & UV_CREATE_PIPE) || fd < 0) {
if (!(container->flags & UV_CREATE_PIPE) || fd < 0)
return 0;
}
assert(child_fd >= 0);
close(child_fd);
@@ -197,62 +247,78 @@ static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2],
static void uv__process_close_stream(uv_stdio_container_t* container) {
if (!(container->flags & UV_CREATE_PIPE)) return;
uv__stream_close((uv_stream_t*)container->data.stream);
}
static void uv__write_int(int fd, int val) {
ssize_t n;
do
n = write(fd, &val, sizeof(val));
while (n == -1 && errno == EINTR);
if (n == -1 && errno == EPIPE)
return; /* parent process has quit */
assert(n == sizeof(val));
}
static void uv__process_child_init(uv_process_options_t options,
int stdio_count,
int* pipes) {
int (*pipes)[2],
int error_fd) {
int close_fd;
int use_fd;
int i;
if (options.flags & UV_PROCESS_DETACHED) {
if (options.flags & UV_PROCESS_DETACHED)
setsid();
}
/* Dup fds */
for (i = 0; i < stdio_count; i++) {
/*
* stdin has swapped ends of pipe
* (it's the only one readable stream)
*/
int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2];
int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1];
close_fd = pipes[i][0];
use_fd = pipes[i][1];
if (use_fd >= 0) {
if (use_fd >= 0)
close(close_fd);
} else if (i < 3) {
/* `/dev/null` stdin, stdout, stderr even if they've flag UV_IGNORE */
else if (i >= 3)
continue;
else {
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
* set
*/
use_fd = open("/dev/null", i == 0 ? O_RDONLY : O_RDWR);
if (use_fd < 0) {
if (use_fd == -1) {
uv__write_int(error_fd, errno);
perror("failed to open stdio");
_exit(127);
}
} else {
continue;
}
if (i != use_fd) {
if (i == use_fd)
uv__cloexec(use_fd, 0);
else {
dup2(use_fd, i);
close(use_fd);
} else {
uv__cloexec(use_fd, 0);
}
}
if (options.cwd && chdir(options.cwd)) {
uv__write_int(error_fd, errno);
perror("chdir()");
_exit(127);
}
if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
uv__write_int(error_fd, errno);
perror("setgid()");
_exit(127);
}
if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
uv__write_int(error_fd, errno);
perror("setuid()");
_exit(127);
}
@@ -260,63 +326,57 @@ static void uv__process_child_init(uv_process_options_t options,
environ = options.env;
execvp(options.file, options.args);
uv__write_int(error_fd, errno);
perror("execvp()");
_exit(127);
}
#ifndef SPAWN_WAIT_EXEC
# define SPAWN_WAIT_EXEC 1
#endif
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
uv_process_options_t options) {
/*
* Save environ in the case that we get it clobbered
* by the child process.
*/
char** save_our_env = environ;
int stdio_count = options.stdio_count < 3 ? 3 : options.stdio_count;
int* pipes = malloc(2 * stdio_count * sizeof(int));
#if SPAWN_WAIT_EXEC
int uv_spawn(uv_loop_t* loop,
uv_process_t* process,
const uv_process_options_t options) {
int signal_pipe[2] = { -1, -1 };
struct pollfd pfd;
#endif
int status;
int (*pipes)[2];
int stdio_count;
ngx_queue_t* q;
ssize_t r;
pid_t pid;
int i;
if (pipes == NULL) {
errno = ENOMEM;
goto error;
}
assert(options.file != NULL);
assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
UV_PROCESS_DETACHED |
UV_PROCESS_SETGID |
UV_PROCESS_SETUID)));
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
loop->counters.process_init++;
uv__handle_start(process);
ngx_queue_init(&process->queue);
process->exit_cb = options.exit_cb;
stdio_count = options.stdio_count;
if (stdio_count < 3)
stdio_count = 3;
/* Init pipe pairs */
for (i = 0; i < stdio_count; i++) {
pipes[i * 2] = -1;
pipes[i * 2 + 1] = -1;
pipes = malloc(stdio_count * sizeof(*pipes));
if (pipes == NULL) {
errno = ENOMEM;
goto error;
}
/* Create socketpairs/pipes, or use raw fd */
for (i = 0; i < options.stdio_count; i++) {
if (uv__process_init_stdio(&options.stdio[i], pipes + i * 2, i != 0)) {
for (i = 0; i < stdio_count; i++) {
pipes[i][0] = -1;
pipes[i][1] = -1;
}
for (i = 0; i < options.stdio_count; i++)
if (uv__process_init_stdio(options.stdio + i, pipes[i]))
goto error;
}
/* swap stdin file descriptors, it's the only writable stream */
{
int* p = pipes[0];
int t = p[0];
p[0] = p[1];
p[1] = t;
}
/* This pipe is used by the parent to wait until
@@ -337,81 +397,68 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
*
* To avoid ambiguity, we create a pipe with both ends
* marked close-on-exec. Then, after the call to `fork()`,
* the parent polls the read end until it sees POLLHUP.
* the parent polls the read end until it EOFs or errors with EPIPE.
*/
#if SPAWN_WAIT_EXEC
if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK))
if (uv__make_pipe(signal_pipe, 0))
goto error;
#endif
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
pid = fork();
if (pid == -1) {
#if SPAWN_WAIT_EXEC
close(signal_pipe[0]);
close(signal_pipe[1]);
#endif
environ = save_our_env;
goto error;
}
if (pid == 0) {
/* Child */
uv__process_child_init(options, stdio_count, pipes);
/* Execution never reaches here. */
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
abort();
}
/* Parent. */
/* Restore environment. */
environ = save_our_env;
#if SPAWN_WAIT_EXEC
/* POLLHUP signals child has exited or execve()'d. */
close(signal_pipe[1]);
do {
pfd.fd = signal_pipe[0];
pfd.events = POLLIN|POLLHUP;
pfd.revents = 0;
errno = 0, status = poll(&pfd, 1, -1);
}
while (status == -1 && (errno == EINTR || errno == ENOMEM));
assert((status == 1) && "poll() on pipe read end failed");
process->errorno = 0;
do
r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno));
while (r == -1 && errno == EINTR);
if (r == 0)
; /* okay, EOF */
else if (r == sizeof(process->errorno))
; /* okay, read errorno */
else if (r == -1 && errno == EPIPE)
; /* okay, got EPIPE */
else
abort();
close(signal_pipe[0]);
#endif
process->pid = pid;
ev_child_init(&process->child_watcher, uv__chld, pid, 0);
ev_child_start(process->loop->ev, &process->child_watcher);
process->child_watcher.data = process;
for (i = 0; i < options.stdio_count; i++) {
if (uv__process_open_stream(&options.stdio[i], pipes + i * 2, i == 0)) {
int j;
/* Close all opened streams */
for (j = 0; j < i; j++) {
uv__process_close_stream(&options.stdio[j]);
}
if (uv__process_open_stream(options.stdio + i, pipes[i], i == 0)) {
while (i--) uv__process_close_stream(options.stdio + i);
goto error;
}
}
free(pipes);
q = uv__process_queue(loop, pid);
ngx_queue_insert_tail(q, &process->queue);
process->pid = pid;
process->exit_cb = options.exit_cb;
uv__handle_start(process);
free(pipes);
return 0;
error:
uv__set_sys_error(process->loop, errno);
for (i = 0; i < stdio_count; i++) {
close(pipes[i * 2]);
close(pipes[i * 2 + 1]);
close(pipes[i][0]);
close(pipes[i][1]);
}
free(pipes);
return -1;
@@ -442,6 +489,7 @@ uv_err_t uv_kill(int pid, int signum) {
void uv__process_close(uv_process_t* handle) {
ev_child_stop(handle->loop->ev, &handle->child_watcher);
/* TODO stop signal watcher when this is the last handle */
ngx_queue_remove(&handle->queue);
uv__handle_stop(handle);
}

269
deps/uv/src/unix/signal.c vendored Normal file
View File

@@ -0,0 +1,269 @@
/* 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 <assert.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
struct signal_ctx {
int pipefd[2];
uv__io_t io_watcher;
unsigned int nqueues;
ngx_queue_t queues[1]; /* variable length */
};
static void uv__signal_handler(int signum);
static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events);
static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop);
static void uv__signal_ctx_delete(struct signal_ctx* ctx);
static void uv__signal_write(int fd, unsigned int val);
static unsigned int uv__signal_read(int fd);
static unsigned int uv__signal_max(void);
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_SIGNAL);
handle->signum = 0;
return 0;
}
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum_) {
struct signal_ctx* ctx;
struct sigaction sa;
unsigned int signum;
uv_loop_t* loop;
ngx_queue_t* q;
/* XXX doing this check in uv_signal_init() - the logical place for it -
* leads to an infinite loop when uv__loop_init() inits a signal watcher
*/
/* FIXME */
assert(handle->loop == uv_default_loop() &&
"uv_signal_t is currently only supported by the default loop");
loop = handle->loop;
signum = signum_;
if (uv__is_active(handle))
return uv__set_artificial_error(loop, UV_EBUSY);
if (signal_cb == NULL)
return uv__set_artificial_error(loop, UV_EINVAL);
if (signum <= 0)
return uv__set_artificial_error(loop, UV_EINVAL);
ctx = loop->signal_ctx;
if (ctx == NULL) {
ctx = uv__signal_ctx_new(loop);
if (ctx == NULL)
return uv__set_artificial_error(loop, UV_ENOMEM);
loop->signal_ctx = ctx;
}
if (signum > ctx->nqueues)
return uv__set_artificial_error(loop, UV_EINVAL);
q = ctx->queues + signum;
if (!ngx_queue_empty(q))
goto skip;
/* XXX use a separate signal stack? */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = uv__signal_handler;
/* XXX save old action so we can restore it later on? */
if (sigaction(signum, &sa, NULL))
return uv__set_artificial_error(loop, UV_EINVAL);
skip:
ngx_queue_insert_tail(q, &handle->queue);
uv__handle_start(handle);
handle->signum = signum;
handle->signal_cb = signal_cb;
return 0;
}
int uv_signal_stop(uv_signal_t* handle) {
struct signal_ctx* ctx;
struct sigaction sa;
unsigned int signum;
uv_loop_t* loop;
if (!uv__is_active(handle))
return 0;
signum = handle->signum;
loop = handle->loop;
ctx = loop->signal_ctx;
assert(signum > 0);
assert(signum <= ctx->nqueues);
ngx_queue_remove(&handle->queue);
uv__handle_stop(handle);
handle->signum = 0;
if (!ngx_queue_empty(ctx->queues + signum))
goto skip;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL; /* XXX restore previous action? */
if (sigaction(signum, &sa, NULL))
return uv__set_artificial_error(loop, UV_EINVAL);
skip:
return 0;
}
void uv__signal_close(uv_signal_t* handle) {
uv_signal_stop(handle);
}
void uv__signal_unregister(uv_loop_t* loop) {
uv__signal_ctx_delete(loop->signal_ctx);
loop->signal_ctx = NULL;
}
static void uv__signal_handler(int signum) {
struct signal_ctx* ctx = uv_default_loop()->signal_ctx;
uv__signal_write(ctx->pipefd[1], (unsigned int) signum);
}
static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events) {
struct signal_ctx* ctx;
unsigned int signum;
uv_signal_t* h;
ngx_queue_t* q;
ctx = container_of(w, struct signal_ctx, io_watcher);
signum = uv__signal_read(ctx->pipefd[0]);
assert(signum > 0);
assert(signum <= ctx->nqueues);
ngx_queue_foreach(q, ctx->queues + signum) {
h = ngx_queue_data(q, uv_signal_t, queue);
h->signal_cb(h, signum);
}
}
static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop) {
struct signal_ctx* ctx;
unsigned int nqueues;
unsigned int i;
nqueues = uv__signal_max();
assert(nqueues > 0);
/* The first ctx->queues entry is never used. It wastes a few bytes of memory
* but it saves us from having to substract 1 from the signum all the time -
* which inevitably someone will forget to do.
*/
ctx = calloc(1, sizeof(*ctx) + sizeof(ctx->queues[0]) * (nqueues + 1));
if (ctx == NULL)
return NULL;
if (uv__make_pipe(ctx->pipefd, UV__F_NONBLOCK)) {
free(ctx);
return NULL;
}
uv__io_init(&ctx->io_watcher, uv__signal_event, ctx->pipefd[0], UV__IO_READ);
uv__io_start(loop, &ctx->io_watcher);
ctx->nqueues = nqueues;
for (i = 1; i <= nqueues; i++)
ngx_queue_init(ctx->queues + i);
return ctx;
}
static void uv__signal_ctx_delete(struct signal_ctx* ctx) {
if (ctx == NULL) return;
close(ctx->pipefd[0]);
close(ctx->pipefd[1]);
free(ctx);
}
static void uv__signal_write(int fd, unsigned int val) {
ssize_t n;
do
n = write(fd, &val, sizeof(val));
while (n == -1 && errno == EINTR);
if (n == sizeof(val))
return;
if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
return; /* pipe full - nothing we can do about that */
abort();
}
static unsigned int uv__signal_read(int fd) {
unsigned int val;
ssize_t n;
do
n = read(fd, &val, sizeof(val));
while (n == -1 && errno == EINTR);
if (n == sizeof(val))
return val;
abort();
}
static unsigned int uv__signal_max(void) {
#if defined(_SC_RTSIG_MAX)
int max = sysconf(_SC_RTSIG_MAX);
if (max != -1) return max;
#endif
#if defined(SIGRTMAX)
return SIGRTMAX;
#elif defined(NSIG)
return NSIG;
#else
return 32;
#endif
}

View File

@@ -57,8 +57,6 @@ void uv__stream_init(uv_loop_t* loop,
uv_stream_t* stream,
uv_handle_type type) {
uv__handle_init(loop, (uv_handle_t*)stream, type);
loop->counters.stream_init++;
stream->alloc_cb = NULL;
stream->close_cb = NULL;
stream->connection_cb = NULL;
@@ -489,7 +487,6 @@ start:
} else {
/* Successful write */
/* Update the counters. */
while (n >= 0) {
uv_buf_t* buf = &(req->bufs[req->write_index]);
size_t len = buf->len;
@@ -834,10 +831,16 @@ static void uv__stream_connect(uv_stream_t* stream) {
}
int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
uv_stream_t* send_handle, uv_write_cb cb) {
int uv_write2(uv_write_t* req,
uv_stream_t* stream,
uv_buf_t bufs[],
int bufcnt,
uv_stream_t* send_handle,
uv_write_cb cb) {
int empty_queue;
assert(bufcnt > 0);
assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
stream->type == UV_TTY) &&
"uv_write (unix) does not yet support other types of streams");
@@ -864,7 +867,7 @@ int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
req->send_handle = send_handle;
ngx_queue_init(&req->queue);
if (bufcnt <= UV_REQ_BUFSML_SIZE)
if (bufcnt <= (int) ARRAY_SIZE(req->bufsml))
req->bufs = req->bufsml;
else
req->bufs = malloc(sizeof(uv_buf_t) * bufcnt);

View File

@@ -63,6 +63,19 @@
#endif
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
loop->fs_fd = -1;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->fs_fd == -1) return;
close(loop->fs_fd);
loop->fs_fd = -1;
}
uint64_t uv_hrtime() {
return (gethrtime());
}
@@ -183,8 +196,6 @@ int uv_fs_event_init(uv_loop_t* loop,
int portfd;
int first_run = 0;
loop->counters.fs_event_init++;
/* We don't support any flags yet. */
assert(!flags);
if (loop->fs_fd == -1) {
@@ -233,7 +244,6 @@ int uv_fs_event_init(uv_loop_t* loop,
const char* filename,
uv_fs_event_cb cb,
int flags) {
loop->counters.fs_event_init++;
uv__set_sys_error(loop, ENOSYS);
return -1;
}
@@ -344,8 +354,10 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
cpu_info->model = NULL;
} else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clock_MHz");
assert(knp->data_type == KSTAT_DATA_INT32);
cpu_info->speed = knp->value.i32;
assert(knp->data_type == KSTAT_DATA_INT32 ||
knp->data_type == KSTAT_DATA_INT64);
cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
: knp->value.i64;
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"brand");
assert(knp->data_type == KSTAT_DATA_STRING);

View File

@@ -30,7 +30,6 @@
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
loop->counters.tcp_init++;
tcp->idle_handle = NULL;
return 0;
}

View File

@@ -39,8 +39,6 @@ RB_GENERATE_STATIC(uv__timers, uv_timer_s, tree_entry, uv__timer_cmp)
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
loop->counters.timer_init++;
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
handle->timer_cb = NULL;

View File

@@ -45,7 +45,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
tty->flags |= UV_STREAM_BLOCKING;
}
loop->counters.tty_init++;
tty->mode = 0;
return 0;
}

View File

@@ -418,6 +418,8 @@ static int uv__udp_send(uv_udp_send_t* req,
struct sockaddr* addr,
socklen_t addrlen,
uv_udp_send_cb send_cb) {
assert(bufcnt > 0);
if (uv__udp_maybe_deferred_bind(handle, addr->sa_family))
return -1;
@@ -429,7 +431,7 @@ static int uv__udp_send(uv_udp_send_t* req,
req->handle = handle;
req->bufcnt = bufcnt;
if (bufcnt <= UV_REQ_BUFSML_SIZE) {
if (bufcnt <= (int) ARRAY_SIZE(req->bufsml)) {
req->bufs = req->bufsml;
}
else if ((req->bufs = malloc(bufcnt * sizeof(bufs[0]))) == NULL) {
@@ -453,8 +455,6 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
memset(handle, 0, sizeof *handle);
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
loop->counters.udp_init++;
handle->fd = -1;
ngx_queue_init(&handle->write_queue);
ngx_queue_init(&handle->write_completed_queue);

View File

@@ -83,8 +83,8 @@ static void uv__eio_init(void) {
void uv_eio_init(uv_loop_t* loop) {
if (loop->counters.eio_init) return;
loop->counters.eio_init = 1;
if (loop->flags & UV_LOOP_EIO_INITIALIZED) return;
loop->flags |= UV_LOOP_EIO_INITIALIZED;
uv_idle_init(loop, &loop->uv_eio_poller);
uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll);

View File

@@ -158,7 +158,6 @@ UNUSED static void uv__handle_unref(uv_handle_t* h) {
UNUSED static void uv__handle_init(uv_loop_t* loop,
uv_handle_t* handle,
uv_handle_type type) {
loop->counters.handle_init++;
handle->loop = loop;
handle->type = type;
handle->flags = UV__HANDLE_REF; /* ref the loop when active */

View File

@@ -23,39 +23,11 @@
#include "uv.h"
#include "internal.h"
#include "atomicops-inl.h"
#include "handle-inl.h"
#include "req-inl.h"
/* Atomic set operation on char */
#ifdef _MSC_VER /* MSVC */
/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
/* exist, and interlocked operations on larger targets might require the */
/* target to be aligned. */
#pragma intrinsic(_InterlockedOr8)
static char __declspec(inline) uv_atomic_exchange_set(char volatile* target) {
return _InterlockedOr8(target, 1);
}
#else /* GCC */
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
static inline char uv_atomic_exchange_set(char volatile* target) {
const char one = 1;
char old_value;
__asm__ __volatile__ ("lock xchgb %0, %1\n\t"
: "=r"(old_value), "=m"(*target)
: "0"(one), "m"(*target)
: "memory");
return old_value;
}
#endif
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
!handle->async_sent) {
@@ -78,8 +50,6 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
req->type = UV_WAKEUP;
req->data = handle;
loop->counters.async_init++;
uv__handle_start(handle);
return 0;
@@ -107,7 +77,7 @@ int uv_async_send(uv_async_t* handle) {
/* or closed handle. */
assert(!(handle->flags & UV_HANDLE_CLOSING));
if (!uv_atomic_exchange_set(&handle->async_sent)) {
if (!uv__atomic_exchange_set(&handle->async_sent)) {
POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
}

56
deps/uv/src/win/atomicops-inl.h vendored Normal file
View File

@@ -0,0 +1,56 @@
/* 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.
*/
#ifndef UV_WIN_ATOMICOPS_INL_H_
#define UV_WIN_ATOMICOPS_INL_H_
#include "uv.h"
/* Atomic set operation on char */
#ifdef _MSC_VER /* MSVC */
/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
/* exist, and interlocked operations on larger targets might require the */
/* target to be aligned. */
#pragma intrinsic(_InterlockedOr8)
static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
return _InterlockedOr8(target, 1);
}
#else /* GCC */
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
static inline char uv__atomic_exchange_set(char volatile* target) {
const char one = 1;
char old_value;
__asm__ __volatile__ ("lock xchgb %0, %1\n\t"
: "=r"(old_value), "=m"(*target)
: "0"(one), "m"(*target)
: "memory");
return old_value;
}
#endif
#endif /* UV_WIN_ATOMICOPS_INL_H_ */

View File

@@ -55,6 +55,9 @@ static void uv_init(void) {
/* Initialize FS */
uv_fs_init();
/* Initialize signal stuff */
uv_signals_init();
/* Initialize console */
uv_console_init();
@@ -96,8 +99,6 @@ static void uv_loop_init(uv_loop_t* loop) {
loop->active_udp_streams = 0;
loop->last_err = uv_ok_;
memset(&loop->counters, 0, sizeof loop->counters);
}

View File

@@ -26,7 +26,7 @@ static int uv__dlerror(uv_lib_t* lib, int errorno);
int uv_dlopen(const char* filename, uv_lib_t* lib) {
wchar_t filename_w[32768];
WCHAR filename_w[32768];
lib->handle = NULL;
lib->errmsg = NULL;

View File

@@ -110,8 +110,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case WSAEFAULT: return UV_EFAULT;
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
case ERROR_OPERATION_ABORTED: return UV_EINTR;
case WSAEINTR: return UV_EINTR;
case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
case WSAEINTR: return UV_ECANCELED;
case ERROR_INVALID_DATA: return UV_EINVAL;
case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL;

View File

@@ -55,8 +55,6 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle,
}
uv__handle_start(handle);
loop->counters.fs_event_init++;
}
@@ -90,15 +88,15 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
}
static int uv_split_path(const wchar_t* filename, wchar_t** dir,
wchar_t** file) {
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) {
int len = wcslen(filename);
int i = len;
while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
if (i == 0) {
if (dir) {
*dir = (wchar_t*)malloc((MAX_PATH + 1) * sizeof(wchar_t));
*dir = (WCHAR*)malloc((MAX_PATH + 1) * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
@@ -113,7 +111,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir,
*file = wcsdup(filename);
} else {
if (dir) {
*dir = (wchar_t*)malloc((i + 1) * sizeof(wchar_t));
*dir = (WCHAR*)malloc((i + 1) * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
@@ -121,7 +119,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir,
(*dir)[i] = L'\0';
}
*file = (wchar_t*)malloc((len - i) * sizeof(wchar_t));
*file = (WCHAR*)malloc((len - i) * sizeof(WCHAR));
if (!*file) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
@@ -137,8 +135,8 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
const char* filename, uv_fs_event_cb cb, int flags) {
int name_size, is_path_dir;
DWORD attr, last_error;
wchar_t* dir = NULL, *dir_to_watch, *filenamew = NULL;
wchar_t short_path[MAX_PATH];
WCHAR* dir = NULL, *dir_to_watch, *filenamew = NULL;
WCHAR short_path[MAX_PATH];
/* We don't support any flags yet. */
assert(!flags);
@@ -146,14 +144,14 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
uv_fs_event_init_handle(loop, handle, filename, cb);
/* Convert name to UTF16. */
name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(wchar_t);
filenamew = (wchar_t*)malloc(name_size);
name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(WCHAR);
filenamew = (WCHAR*)malloc(name_size);
if (!filenamew) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
if (!uv_utf8_to_utf16(filename, filenamew,
name_size / sizeof(wchar_t))) {
name_size / sizeof(WCHAR))) {
uv__set_sys_error(loop, GetLastError());
return -1;
}
@@ -294,7 +292,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
FILE_NOTIFY_INFORMATION* file_info;
int sizew, size, result;
char* filename = NULL;
wchar_t* filenamew, *long_filenamew = NULL;
WCHAR* filenamew, *long_filenamew = NULL;
DWORD offset = 0;
assert(req->type == UV_FS_EVENT_REQ);
@@ -323,9 +321,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
*/
if (handle->dirw ||
_wcsnicmp(handle->filew, file_info->FileName,
file_info->FileNameLength / sizeof(wchar_t)) == 0 ||
file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
_wcsnicmp(handle->short_filew, file_info->FileName,
file_info->FileNameLength / sizeof(wchar_t)) == 0) {
file_info->FileNameLength / sizeof(WCHAR)) == 0) {
if (handle->dirw) {
/*
@@ -337,9 +335,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
/* Construct a full path to the file. */
size = wcslen(handle->dirw) +
file_info->FileNameLength / sizeof(wchar_t) + 2;
file_info->FileNameLength / sizeof(WCHAR) + 2;
filenamew = (wchar_t*)malloc(size * sizeof(wchar_t));
filenamew = (WCHAR*)malloc(size * sizeof(WCHAR));
if (!filenamew) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
@@ -353,7 +351,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
size = GetLongPathNameW(filenamew, NULL, 0);
if (size) {
long_filenamew = (wchar_t*)malloc(size * sizeof(wchar_t));
long_filenamew = (WCHAR*)malloc(size * sizeof(WCHAR));
if (!long_filenamew) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
@@ -388,7 +386,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
*/
if (!long_filenamew) {
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(wchar_t);
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
/* Removed or renamed callbacks don't provide filename. */

View File

@@ -37,13 +37,13 @@
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
wchar_t* ai_canonname;
WCHAR* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfoW* ai_next;
} ADDRINFOW, *PADDRINFOW;
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const wchar_t* node,
const wchar_t* service,
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
const WCHAR* service,
const ADDRINFOW* hints,
PADDRINFOW* result);
@@ -271,7 +271,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* calculate required memory size for all input values */
if (node != NULL) {
nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(wchar_t));
nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR));
if (nodesize == 0) {
uv__set_sys_error(loop, GetLastError());
goto error;
@@ -280,7 +280,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
if (service != NULL) {
servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) *
sizeof(wchar_t));
sizeof(WCHAR));
if (servicesize == 0) {
uv__set_sys_error(loop, GetLastError());
goto error;
@@ -303,10 +303,10 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* convert node string to UTF16 into allocated memory and save pointer in */
/* the reques. */
if (node != NULL) {
req->node = (wchar_t*)alloc_ptr;
req->node = (WCHAR*)alloc_ptr;
if (uv_utf8_to_utf16(node,
(wchar_t*) alloc_ptr,
nodesize / sizeof(wchar_t)) == 0) {
(WCHAR*) alloc_ptr,
nodesize / sizeof(WCHAR)) == 0) {
uv__set_sys_error(loop, GetLastError());
goto error;
}
@@ -318,10 +318,10 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* convert service string to UTF16 into allocated memory and save pointer */
/* in the req. */
if (service != NULL) {
req->service = (wchar_t*)alloc_ptr;
req->service = (WCHAR*)alloc_ptr;
if (uv_utf8_to_utf16(service,
(wchar_t*) alloc_ptr,
servicesize / sizeof(wchar_t)) == 0) {
(WCHAR*) alloc_ptr,
servicesize / sizeof(WCHAR)) == 0) {
uv__set_sys_error(loop, GetLastError());
goto error;
}

View File

@@ -123,6 +123,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
uv_async_endgame(loop, (uv_async_t*) handle);
break;
case UV_SIGNAL:
uv_signal_endgame(loop, (uv_signal_t*) handle);
break;
case UV_PROCESS:
uv_process_endgame(loop, (uv_process_t*) handle);
break;

View File

@@ -124,6 +124,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
uv_async_close(loop, (uv_async_t*) handle);
return;
case UV_SIGNAL:
uv_signal_close(loop, (uv_signal_t*) handle);
return;
case UV_PROCESS:
uv_process_close(loop, (uv_process_t*) handle);
return;

View File

@@ -74,9 +74,10 @@
#define UV_HANDLE_PIPESERVER 0x02000000
/* Only used by uv_tty_t handles. */
#define UV_HANDLE_TTY_RAW 0x01000000
#define UV_HANDLE_TTY_SAVED_POSITION 0x02000000
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x04000000
#define UV_HANDLE_TTY_READABLE 0x01000000
#define UV_HANDLE_TTY_RAW 0x02000000
#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
/* Only used by uv_poll_t handles. */
#define UV_HANDLE_POLL_SLOW 0x02000000
@@ -134,7 +135,7 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
/*
* Pipes
*/
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
uv_err_t uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
char* name, size_t nameSize);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
@@ -231,11 +232,23 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req);
/*
* Signal watcher
*/
void uv_signals_init();
int uv__signal_dispatch(int signum);
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req);
/*
* Spawn
*/
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle);
void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
@@ -287,7 +300,7 @@ uv_err_code uv_translate_sys_error(int sys_errno);
/*
* Process stdio handles.
*/
int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
uv_err_t uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
BYTE** buffer_ptr);
void uv__stdio_destroy(BYTE* buffer);
void uv__stdio_noinherit(BYTE* buffer);

View File

@@ -39,7 +39,6 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
loop->counters.name##_init++; \
\
return 0; \
} \

View File

@@ -88,8 +88,6 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req);
loop->counters.pipe_init++;
return 0;
}
@@ -159,11 +157,11 @@ static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
}
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
uv_err_t uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
char* name, size_t nameSize) {
HANDLE pipeHandle;
int errorno;
int err;
uv_err_t err;
char* ptr = (char*)handle;
for (;;) {
@@ -181,9 +179,8 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
errorno = GetLastError();
if (errorno != ERROR_PIPE_BUSY && errorno != ERROR_ACCESS_DENIED) {
uv__set_sys_error(loop, errorno);
err = -1;
goto done;
err = uv__new_sys_error(errorno);
goto error;
}
/* Pipe name collision. Increment the pointer and try again. */
@@ -194,17 +191,17 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
loop->iocp,
(ULONG_PTR)handle,
0) == NULL) {
uv__set_sys_error(loop, GetLastError());
err = -1;
goto done;
err = uv__new_sys_error(GetLastError());
goto error;
}
uv_pipe_connection_init(handle);
handle->handle = pipeHandle;
err = 0;
done:
if (err && pipeHandle != INVALID_HANDLE_VALUE) {
return uv_ok_;
error:
if (pipeHandle != INVALID_HANDLE_VALUE) {
CloseHandle(pipeHandle);
}
@@ -433,13 +430,13 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
}
/* Convert name to UTF16. */
nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t);
handle->name = (wchar_t*)malloc(nameSize);
nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
handle->name = (WCHAR*)malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) {
if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
uv__set_sys_error(loop, GetLastError());
return -1;
}
@@ -545,13 +542,13 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
req->cb = cb;
/* Convert name to UTF16. */
nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t);
handle->name = (wchar_t*)malloc(nameSize);
nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
handle->name = (WCHAR*)malloc(nameSize);
if (!handle->name) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) {
if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
errorno = GetLastError();
goto error;
}

View File

@@ -558,8 +558,6 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
handle->poll_req_2.type = UV_POLL_REQ;
handle->poll_req_2.data = handle;
loop->counters.poll_init++;
return 0;
}

View File

@@ -94,13 +94,14 @@ void uv_disable_stdio_inheritance(void) {
}
static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
HANDLE* child_pipe_ptr, unsigned int flags) {
static uv_err_t uv__create_stdio_pipe_pair(uv_loop_t* loop,
uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
char pipe_name[64];
SECURITY_ATTRIBUTES sa;
DWORD server_access = 0;
DWORD client_access = 0;
HANDLE child_pipe = INVALID_HANDLE_VALUE;
uv_err_t err;
if (flags & UV_READABLE_PIPE) {
server_access |= PIPE_ACCESS_OUTBOUND;
@@ -112,13 +113,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
}
/* Create server pipe handle. */
if (uv_stdio_pipe_server(loop,
server_pipe,
server_access,
pipe_name,
sizeof(pipe_name)) < 0) {
err = uv_stdio_pipe_server(loop,
server_pipe,
server_access,
pipe_name,
sizeof(pipe_name));
if (err.code != UV_OK)
goto error;
}
/* Create child pipe handle. */
sa.nLength = sizeof sa;
@@ -133,7 +134,7 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
NULL);
if (child_pipe == INVALID_HANDLE_VALUE) {
uv__set_sys_error(loop, GetLastError());
err = uv__new_sys_error(GetLastError());
goto error;
}
@@ -157,13 +158,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
/* both ends of the pipe created. */
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
uv__set_sys_error(loop, GetLastError());
err = uv__new_sys_error(GetLastError());
goto error;
}
}
*child_pipe_ptr = child_pipe;
return 0;
return uv_ok_;
error:
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
@@ -174,7 +175,7 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
CloseHandle(child_pipe);
}
return -1;
return err;
}
@@ -227,7 +228,7 @@ static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
}
static int uv__create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr,
uv_err_t uv__create_nul_handle(HANDLE* handle_ptr,
DWORD access) {
HANDLE handle;
SECURITY_ATTRIBUTES sa;
@@ -244,36 +245,34 @@ static int uv__create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr,
0,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
uv__set_sys_error(loop, GetLastError());
return -1;
return uv__new_sys_error(GetLastError());
}
*handle_ptr = handle;
return 0;
return uv_ok_;
}
int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
uv_err_t uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
BYTE** buffer_ptr) {
BYTE* buffer;
int count, i;
uv_err_t err;
count = options->stdio_count;
if (count < 0 || count > 255) {
/* Only support FDs 0-255 */
uv__set_artificial_error(loop, UV_ENOTSUP);
return -1;
return uv__new_artificial_error(UV_ENOTSUP);
} else if (count < 3) {
/* There should always be at least 3 stdio handles. */
count = 3;
}
/* Allocate the child stdio buffer */
buffer = malloc(CHILD_STDIO_SIZE(count));
buffer = (BYTE*) malloc(CHILD_STDIO_SIZE(count));
if (buffer == NULL) {
uv__set_artificial_error(loop, UV_ENOMEM);
return -1;
return uv__new_artificial_error(UV_ENOMEM);
}
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
@@ -304,11 +303,12 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
if (i <= 2) {
DWORD access = (i == 0) ? FILE_GENERIC_READ :
FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
if (uv__create_nul_handle(loop,
&CHILD_STDIO_HANDLE(buffer, i),
access) < 0) {
err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
access);
if (err.code != UV_OK)
goto error;
}
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
}
break;
@@ -326,12 +326,12 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
if (uv__create_stdio_pipe_pair(loop,
parent_pipe,
&child_pipe,
fdopt.flags) < 0) {
err = uv__create_stdio_pipe_pair(loop,
parent_pipe,
&child_pipe,
fdopt.flags);
if (err.code != UV_OK)
goto error;
}
CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
@@ -430,11 +430,11 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
}
*buffer_ptr = buffer;
return 0;
return uv_ok_;
error:
uv__stdio_destroy(buffer);
return -1;
return err;
}

View File

@@ -36,7 +36,7 @@
typedef struct env_var {
const char* narrow;
const wchar_t* wide;
const WCHAR* wide;
int len; /* including null or '=' */
int supplied;
int value_len;
@@ -45,38 +45,52 @@ typedef struct env_var {
#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 }
#define UTF8_TO_UTF16(s, t) \
size = uv_utf8_to_utf16(s, NULL, 0) * sizeof(wchar_t); \
t = (wchar_t*)malloc(size); \
if (!t) { \
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); \
} \
if (!uv_utf8_to_utf16(s, t, size / sizeof(wchar_t))) { \
uv__set_sys_error(loop, GetLastError()); \
err = -1; \
goto done; \
static uv_err_t uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
int ws_len, r;
WCHAR* ws;
ws_len = MultiByteToWideChar(CP_UTF8,
0,
s,
-1,
NULL,
0);
if (ws_len <= 0) {
return uv__new_sys_error(GetLastError());
}
ws = (WCHAR*) malloc(ws_len * sizeof(WCHAR));
if (ws == NULL) {
return uv__new_artificial_error(UV_ENOMEM);
}
r = MultiByteToWideChar(CP_UTF8,
0,
s,
-1,
ws,
ws_len);
assert(r == ws_len);
*ws_ptr = ws;
return uv_ok_;
}
static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
handle->exit_cb = NULL;
handle->pid = 0;
handle->spawn_error = uv_ok_;
handle->exit_signal = 0;
handle->wait_handle = INVALID_HANDLE_VALUE;
handle->process_handle = INVALID_HANDLE_VALUE;
handle->close_handle = INVALID_HANDLE_VALUE;
handle->child_stdio_buffer = NULL;
handle->exit_cb_pending = 0;
uv_req_init(loop, (uv_req_t*)&handle->exit_req);
handle->exit_req.type = UV_PROCESS_EXIT;
handle->exit_req.data = handle;
uv_req_init(loop, (uv_req_t*)&handle->close_req);
handle->close_req.type = UV_PROCESS_CLOSE;
handle->close_req.data = handle;
loop->counters.handle_init++;
loop->counters.process_init++;
}
@@ -87,15 +101,15 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
/*
* Helper function for search_path
*/
static wchar_t* search_path_join_test(const wchar_t* dir,
static WCHAR* search_path_join_test(const WCHAR* dir,
int dir_len,
const wchar_t* name,
const WCHAR* name,
int name_len,
const wchar_t* ext,
const WCHAR* ext,
int ext_len,
const wchar_t* cwd,
const WCHAR* cwd,
int cwd_len) {
wchar_t *result, *result_pos;
WCHAR *result, *result_pos;
DWORD attrs;
if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
@@ -121,7 +135,7 @@ static wchar_t* search_path_join_test(const wchar_t* dir,
}
/* Allocate buffer for output */
result = result_pos = (wchar_t*)malloc(sizeof(wchar_t) *
result = result_pos = (WCHAR*)malloc(sizeof(WCHAR) *
(cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
/* Copy cwd */
@@ -178,14 +192,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir,
/*
* Helper function for search_path
*/
static wchar_t* path_search_walk_ext(const wchar_t *dir,
static WCHAR* path_search_walk_ext(const WCHAR *dir,
int dir_len,
const wchar_t *name,
const WCHAR *name,
int name_len,
wchar_t *cwd,
WCHAR *cwd,
int cwd_len,
int name_has_ext) {
wchar_t* result;
WCHAR* result;
/* If the name itself has a nonempty extension, try this extension first */
if (name_has_ext) {
@@ -259,14 +273,14 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
*
* TODO: correctly interpret UNC paths
*/
static wchar_t* search_path(const wchar_t *file,
wchar_t *cwd,
const wchar_t *path) {
static WCHAR* search_path(const WCHAR *file,
WCHAR *cwd,
const WCHAR *path) {
int file_has_dir;
wchar_t* result = NULL;
wchar_t *file_name_start;
wchar_t *dot;
const wchar_t *dir_start, *dir_end, *dir_path;
WCHAR* result = NULL;
WCHAR *file_name_start;
WCHAR *dot;
const WCHAR *dir_start, *dir_end, *dir_path;
int dir_len;
int name_has_ext;
@@ -283,7 +297,7 @@ static wchar_t* search_path(const wchar_t *file,
/* Find the start of the filename so we can split the directory from the */
/* name. */
for (file_name_start = (wchar_t*)file + file_len;
for (file_name_start = (WCHAR*)file + file_len;
file_name_start > file
&& file_name_start[-1] != L'\\'
&& file_name_start[-1] != L'/'
@@ -365,10 +379,10 @@ static wchar_t* search_path(const wchar_t *file,
* Quotes command line arguments
* Returns a pointer to the end (next char to be written) of the buffer
*/
wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
int len = wcslen(source),
i, quote_hit;
wchar_t* start;
WCHAR* start;
/*
* Check if the string must be quoted;
@@ -438,61 +452,92 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
}
wchar_t* make_program_args(char** args, int verbatim_arguments) {
wchar_t* dst;
wchar_t* ptr;
uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
char** arg;
size_t size = 0;
size_t len;
WCHAR* dst = NULL;
WCHAR* temp_buffer = NULL;
size_t dst_len = 0;
size_t temp_buffer_len = 0;
WCHAR* pos;
int arg_count = 0;
wchar_t* buffer;
int arg_size;
int buffer_size = 0;
uv_err_t err = uv_ok_;
/* Count the required size. */
for (arg = args; *arg; arg++) {
arg_size = uv_utf8_to_utf16(*arg, NULL, 0) * sizeof(wchar_t);
size += arg_size;
buffer_size = arg_size > buffer_size ? arg_size : buffer_size;
DWORD arg_len;
arg_len = MultiByteToWideChar(CP_UTF8,
0,
*arg,
-1,
NULL,
0);
if (arg_len == 0) {
return uv__new_sys_error(GetLastError());
}
dst_len += arg_len;
if (arg_len > temp_buffer_len)
temp_buffer_len = arg_len;
arg_count++;
}
/* Adjust for potential quotes. Also assume the worst-case scenario
/* Adjust for potential quotes. Also assume the worst-case scenario */
/* that every character needs escaping, so we need twice as much space. */
size = size * 2 + arg_count * 2;
dst_len = dst_len * 2 + arg_count * 2;
dst = (wchar_t*)malloc(size);
if (!dst) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
/* Allocate buffer for the final command line. */
dst = (WCHAR*) malloc(dst_len * sizeof(WCHAR));
if (dst == NULL) {
err = uv__new_artificial_error(UV_ENOMEM);
goto error;
}
buffer = (wchar_t*)malloc(buffer_size);
if (!buffer) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
/* Allocate temporary working buffer. */
temp_buffer = (WCHAR*) malloc(temp_buffer_len * sizeof(WCHAR));
if (temp_buffer == NULL) {
err = uv__new_artificial_error(UV_ENOMEM);
goto error;
}
ptr = dst;
pos = dst;
for (arg = args; *arg; arg++) {
len = uv_utf8_to_utf16(*arg, buffer, (size_t)(size - (ptr - dst)));
if (!len) {
DWORD arg_len;
/* Convert argument to wide char. */
arg_len = MultiByteToWideChar(CP_UTF8,
0,
*arg,
-1,
temp_buffer,
dst + dst_len - pos);
if (arg_len == 0) {
goto error;
}
if (verbatim_arguments) {
wcscpy(ptr, buffer);
ptr += len - 1;
/* Copy verbatim. */
wcscpy(pos, temp_buffer);
pos += arg_len - 1;
} else {
ptr = quote_cmd_arg(buffer, ptr);
/* Quote/escape, if needed. */
pos = quote_cmd_arg(temp_buffer, pos);
}
*ptr++ = *(arg + 1) ? L' ' : L'\0';
*pos++ = *(arg + 1) ? L' ' : L'\0';
}
free(buffer);
return dst;
free(temp_buffer);
*dst_ptr = dst;
return uv_ok_;
error:
free(dst);
free(buffer);
return NULL;
free(temp_buffer);
return err;
}
@@ -526,11 +571,11 @@ static void check_required_vars_contains_var(env_var_t* required, int size,
* these get defined if the input environment block does not contain any
* values for them.
*/
wchar_t* make_program_env(char** env_block) {
wchar_t* dst;
wchar_t* ptr;
WCHAR* make_program_env(char** env_block) {
WCHAR* dst;
WCHAR* ptr;
char** env;
int env_len = 1 * sizeof(wchar_t); /* room for closing null */
int env_len = 1 * sizeof(WCHAR); /* room for closing null */
int len;
int i;
DWORD var_size;
@@ -545,18 +590,18 @@ wchar_t* make_program_env(char** env_block) {
check_required_vars_contains_var(required_vars,
ARRAY_SIZE(required_vars),
*env);
env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(wchar_t));
env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(WCHAR));
}
for (i = 0; i < ARRAY_SIZE(required_vars); ++i) {
if (!required_vars[i].supplied) {
env_len += required_vars[i].len * sizeof(wchar_t);
env_len += required_vars[i].len * sizeof(WCHAR);
var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
if (var_size == 0) {
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
}
required_vars[i].value_len = (int)var_size;
env_len += (int)var_size * sizeof(wchar_t);
env_len += (int)var_size * sizeof(WCHAR);
}
}
@@ -600,74 +645,17 @@ wchar_t* make_program_env(char** env_block) {
* a child process has exited.
*/
static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
uv_process_t* process = (uv_process_t*)data;
uv_loop_t* loop = process->loop;
assert(didTimeout == FALSE);
assert(process);
/* Post completed */
POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
}
/*
* Called on Windows thread-pool thread to indicate that
* UnregisterWaitEx has completed.
*/
static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
uv_process_t* process = (uv_process_t*)data;
uv_loop_t* loop = process->loop;
assert(didTimeout == FALSE);
assert(process);
/* Post completed */
POST_COMPLETION_FOR_REQ(loop, &process->close_req);
}
/*
* Called on windows thread pool when CreateProcess failed. It writes an error
* message to the process' intended stderr and then posts a PROCESS_EXIT
* packet to the completion port.
*/
static DWORD WINAPI spawn_failure(void* data) {
char syscall[] = "CreateProcessW: ";
char unknown[] = "unknown error\n";
uv_process_t* process = (uv_process_t*) data;
uv_loop_t* loop = process->loop;
HANDLE child_stderr = uv__stdio_handle(process->child_stdio_buffer, 2);
char* buf = NULL;
DWORD count, written;
if (child_stderr != INVALID_HANDLE_VALUE) {
WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);
assert(didTimeout == FALSE);
assert(process);
assert(!process->exit_cb_pending);
count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
process->spawn_errno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR) &buf,
0,
NULL);
if (buf != NULL && count > 0) {
WriteFile(child_stderr, buf, count, &written, NULL);
LocalFree(buf);
} else {
WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
}
FlushFileBuffers(child_stderr);
}
process->exit_cb_pending = 1;
/* Post completed */
POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
return 0;
}
@@ -675,8 +663,13 @@ static DWORD WINAPI spawn_failure(void* data) {
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
DWORD exit_code;
/* FIXME: race condition. */
assert(handle->exit_cb_pending);
handle->exit_cb_pending = 0;
/* If we're closing, don't call the exit callback. Just schedule a close */
/* callback now. */
if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*) handle);
return;
}
@@ -686,71 +679,68 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
handle->wait_handle = INVALID_HANDLE_VALUE;
}
if (handle->process_handle == INVALID_HANDLE_VALUE ||
!GetExitCodeProcess(handle->process_handle, &exit_code)) {
/* The process never even started in the first place, or we were unable */
/* to obtain the exit code. */
exit_code = 127;
}
/* Set the handle to inactive: no callbacks will be made after the exit */
/* callback.*/
uv__handle_stop(handle);
if (handle->spawn_error.code != UV_OK) {
/* Spawning failed. */
exit_code = (DWORD) -1;
} else if (!GetExitCodeProcess(handle->process_handle, &exit_code)) {
/* Unable to to obtain the exit code. This should never happen. */
exit_code = (DWORD) -1;
}
/* Fire the exit callback. */
if (handle->exit_cb) {
loop->last_err = handle->spawn_error;
handle->exit_cb(handle, exit_code, handle->exit_signal);
}
}
/* Called on main thread after UnregisterWaitEx finishes. */
void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
uv__handle_start(handle);
if (handle->wait_handle != INVALID_HANDLE_VALUE) {
handle->close_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
UnregisterWaitEx(handle->wait_handle, handle->close_handle);
handle->wait_handle = NULL;
/* This blocks until either the wait was cancelled, or the callback has */
/* completed. */
BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
if (!r) {
/* This should never happen, and if it happens, we can't recover... */
uv_fatal_error(GetLastError(), "UnregisterWaitEx");
}
RegisterWaitForSingleObject(&handle->wait_handle, handle->close_handle,
close_wait_callback, (void*)handle, INFINITE,
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
} else {
handle->wait_handle = INVALID_HANDLE_VALUE;
}
if (!handle->exit_cb_pending) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
}
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
uv__handle_stop(handle);
assert(!handle->exit_cb_pending);
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
/* Clean-up the process handle. */
CloseHandle(handle->process_handle);
uv__handle_stop(handle);
/* Clean up the child stdio ends that may have been left open. */
if (handle->child_stdio_buffer != NULL) {
uv__stdio_destroy(handle->child_stdio_buffer);
}
/* Clean-up the process handle. */
CloseHandle(handle->process_handle);
uv__handle_close(handle);
}
uv__handle_close(handle);
}
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
uv_process_options_t options) {
int i, size, err = 0, keep_child_stdio_open = 0;
wchar_t* path = NULL;
int i;
uv_err_t err = uv_ok_;
WCHAR* path = NULL;
BOOL result;
wchar_t* application_path = NULL, *application = NULL, *arguments = NULL,
WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
*env = NULL, *cwd = NULL;
STARTUPINFOW startup;
PROCESS_INFORMATION info;
@@ -761,6 +751,12 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
return -1;
}
if (options.file == NULL ||
options.args == NULL) {
uv__set_artificial_error(loop, UV_EINVAL);
return -1;
}
assert(options.file != NULL);
assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
UV_PROCESS_DETACHED |
@@ -768,57 +764,84 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
UV_PROCESS_SETUID)));
uv_process_init(loop, process);
process->exit_cb = options.exit_cb;
UTF8_TO_UTF16(options.file, application);
arguments = options.args ? make_program_args(options.args,
options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS) : NULL;
env = options.env ? make_program_env(options.env) : NULL;
err = uv_utf8_to_utf16_alloc(options.file, &application);
if (err.code != UV_OK)
goto done;
err = make_program_args(options.args,
options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
&arguments);
if (err.code != UV_OK)
goto done;
if (options.cwd) {
UTF8_TO_UTF16(options.cwd, cwd);
} else {
size = GetCurrentDirectoryW(0, NULL) * sizeof(wchar_t);
if (size) {
cwd = (wchar_t*)malloc(size);
if (!cwd) {
uv__set_artificial_error(loop, UV_ENOMEM);
err = -1;
goto done;
}
/* Explicit cwd */
err = uv_utf8_to_utf16_alloc(options.cwd, &cwd);
if (err.code != UV_OK)
goto done;
GetCurrentDirectoryW(size, cwd);
} else {
uv__set_sys_error(loop, GetLastError());
err = -1;
} else {
/* Inherit cwd */
DWORD cwd_len, r;
cwd_len = GetCurrentDirectoryW(0, NULL);
if (!cwd_len) {
err = uv__new_sys_error(GetLastError());
goto done;
}
cwd = (WCHAR*) malloc(cwd_len * sizeof(WCHAR));
if (cwd == NULL) {
err = uv__new_artificial_error(UV_ENOMEM);
goto done;
}
r = GetCurrentDirectoryW(cwd_len, cwd);
if (r == 0 || r >= cwd_len) {
err = uv__new_sys_error(GetLastError());
goto done;
}
}
/* Get PATH env. variable. */
size = GetEnvironmentVariableW(L"PATH", NULL, 0) + 1;
path = (wchar_t*)malloc(size * sizeof(wchar_t));
if (!path) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
/* Get PATH environment variable. */
{
DWORD path_len, r;
path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
if (path_len == 0) {
err = uv__new_sys_error(GetLastError());
goto done;
}
path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
if (path == NULL) {
err = uv__new_artificial_error(UV_ENOMEM);
goto done;
}
r = GetEnvironmentVariableW(L"PATH", path, path_len);
if (r == 0 || r >= path_len) {
err = uv__new_sys_error(GetLastError());
goto done;
}
}
GetEnvironmentVariableW(L"PATH", path, size * sizeof(wchar_t));
path[size - 1] = L'\0';
application_path = search_path(application,
cwd,
path);
if (!application_path) {
/* CreateProcess will fail, but this allows us to pass this error to */
/* the user asynchronously. */
application_path = application;
if (application_path == NULL) {
/* Not found. */
err = uv__new_artificial_error(UV_ENOENT);
goto done;
}
if (uv__stdio_create(loop, &options, &process->child_stdio_buffer) < 0) {
err = -1;
goto done;
}
err = uv__stdio_create(loop, &options, &process->child_stdio_buffer);
if (err.code != UV_OK)
goto done;
startup.cb = sizeof(startup);
startup.lpReserved = NULL;
@@ -871,60 +894,37 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
CloseHandle(info.hThread);
} else {
/* CreateProcessW failed, but this failure should be delivered */
/* 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();
keep_child_stdio_open = 1;
if (!QueueUserWorkItem(spawn_failure, process, WT_EXECUTEDEFAULT)) {
uv_fatal_error(GetLastError(), "QueueUserWorkItem");
}
/* CreateProcessW failed. */
err = uv__new_sys_error(GetLastError());
}
done:
free(application);
if (application_path != application) {
free(application_path);
}
free(application_path);
free(arguments);
free(cwd);
free(env);
free(path);
/* Under normal circumstances we should close the stdio handles now - the */
/* the child now has its own duplicates, or something went horribly wrong */
/* The only exception is when CreateProcess has failed, then we actually */
/* need to keep the stdio handles to report the error asynchronously. */
if (process->child_stdio_buffer == NULL) {
/* Something went wrong before child stdio was initialized. */
} else if (!keep_child_stdio_open) {
process->spawn_error = err;
if (process->child_stdio_buffer != NULL) {
/* Clean up child stdio handles. */
uv__stdio_destroy(process->child_stdio_buffer);
process->child_stdio_buffer = NULL;
} else {
/* We're keeping the handles open, the thread pool is going to have */
/* it's way with them. But at least make them non-inheritable. */
uv__stdio_noinherit(process->child_stdio_buffer);
}
if (err == 0) {
/* Spawn was succesful. The handle will be active until the exit */
/* is made or the handle is closed, whichever happens first. */
uv__handle_start(process);
} else {
/* Spawn was not successful. Clean up. */
if (process->wait_handle != INVALID_HANDLE_VALUE) {
UnregisterWait(process->wait_handle);
process->wait_handle = INVALID_HANDLE_VALUE;
}
/* Make the handle active. It will remain active until the exit callback */
/* is made or the handle is closed, whichever happens first. */
uv__handle_start(process);
if (process->process_handle != INVALID_HANDLE_VALUE) {
CloseHandle(process->process_handle);
process->process_handle = INVALID_HANDLE_VALUE;
}
/* If an error happened, queue the exit req. */
if (err.code != UV_OK) {
process->exit_cb_pending = 1;
uv_insert_pending_req(loop, (uv_req_t*) &process->exit_req);
}
return err;
return 0;
}

View File

@@ -80,7 +80,6 @@
INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
loop->counters.req_init++;
req->type = UV_UNKNOWN_REQ;
SET_REQ_SUCCESS(req);
}
@@ -188,6 +187,10 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
break;
case UV_SIGNAL_REQ:
uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
break;
case UV_POLL_REQ:
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break;
@@ -200,10 +203,6 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
uv_process_proc_exit(loop, (uv_process_t*) req->data);
break;
case UV_PROCESS_CLOSE:
uv_process_proc_close(loop, (uv_process_t*) req->data);
break;
case UV_FS:
uv_process_fs_req(loop, (uv_fs_t*) req);
break;

349
deps/uv/src/win/signal.c vendored Normal file
View File

@@ -0,0 +1,349 @@
/* 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 <assert.h>
#include <signal.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
RB_HEAD(uv_signal_tree_s, uv_signal_s);
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
static ssize_t volatile uv__signal_control_handler_refs = 0;
static CRITICAL_SECTION uv__signal_lock;
void uv_signals_init() {
InitializeCriticalSection(&uv__signal_lock);
}
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
/* Compare signums first so all watchers with the same signnum end up */
/* adjacent. */
if (w1->signum < w2->signum) return -1;
if (w1->signum > w2->signum) return 1;
/* Sort by loop pointer, so we can easily look up the first item after */
/* { .signum = x, .loop = NULL } */
if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
return 0;
}
RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
/*
* Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
* Returns 1 if the signal was dispatched to any watcher, or 0 if there were
* no active signal watchers observing this signal.
*/
int uv__signal_dispatch(int signum) {
uv_signal_t lookup;
uv_signal_t* handle;
int dispatched = 0;
EnterCriticalSection(&uv__signal_lock);
lookup.signum = signum;
lookup.loop = NULL;
for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
handle != NULL && handle->signum == signum;
handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
unsigned long previous = InterlockedExchange(&handle->pending_signum, signum);
if (!previous) {
POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
}
dispatched = 1;
}
LeaveCriticalSection(&uv__signal_lock);
return dispatched;
}
static BOOL WINAPI uv__signal_control_handler(DWORD type) {
switch (type) {
case CTRL_C_EVENT:
return uv__signal_dispatch(SIGINT);
case CTRL_BREAK_EVENT:
return uv__signal_dispatch(SIGBREAK);
case CTRL_CLOSE_EVENT:
if (uv__signal_dispatch(SIGHUP)) {
/* Windows will terminate the process after the control handler */
/* returns. After that it will just terminate our process. Therefore */
/* block the signal handler so the main loop has some time to pick */
/* up the signal and do something for a few seconds. */
Sleep(INFINITE);
return TRUE;
}
return FALSE;
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
/* These signals are only sent to services. Services have their own */
/* notification mechanism, so there's no point in handling these. */
default:
/* We don't handle these. */
return FALSE;
}
}
static uv_err_t uv__signal_register_control_handler() {
/* When this function is called, the uv__signal_lock must be held. */
/* If the console control handler has already been hooked, just add a */
/* reference. */
if (uv__signal_control_handler_refs > 0)
return uv_ok_;
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
return uv__new_sys_error(GetLastError());
uv__signal_control_handler_refs++;
return uv_ok_;
}
static void uv__signal_unregister_control_handler() {
/* When this function is called, the uv__signal_lock must be held. */
BOOL r;
/* Don't unregister if the number of console control handlers exceeds one. */
/* Just remove a reference in that case. */
if (uv__signal_control_handler_refs > 1) {
uv__signal_control_handler_refs--;
return;
}
assert(uv__signal_control_handler_refs == 1);
r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
/* This should never fail; if it does it is probably a bug in libuv. */
assert(r);
uv__signal_control_handler_refs--;
}
static uv_err_t uv__signal_register(int signum) {
switch (signum) {
case SIGINT:
case SIGBREAK:
case SIGHUP:
return uv__signal_register_control_handler();
case SIGILL:
case SIGABRT_COMPAT:
case SIGFPE:
case SIGSEGV:
case SIGTERM:
case SIGABRT:
/* Signal is never raised. */
return uv_ok_;
default:
/* Invalid signal. */
return uv__new_artificial_error(UV_EINVAL);
}
}
static void uv__signal_unregister(int signum) {
switch (signum) {
case SIGINT:
case SIGBREAK:
case SIGHUP:
uv__signal_unregister_control_handler();
return;
case SIGILL:
case SIGABRT_COMPAT:
case SIGFPE:
case SIGSEGV:
case SIGTERM:
case SIGABRT:
/* Nothing is registered for this signal. */
return;
default:
/* Libuv bug. */
assert(0 && "Invalid signum");
return;
}
}
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
uv_req_t* req;
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
handle->pending_signum = 0;
handle->signum = 0;
handle->signal_cb = NULL;
req = &handle->signal_req;
uv_req_init(loop, req);
req->type = UV_SIGNAL_REQ;
req->data = handle;
uv__handle_start(handle);
return 0;
}
int uv_signal_stop(uv_signal_t* handle) {
uv_signal_t* removed_handle;
/* If the watcher wasn't started, this is a no-op. */
if (handle->signum == 0)
return 0;
EnterCriticalSection(&uv__signal_lock);
uv__signal_unregister(handle->signum);
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
assert(removed_handle == handle);
LeaveCriticalSection(&uv__signal_lock);
handle->signum = 0;
uv__handle_stop(handle);
return 0;
}
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
uv_err_t err;
/* If the user supplies signum == 0, then return an error already. If the */
/* signum is otherwise invalid then uv__signal_register will find out */
/* eventually. */
if (signum == 0) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
/* Short circuit: if the signal watcher is already watching {signum} don't */
/* go through the process of deregistering and registering the handler. */
/* Additionally, this avoids pending signals getting lost in the (small) */
/* time frame that handle->signum == 0. */
if (signum == handle->signum) {
handle->signal_cb = signal_cb;
return 0;
}
/* If the signal handler was already active, stop it first. */
if (handle->signum != 0) {
int r = uv_signal_stop(handle);
/* uv_signal_stop is infallible. */
assert(r == 0);
}
EnterCriticalSection(&uv__signal_lock);
err = uv__signal_register(signum);
if (err.code != UV_OK) {
/* Uh-oh, didn't work. */
handle->loop->last_err = err;
LeaveCriticalSection(&uv__signal_lock);
return -1;
}
handle->signum = signum;
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
LeaveCriticalSection(&uv__signal_lock);
handle->signal_cb = signal_cb;
uv__handle_start(handle);
return 0;
}
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req) {
unsigned long dispatched_signum;
assert(handle->type == UV_SIGNAL);
assert(req->type == UV_SIGNAL_REQ);
dispatched_signum = InterlockedExchange(&handle->pending_signum, 0);
assert(dispatched_signum != 0);
/* Check if the pending signal equals the signum that we are watching for. */
/* These can get out of sync when the handler is stopped and restarted */
/* while the signal_req is pending. */
if (dispatched_signum == handle->signum)
handle->signal_cb(handle, dispatched_signum);
if (handle->flags & UV_HANDLE_CLOSING) {
/* When it is closing, it must be stopped at this point. */
assert(handle->signum == 0);
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
uv_signal_stop(handle);
if (handle->pending_signum == 0) {
uv__handle_start(handle);
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->signum == 0);
assert(handle->pending_signum == 0);
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
uv__handle_close(handle);
}

View File

@@ -36,8 +36,6 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
uv__handle_init(loop, (uv_handle_t*) handle, type);
handle->write_queue_size = 0;
handle->activecnt = 0;
loop->counters.stream_init++;
}

View File

@@ -149,8 +149,6 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
handle->func_connectex = NULL;
handle->processed_accepts = 0;
loop->counters.tcp_init++;
return 0;
}

View File

@@ -71,8 +71,6 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
handle->timer_cb = NULL;
handle->repeat = 0;
loop->counters.timer_init++;
return 0;
}

118
deps/uv/src/win/tty.c vendored
View File

@@ -89,54 +89,70 @@ void uv_console_init() {
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
HANDLE win_handle;
CONSOLE_SCREEN_BUFFER_INFO info;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD original_console_mode = 0;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
loop->counters.tty_init++;
win_handle = (HANDLE) _get_osfhandle(fd);
if (win_handle == INVALID_HANDLE_VALUE) {
uv__set_sys_error(loop, ERROR_INVALID_HANDLE);
handle = (HANDLE) _get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
uv__set_artificial_error(loop, UV_EBADF);
return -1;
}
if (!GetConsoleMode(win_handle, &tty->original_console_mode)) {
uv__set_sys_error(loop, GetLastError());
return -1;
}
if (readable) {
/* Try to obtain the original console mode fromt he input handle. */
if (!GetConsoleMode(handle, &original_console_mode)) {
uv__set_sys_error(loop, GetLastError());
return -1;
}
/* Initialize virtual window size; if it fails, assume that this is stdin. */
if (GetConsoleScreenBufferInfo(win_handle, &info)) {
} else {
/* Obtain the screen buffer info with the output handle. */
if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
uv__set_sys_error(loop, GetLastError());
return -1;
}
/* Update the virtual window. We must hold the tty_output_lock because the */
/* virtual window state is shared between all uv_tty handles. */
EnterCriticalSection(&uv_tty_output_lock);
uv_tty_update_virtual_window(&info);
uv_tty_update_virtual_window(&screen_buffer_info);
LeaveCriticalSection(&uv_tty_output_lock);
}
uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
uv_connection_init((uv_stream_t*) tty);
tty->handle = win_handle;
tty->read_line_handle = NULL;
tty->read_line_buffer = uv_null_buf_;
tty->read_raw_wait = NULL;
tty->handle = handle;
tty->reqs_pending = 0;
tty->flags |= UV_HANDLE_BOUND;
/* Init keycode-to-vt100 mapper state. */
tty->last_key_len = 0;
tty->last_key_offset = 0;
tty->last_utf16_high_surrogate = 0;
memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
if (readable) {
/* Initialize TTY input specific fields. */
tty->original_console_mode = original_console_mode;
tty->flags |= UV_HANDLE_TTY_READABLE;
tty->read_line_handle = NULL;
tty->read_line_buffer = uv_null_buf_;
tty->read_raw_wait = NULL;
/* Init utf8-to-utf16 conversion state. */
tty->utf8_bytes_left = 0;
tty->utf8_codepoint = 0;
/* Init keycode-to-vt100 mapper state. */
tty->last_key_len = 0;
tty->last_key_offset = 0;
tty->last_utf16_high_surrogate = 0;
memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
} else {
/* TTY output specific fields. */
/* Init utf8-to-utf16 conversion state. */
tty->utf8_bytes_left = 0;
tty->utf8_codepoint = 0;
/* Initialize eol conversion state */
tty->previous_eol = 0;
/* Initialize eol conversion state */
tty->previous_eol = 0;
/* Init ANSI parser state. */
tty->ansi_parser_state = ANSI_NORMAL;
/* Init ANSI parser state. */
tty->ansi_parser_state = ANSI_NORMAL;
}
return 0;
}
@@ -148,6 +164,11 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
uv_alloc_cb alloc_cb;
uv_read_cb read_cb;
if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
uv__set_artificial_error(tty->loop, UV_EINVAL);
return -1;
}
if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
return 0;
}
@@ -444,6 +465,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
off_t buf_used;
assert(handle->type == UV_TTY);
assert(handle->flags & UV_HANDLE_TTY_READABLE);
handle->flags &= ~UV_HANDLE_READ_PENDING;
if (!(handle->flags & UV_HANDLE_READING) ||
@@ -683,6 +705,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
uv_buf_t buf;
assert(handle->type == UV_TTY);
assert(handle->flags & UV_HANDLE_TTY_READABLE);
buf = handle->read_line_buffer;
@@ -726,6 +749,8 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req) {
assert(handle->type == UV_TTY);
assert(handle->flags & UV_HANDLE_TTY_READABLE);
/* If the read_line_buffer member is zero, it must have been an raw read. */
/* Otherwise it was a line-buffered read. */
@@ -742,6 +767,11 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
uv_loop_t* loop = handle->loop;
if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
handle->flags |= UV_HANDLE_READING;
INCREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb = read_cb;
@@ -769,6 +799,10 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
int uv_tty_read_stop(uv_tty_t* handle) {
uv_loop_t* loop = handle->loop;
if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
if (handle->flags & UV_HANDLE_READING) {
handle->flags &= ~UV_HANDLE_READING;
@@ -1678,6 +1712,11 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
uv_buf_t bufs[], int bufcnt, uv_write_cb cb) {
DWORD error;
if (handle->flags & UV_HANDLE_TTY_READABLE) {
uv__set_artificial_error(handle->loop, UV_EINVAL);
return -1;
}
if ((handle->flags & UV_HANDLE_SHUTTING) ||
(handle->flags & UV_HANDLE_CLOSING)) {
uv__set_sys_error(loop, WSAESHUTDOWN);
@@ -1729,11 +1768,16 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
void uv_tty_close(uv_tty_t* handle) {
handle->flags |= UV_HANDLE_SHUTTING;
uv_tty_read_stop(handle);
CloseHandle(handle->handle);
if (handle->flags & UV_HANDLE_TTY_READABLE) {
/* Readable TTY handle */
uv_tty_read_stop(handle);
} else {
/* Writable TTY handle */
handle->flags |= UV_HANDLE_SHUTTING;
}
uv__handle_start(handle);
if (handle->reqs_pending == 0) {
@@ -1743,7 +1787,7 @@ void uv_tty_close(uv_tty_t* handle) {
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
if ((handle->flags && UV_HANDLE_CONNECTION) &&
if (!(handle->flags && UV_HANDLE_TTY_READABLE) &&
handle->shutdown_req != NULL &&
handle->write_reqs_pending == 0) {
UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
@@ -1768,11 +1812,13 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
handle->reqs_pending == 0) {
/* The console handle duplicate used for line reading should be destroyed */
/* by uv_tty_read_stop. */
assert(handle->read_line_handle == NULL);
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
handle->read_line_handle == NULL);
/* The wait handle used for raw reading should be unregistered when the */
/* wait callback runs. */
assert(handle->read_raw_wait == NULL);
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
handle->read_raw_wait == NULL);
assert(!(handle->flags & UV_HANDLE_CLOSED));
uv__handle_stop(handle);

View File

@@ -135,8 +135,6 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
handle->recv_req.type = UV_UDP_RECV;
handle->recv_req.data = handle;
loop->counters.udp_init++;
return 0;
}

View File

@@ -74,7 +74,7 @@ void uv__util_init() {
}
int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size,
int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
char* utf8Buffer, size_t utf8Size) {
return WideCharToMultiByte(CP_UTF8,
0,
@@ -87,7 +87,7 @@ int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size,
}
int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer,
int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
size_t utf16Size) {
return MultiByteToWideChar(CP_UTF8,
0,
@@ -113,7 +113,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
utf16_buffer_len = (int) *size_ptr;
}
utf16_buffer = (wchar_t*) malloc(sizeof(WCHAR) * utf16_buffer_len);
utf16_buffer = (WCHAR*) malloc(sizeof(WCHAR) * utf16_buffer_len);
if (!utf16_buffer) {
return -1;
}
@@ -340,7 +340,7 @@ char** uv_setup_args(int argc, char** argv) {
uv_err_t uv_set_process_title(const char* title) {
uv_err_t err;
int length;
wchar_t* title_w = NULL;
WCHAR* title_w = NULL;
uv__once_init();
@@ -352,7 +352,7 @@ uv_err_t uv_set_process_title(const char* title) {
}
/* Convert to wide-char string */
title_w = (wchar_t*)malloc(sizeof(wchar_t) * length);
title_w = (WCHAR*)malloc(sizeof(WCHAR) * length);
if (!title_w) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
@@ -387,7 +387,7 @@ done:
static int uv__get_process_title() {
wchar_t title_w[MAX_TITLE_LENGTH];
WCHAR title_w[MAX_TITLE_LENGTH];
int length;
if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {

View File

@@ -26,7 +26,7 @@
#include <stdlib.h>
#define NUM_SYNC_REQS (10 * 1e5)
#define NUM_ASYNC_REQS (1 * 1e5)
#define NUM_ASYNC_REQS (1 * (int) 1e5)
#define MAX_CONCURRENT_REQS 32
#define sync_stat(req, path) \

View File

@@ -36,6 +36,7 @@ BENCHMARK_IMPL(sizes) {
LOGF("uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t));
LOGF("uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t));
LOGF("uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t));
LOGF("uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t));
LOGF("uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t));
LOGF("uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
LOGF("uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));

View File

@@ -103,8 +103,8 @@ int process_start(char *name, char *part, process_info_t *p) {
goto error;
if (part) {
if (_snwprintf((wchar_t*)args,
sizeof(args) / sizeof(wchar_t),
if (_snwprintf((WCHAR*)args,
sizeof(args) / sizeof(WCHAR),
L"\"%s\" %S %S",
image,
name,
@@ -112,8 +112,8 @@ int process_start(char *name, char *part, process_info_t *p) {
goto error;
}
} else {
if (_snwprintf((wchar_t*)args,
sizeof(args) / sizeof(wchar_t),
if (_snwprintf((WCHAR*)args,
sizeof(args) / sizeof(WCHAR),
L"\"%s\" %S",
image,
name) < 0) {

View File

@@ -42,7 +42,7 @@ const char* fmt(double d) {
char* p;
p = (char *) calloc(1, 32) + 31; /* leaks memory */
v = d;
v = (uint64_t) d;
#if 0 /* works but we don't care about fractional precision */
if (d - v >= 0.01) {

View File

@@ -1,215 +0,0 @@
/* 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.
*/
#define UNIX (defined(__unix__) || defined(__POSIX__) || defined(__APPLE__))
#include "task.h"
#include "uv.h"
#include <fcntl.h>
#if UNIX
#include <unistd.h> /* unlink, rmdir, etc. */
#else
# include <direct.h>
# include <io.h>
# define unlink _unlink
# define rmdir _rmdir
# define stat _stati64
# define open _open
# define write _write
# define lseek _lseek
# define close _close
#endif
static char exepath[1024];
static size_t exepath_size = 1024;
static char* args[3];
static uv_fs_t open_req;
static uv_tcp_t tcp;
static uv_udp_t udp;
static uv_pipe_t uvpipe;
static uv_tty_t tty;
static uv_prepare_t prepare;
static uv_check_t check;
static uv_idle_t idle;
static uv_async_t async;
static uv_timer_t timer;
static uv_fs_event_t fs_event;
static uv_process_t process;
static uv_process_options_t options;
static uv_fs_t fs_req;
static void exit_cb(uv_process_t* process, int exit_status, int term_signal) {
ASSERT(exit_status == 1);
ASSERT(term_signal == 0);
uv_close((uv_handle_t*)process, NULL);
}
static void init_process_options(char* test, uv_exit_cb exit_cb) {
int r = uv_exepath(exepath, &exepath_size);
ASSERT(r == 0);
exepath[exepath_size] = '\0';
args[0] = exepath;
args[1] = test;
args[2] = NULL;
options.file = exepath;
options.args = args;
options.exit_cb = exit_cb;
}
static void create_dir(uv_loop_t* loop, const char* name) {
int r;
uv_fs_t req;
r = uv_fs_rmdir(loop, &req, name, NULL);
r = uv_fs_mkdir(loop, &req, name, 0755, NULL);
ASSERT(r == 0 || uv_last_error(loop).code == UV_EEXIST);
uv_fs_req_cleanup(&req);
}
static void create_cb(uv_fs_t* req) {
ASSERT(req == &open_req);
ASSERT(req->fs_type == UV_FS_OPEN);
ASSERT(req->result != -1);
uv_fs_req_cleanup(req);
unlink("test_file");
}
TEST_IMPL(counters_init) {
int r;
uint64_t eio_init_prev;
uint64_t req_init_prev;
uint64_t handle_init_prev;
uint64_t stream_init_prev;
uint64_t tcp_init_prev;
uint64_t udp_init_prev;
uint64_t pipe_init_prev;
uint64_t tty_init_prev;
uint64_t prepare_init_prev;
uint64_t check_init_prev;
uint64_t idle_init_prev;
uint64_t async_init_prev;
uint64_t timer_init_prev;
uint64_t process_init_prev;
uint64_t fs_event_init_prev;
/* req_init and eio_init test by uv_fs_open() */
unlink("test_file");
req_init_prev = uv_default_loop()->counters.req_init;
eio_init_prev = uv_default_loop()->counters.eio_init;
r = uv_fs_open(uv_default_loop(), &open_req, "test_file", O_WRONLY | O_CREAT,
S_IREAD | S_IWRITE, create_cb);
ASSERT(r == 0);
ASSERT(open_req.result == 0);
ASSERT(uv_default_loop()->counters.req_init == ++req_init_prev);
#ifndef _WIN32
ASSERT(uv_default_loop()->counters.eio_init == ++eio_init_prev);
#endif
/* tcp_init, stream_init and handle_init test by uv_tcp_init() */
tcp_init_prev = uv_default_loop()->counters.tcp_init;
stream_init_prev = uv_default_loop()->counters.stream_init;
handle_init_prev = uv_default_loop()->counters.handle_init;
r = uv_tcp_init(uv_default_loop(), &tcp);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.tcp_init == ++tcp_init_prev);
ASSERT(uv_default_loop()->counters.stream_init == ++stream_init_prev);
ASSERT(uv_default_loop()->counters.handle_init == ++handle_init_prev);
uv_close((uv_handle_t*)&tcp, NULL);
/* udp_init test by uv_udp_init() */
udp_init_prev = uv_default_loop()->counters.udp_init;
r = uv_udp_init(uv_default_loop(), &udp);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.udp_init == ++udp_init_prev);
uv_close((uv_handle_t*)&udp, NULL);
/* pipe_init uv_pipe_init() */
pipe_init_prev = uv_default_loop()->counters.pipe_init;
uv_pipe_init(uv_default_loop(), &uvpipe, 0);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.pipe_init == ++pipe_init_prev);
uv_close((uv_handle_t*)&uvpipe, NULL);
/* tty_init test by uv_tty_init()*/
tty_init_prev = uv_default_loop()->counters.tty_init;
r = uv_tty_init(uv_default_loop(), &tty, 1, 0);
/* uv_tty_init() always returns -1 in run_test in Windows
so that we avoid to check return value.
*/
#ifndef _WIN32
ASSERT(r == 0);
uv_close((uv_handle_t*)&tty, NULL);
#endif
ASSERT(uv_default_loop()->counters.tty_init == ++tty_init_prev);
/* prepare_init test by uv_prepare_init() */
prepare_init_prev = uv_default_loop()->counters.prepare_init;
r = uv_prepare_init(uv_default_loop(), &prepare);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.prepare_init == ++prepare_init_prev);
uv_close((uv_handle_t*)&prepare, NULL);
/* check_init test by uv_check_init() */
check_init_prev = uv_default_loop()->counters.check_init;
r = uv_check_init(uv_default_loop(), &check);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.check_init == ++check_init_prev);
uv_close((uv_handle_t*)&check, NULL);
/* idle_init test by uv_idle_init() */
idle_init_prev = uv_default_loop()->counters.idle_init;
r = uv_idle_init(uv_default_loop(), &idle);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.idle_init == ++idle_init_prev);
uv_close((uv_handle_t*)&idle, NULL);
/* async_init test by uv_async_init() */
async_init_prev = uv_default_loop()->counters.async_init;
r = uv_async_init(uv_default_loop(), &async, NULL);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.async_init == ++async_init_prev);
uv_close((uv_handle_t*)&async, NULL);
/* timer_init test by uv_timer_init() */
timer_init_prev = uv_default_loop()->counters.timer_init;
r = uv_timer_init(uv_default_loop(), &timer);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.timer_init == ++timer_init_prev);
uv_close((uv_handle_t*)&timer, NULL);
/* process_init test by uv_spawn() */
process_init_prev = uv_default_loop()->counters.process_init;
init_process_options("spawn_helper1", exit_cb);
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.process_init == ++process_init_prev);
r = uv_run(uv_default_loop());
ASSERT(r == 0);
/* fs_event_init test by uv_fs_event_init() */
create_dir(uv_default_loop(), "watch_dir");
fs_event_init_prev = uv_default_loop()->counters.fs_event_init;
r = uv_fs_event_init(uv_default_loop(), &fs_event, "watch_dir", NULL, 0);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.fs_event_init == ++fs_event_init_prev);
uv_fs_rmdir(uv_default_loop(), &fs_req, "watch_dir", NULL);
uv_fs_req_cleanup(&fs_req);
return 0;
}

View File

@@ -50,7 +50,6 @@ static void close_cb(uv_handle_t* handle) {
static void do_accept(uv_timer_t* timer_handle, int status) {
uv_tcp_t* server;
uv_tcp_t* accepted_handle = (uv_tcp_t*)malloc(sizeof *accepted_handle);
uint64_t tcpcnt;
int r;
ASSERT(timer_handle != NULL);
@@ -60,15 +59,10 @@ static void do_accept(uv_timer_t* timer_handle, int status) {
r = uv_tcp_init(uv_default_loop(), accepted_handle);
ASSERT(r == 0);
/* Test to that uv_default_loop()->counters.tcp_init does not increase across the uv_accept. */
tcpcnt = uv_default_loop()->counters.tcp_init;
server = (uv_tcp_t*)timer_handle->data;
r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.tcp_init == tcpcnt);
do_accept_called++;
/* Immediately close the accepted handle. */
@@ -115,9 +109,6 @@ static void start_server() {
r = uv_tcp_init(uv_default_loop(), server);
ASSERT(r == 0);
ASSERT(uv_default_loop()->counters.tcp_init == 1);
ASSERT(uv_default_loop()->counters.handle_init == 1);
r = uv_tcp_bind(server, addr);
ASSERT(r == 0);

View File

@@ -123,6 +123,7 @@ TEST_DECLARE (getsockname_tcp)
TEST_DECLARE (getsockname_udp)
TEST_DECLARE (fail_always)
TEST_DECLARE (pass_always)
TEST_DECLARE (spawn_fails)
TEST_DECLARE (spawn_exit_code)
TEST_DECLARE (spawn_stdout)
TEST_DECLARE (spawn_stdin)
@@ -174,11 +175,12 @@ TEST_DECLARE (thread_rwlock)
TEST_DECLARE (thread_create)
TEST_DECLARE (strlcpy)
TEST_DECLARE (strlcat)
TEST_DECLARE (counters_init)
TEST_DECLARE (dlerror)
TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional)
TEST_DECLARE (poll_close)
TEST_DECLARE (we_get_signal)
TEST_DECLARE (we_get_signals)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (argument_escaping)
@@ -350,6 +352,7 @@ TASK_LIST_START
TEST_ENTRY (poll_unidirectional)
TEST_ENTRY (poll_close)
TEST_ENTRY (spawn_fails)
TEST_ENTRY (spawn_exit_code)
TEST_ENTRY (spawn_stdout)
TEST_ENTRY (spawn_stdin)
@@ -364,6 +367,10 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdout_to_file)
TEST_ENTRY (fs_poll)
TEST_ENTRY (kill)
TEST_ENTRY (we_get_signal)
TEST_ENTRY (we_get_signals)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
TEST_ENTRY (argument_escaping)
@@ -411,7 +418,6 @@ TASK_LIST_START
TEST_ENTRY (thread_create)
TEST_ENTRY (strlcpy)
TEST_ENTRY (strlcat)
TEST_ENTRY (counters_init)
TEST_ENTRY (dlerror)
#if 0
/* These are for testing the test runner. */

162
deps/uv/test/test-signal.c vendored Normal file
View File

@@ -0,0 +1,162 @@
/* 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"
#ifdef _WIN32
TEST_IMPL(we_get_signal) {
return 0;
}
TEST_IMPL(we_get_signals) {
return 0;
}
#else /* !_WIN32 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
/* This test does not pretend to be cross-platform. */
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#define NSIGNALS 10
struct timer_ctx {
unsigned int ncalls;
uv_timer_t handle;
int signum;
};
struct signal_ctx {
enum { CLOSE, STOP } stop_or_close;
unsigned int ncalls;
uv_signal_t handle;
int signum;
};
static void signal_cb(uv_signal_t* handle, int signum) {
struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle);
ASSERT(signum == ctx->signum);
if (++ctx->ncalls == NSIGNALS) {
if (ctx->stop_or_close == STOP)
uv_signal_stop(handle);
else if (ctx->stop_or_close == CLOSE)
uv_close((uv_handle_t*)handle, NULL);
else
ASSERT(0);
}
}
static void timer_cb(uv_timer_t* handle, int status) {
struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle);
raise(ctx->signum);
if (++ctx->ncalls == NSIGNALS)
uv_close((uv_handle_t*)handle, NULL);
}
static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) {
ctx->ncalls = 0;
ctx->signum = signum;
ctx->stop_or_close = CLOSE;
ASSERT(0 == uv_signal_init(loop, &ctx->handle));
ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum));
}
static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) {
ctx->ncalls = 0;
ctx->signum = signum;
ASSERT(0 == uv_timer_init(loop, &ctx->handle));
ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5));
}
TEST_IMPL(we_get_signal) {
struct signal_ctx sc;
struct timer_ctx tc;
uv_loop_t* loop;
loop = uv_default_loop();
start_timer(loop, SIGCHLD, &tc);
start_watcher(loop, SIGCHLD, &sc);
sc.stop_or_close = STOP; /* stop, don't close the signal handle */
ASSERT(0 == uv_run(loop));
ASSERT(tc.ncalls == NSIGNALS);
ASSERT(sc.ncalls == NSIGNALS);
start_timer(loop, SIGCHLD, &tc);
ASSERT(0 == uv_run(loop));
ASSERT(tc.ncalls == NSIGNALS);
ASSERT(sc.ncalls == NSIGNALS);
sc.ncalls = 0;
sc.stop_or_close = CLOSE; /* now close it when it's done */
uv_signal_start(&sc.handle, signal_cb, SIGCHLD);
start_timer(loop, SIGCHLD, &tc);
ASSERT(0 == uv_run(loop));
ASSERT(tc.ncalls == NSIGNALS);
ASSERT(sc.ncalls == NSIGNALS);
return 0;
}
TEST_IMPL(we_get_signals) {
struct signal_ctx sc[4];
struct timer_ctx tc[2];
uv_loop_t* loop;
unsigned int i;
loop = uv_default_loop();
start_watcher(loop, SIGUSR1, sc + 0);
start_watcher(loop, SIGUSR1, sc + 1);
start_watcher(loop, SIGUSR2, sc + 2);
start_watcher(loop, SIGUSR2, sc + 3);
start_timer(loop, SIGUSR1, tc + 0);
start_timer(loop, SIGUSR2, tc + 1);
ASSERT(0 == uv_run(loop));
for (i = 0; i < ARRAY_SIZE(sc); i++)
ASSERT(sc[i].ncalls == NSIGNALS);
for (i = 0; i < ARRAY_SIZE(tc); i++)
ASSERT(tc[i].ncalls == NSIGNALS);
return 0;
}
#endif /* _WIN32 */

View File

@@ -65,7 +65,7 @@ static void exit_cb_failure_expected(uv_process_t* process, int exit_status,
int term_signal) {
printf("exit_cb\n");
exit_cb_called++;
ASSERT(exit_status == 127);
ASSERT(exit_status == -1);
ASSERT(term_signal == 0);
uv_close((uv_handle_t*)process, close_cb);
}
@@ -145,6 +145,17 @@ static void timer_cb(uv_timer_t* handle, int status) {
}
TEST_IMPL(spawn_fails) {
init_process_options("", exit_cb_failure_expected);
options.file = options.args[0] = "program-that-had-better-not-exist";
ASSERT(0 == uv_spawn(uv_default_loop(), &process, options));
ASSERT(0 != uv_is_active((uv_handle_t*)&process));
ASSERT(0 == uv_run(uv_default_loop()));
ASSERT(uv_last_error(uv_default_loop()).code == UV_ENOENT);
return 0;
}
TEST_IMPL(spawn_exit_code) {
int r;
@@ -578,11 +589,11 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
}
wchar_t* make_program_args(char** args, int verbatim_arguments);
wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target);
uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
TEST_IMPL(argument_escaping) {
const wchar_t* test_str[] = {
const WCHAR* test_str[] = {
L"HelloWorld",
L"Hello World",
L"Hello\"World",
@@ -594,12 +605,13 @@ TEST_IMPL(argument_escaping) {
L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
};
const int count = sizeof(test_str) / sizeof(*test_str);
wchar_t** test_output;
wchar_t* command_line;
wchar_t** cracked;
WCHAR** test_output;
WCHAR* command_line;
WCHAR** cracked;
size_t total_size = 0;
int i;
int num_args;
uv_err_t result;
char* verbatim[] = {
"cmd.exe",
@@ -607,18 +619,18 @@ TEST_IMPL(argument_escaping) {
"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
NULL
};
wchar_t* verbatim_output;
wchar_t* non_verbatim_output;
WCHAR* verbatim_output;
WCHAR* non_verbatim_output;
test_output = calloc(count, sizeof(wchar_t*));
test_output = calloc(count, sizeof(WCHAR*));
for (i = 0; i < count; ++i) {
test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(wchar_t));
test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
quote_cmd_arg(test_str[i], test_output[i]);
wprintf(L"input : %s\n", test_str[i]);
wprintf(L"output: %s\n", test_output[i]);
total_size += wcslen(test_output[i]) + 1;
}
command_line = calloc(total_size + 1, sizeof(wchar_t));
command_line = calloc(total_size + 1, sizeof(WCHAR));
for (i = 0; i < count; ++i) {
wcscat(command_line, test_output[i]);
wcscat(command_line, L" ");
@@ -638,8 +650,10 @@ TEST_IMPL(argument_escaping) {
free(test_output[i]);
}
verbatim_output = make_program_args(verbatim, 1);
non_verbatim_output = make_program_args(verbatim, 0);
result = make_program_args(verbatim, 1, &verbatim_output);
ASSERT(result.code == UV_OK);
result = make_program_args(verbatim, 0, &non_verbatim_output);
ASSERT(result.code == UV_OK);
wprintf(L" verbatim_output: %s\n", verbatim_output);
wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
@@ -653,7 +667,7 @@ TEST_IMPL(argument_escaping) {
return 0;
}
wchar_t* make_program_env(char** env_block);
WCHAR* make_program_env(char** env_block);
TEST_IMPL(environment_creation) {
int i;
@@ -666,22 +680,22 @@ TEST_IMPL(environment_creation) {
NULL
};
wchar_t expected[512];
wchar_t* ptr = expected;
wchar_t* result;
wchar_t* str;
WCHAR expected[512];
WCHAR* ptr = expected;
WCHAR* result;
WCHAR* str;
for (i = 0; i < sizeof(environment) / sizeof(environment[0]) - 1; i++) {
ptr += uv_utf8_to_utf16(environment[i], ptr, expected + sizeof(expected) - ptr);
}
memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT="));
ptr += sizeof(L"SYSTEMROOT=")/sizeof(wchar_t) - 1;
ptr += sizeof(L"SYSTEMROOT=")/sizeof(WCHAR) - 1;
ptr += GetEnvironmentVariableW(L"SYSTEMROOT", ptr, expected + sizeof(expected) - ptr);
++ptr;
memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE="));
ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(wchar_t) - 1;
ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(WCHAR) - 1;
ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE", ptr, expected + sizeof(expected) - ptr);
++ptr;
*ptr = '\0';

View File

@@ -107,7 +107,7 @@ TEST_IMPL(tcp_unexpected_read) {
* start busy looping when the server sends a message and the client isn't
* reading.
*/
ASSERT(ticks <= 10);
ASSERT(ticks <= 20);
return 0;
}

10
deps/uv/uv.gyp vendored
View File

@@ -59,6 +59,7 @@
'sources': [
'include/uv-private/uv-win.h',
'src/win/async.c',
'src/win/atomicops-inl.h',
'src/win/core.c',
'src/win/dl.c',
'src/win/error.c',
@@ -76,6 +77,7 @@
'src/win/process-stdio.c',
'src/win/req.c',
'src/win/req-inl.h',
'src/win/signal.c',
'src/win/stream.c',
'src/win/stream-inl.h',
'src/win/tcp.c',
@@ -109,6 +111,10 @@
'include/uv-private/eio.h',
'include/uv-private/ev.h',
'include/uv-private/uv-unix.h',
'include/uv-private/uv-linux.h',
'include/uv-private/uv-sunos.h',
'include/uv-private/uv-darwin.h',
'include/uv-private/uv-bsd.h',
'src/unix/async.c',
'src/unix/core.c',
'src/unix/dl.c',
@@ -127,6 +133,7 @@
'src/unix/pipe.c',
'src/unix/poll.c',
'src/unix/process.c',
'src/unix/signal.c',
'src/unix/stream.c',
'src/unix/tcp.c',
'src/unix/thread.c',
@@ -256,6 +263,7 @@
'test/test-semaphore.c',
'test/test-shutdown-close.c',
'test/test-shutdown-eof.c',
'test/test-signal.c',
'test/test-spawn.c',
'test/test-fs-poll.c',
'test/test-stdio-over-pipes.c',
@@ -275,6 +283,7 @@
'test/test-tcp-unexpected-read.c',
'test/test-threadpool.c',
'test/test-mutexes.c',
'test/test-signal.c',
'test/test-thread.c',
'test/test-timer-again.c',
'test/test-timer.c',
@@ -284,7 +293,6 @@
'test/test-udp-options.c',
'test/test-udp-send-and-recv.c',
'test/test-udp-multicast-join.c',
'test/test-counters-init.c',
'test/test-dlerror.c',
'test/test-udp-multicast-ttl.c',
],