Merge branch 'v1.x' into merge
This commit is contained in:
commit
54a501897f
@ -48,6 +48,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/win \
|
||||
-D_WIN32_WINNT=0x0600
|
||||
libuv_la_SOURCES += src/win/async.c \
|
||||
src/win/core.c \
|
||||
src/win/detect-wakeup.c \
|
||||
src/win/dl.c \
|
||||
src/win/error.c \
|
||||
src/win/fs-event.c \
|
||||
@ -212,6 +213,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-socket-buffer-size.c \
|
||||
test/test-spawn.c \
|
||||
test/test-stdio-over-pipes.c \
|
||||
test/test-tcp-alloc-cb-fail.c \
|
||||
test/test-tcp-bind-error.c \
|
||||
test/test-tcp-bind6-error.c \
|
||||
test/test-tcp-close-accept.c \
|
||||
@ -243,6 +245,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-timer.c \
|
||||
test/test-tmpdir.c \
|
||||
test/test-tty.c \
|
||||
test/test-udp-alloc-cb-fail.c \
|
||||
test/test-udp-bind.c \
|
||||
test/test-udp-create-socket-early.c \
|
||||
test/test-udp-dgram-too-big.c \
|
||||
|
||||
12
README.md
12
README.md
@ -224,16 +224,7 @@ Run:
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
Microsoft Windows operating systems since Windows Vista. It can be built
|
||||
with either Visual Studio 2015 or MinGW-w64.
|
||||
|
||||
Linux using the GCC toolchain.
|
||||
|
||||
macOS >= 10.9 using the GCC or XCode toolchain.
|
||||
|
||||
Solaris 121 and later using GCC toolchain.
|
||||
|
||||
AIX 6 and later using GCC toolchain (see notes).
|
||||
Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md).
|
||||
|
||||
### AIX Notes
|
||||
|
||||
@ -252,7 +243,6 @@ See the [guidelines for contributing][].
|
||||
[node.js]: http://nodejs.org/
|
||||
[GYP]: http://code.google.com/p/gyp/
|
||||
[Python]: https://www.python.org/downloads/
|
||||
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
|
||||
[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md
|
||||
[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png
|
||||
[x32]: https://en.wikipedia.org/wiki/X32_ABI
|
||||
|
||||
70
SUPPORTED_PLATFORMS.md
Normal file
70
SUPPORTED_PLATFORMS.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Supported platforms
|
||||
|
||||
| System | Support type | Supported versions | Notes |
|
||||
|---|---|---|---|
|
||||
| GNU/Linux | Tier 1 | Linux >= 2.6.18 with glibc >= 2.5 | |
|
||||
| macOS | Tier 1 | macOS >= 10.7 | |
|
||||
| Windows | Tier 1 | Windows >= XP SP1 | MSVC 2008 and later are supported |
|
||||
| FreeBSD | Tier 1 | >= 9 (see note) | |
|
||||
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
|
||||
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
|
||||
| Linux with musl | Tier 2 | musl >= 1.0 | |
|
||||
| SunOS | Tier 2 | Solaris 121 and later | Maintainers: @libuv/sunos |
|
||||
| MinGW | Tier 3 | MinGW32 and MinGW-w64 | |
|
||||
| Other | Tier 3 | N/A | |
|
||||
|
||||
#### Note on FreeBSD 9
|
||||
|
||||
While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until
|
||||
it reaches end of life, in December 2016.
|
||||
|
||||
## Support types
|
||||
|
||||
* **Tier 1**: Officially supported and tested with CI. Any contributed patch
|
||||
MUST NOT break such systems. These are supported by @libuv/collaborators.
|
||||
|
||||
* **Tier 2**: Officially supported, but not necessarily tested with CI. These
|
||||
systems are maintained to the best of @libuv/collaborators ability,
|
||||
without being a top priority.
|
||||
|
||||
* **Tier 3**: Community maintained. These systems may inadvertently break and the
|
||||
community and interested parties are expected to help with the maintenance.
|
||||
|
||||
## Adding support for a new platform
|
||||
|
||||
**IMPORTANT**: Before attempting to add support for a new platform please open
|
||||
an issue about it for discussion.
|
||||
|
||||
### Unix
|
||||
|
||||
I/O handling is abstracted by an internal `uv__io_t` handle. The new platform
|
||||
will need to implement some of the functions, the prototypes are in
|
||||
``src/unix/internal.h``.
|
||||
|
||||
If the new platform requires extra fields for any handle structure, create a
|
||||
new include file in ``include/`` with the name ``uv-theplatform.h`` and add
|
||||
the appropriate defines there.
|
||||
|
||||
All functionality related to the new platform must be implemented in its own
|
||||
file inside ``src/unix/`` unless it's already done in a common file, in which
|
||||
case adding an `ifdef` is fine.
|
||||
|
||||
Two build systems are supported: autotools and GYP. Ideally both need to be
|
||||
supported, but if GYP does not support the new platform it can be left out.
|
||||
|
||||
### Windows
|
||||
|
||||
Windows is treated as a single platform, so adding support for a new platform
|
||||
would mean adding support for a new version.
|
||||
|
||||
Compilation and runtime must succeed for the minimum supported version. If a
|
||||
new API is to be used, it must be done optionally, only in supported versions.
|
||||
|
||||
### Common
|
||||
|
||||
Some common notes when adding support for new platforms:
|
||||
|
||||
* Generally libuv tries to avoid compile time checks. Do not add any to the
|
||||
autotools based build system or use version checking macros.
|
||||
Dynamically load functions and symbols if they are not supported by the
|
||||
minimum supported version.
|
||||
@ -1124,8 +1124,9 @@ static void uv__read(uv_stream_t* stream) {
|
||||
&& (count-- > 0)) {
|
||||
assert(stream->alloc_cb != NULL);
|
||||
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
/* User indicates it can't or won't handle the read. */
|
||||
stream->read_cb(stream, UV_ENOBUFS, &buf);
|
||||
return;
|
||||
|
||||
@ -165,8 +165,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
h.msg_name = &peer;
|
||||
|
||||
do {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
115
src/win/core.c
115
src/win/core.c
@ -29,6 +29,7 @@
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "queue.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
@ -78,6 +79,98 @@ static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
|
||||
}
|
||||
#endif
|
||||
|
||||
static uv_loop_t** uv__loops;
|
||||
static int uv__loops_size;
|
||||
static int uv__loops_capacity;
|
||||
#define UV__LOOPS_CHUNK_SIZE 8
|
||||
static uv_mutex_t uv__loops_lock;
|
||||
|
||||
static void uv__loops_init() {
|
||||
uv_mutex_init(&uv__loops_lock);
|
||||
uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*));
|
||||
if (!uv__loops)
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
uv__loops_size = 0;
|
||||
uv__loops_capacity = UV__LOOPS_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static int uv__loops_add(uv_loop_t* loop) {
|
||||
uv_loop_t** new_loops;
|
||||
int new_capacity, i;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
if (uv__loops_size == uv__loops_capacity) {
|
||||
new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
|
||||
if (!new_loops)
|
||||
goto failed_loops_realloc;
|
||||
uv__loops = new_loops;
|
||||
for (i = uv__loops_capacity; i < new_capacity; ++i)
|
||||
uv__loops[i] = NULL;
|
||||
uv__loops_capacity = new_capacity;
|
||||
}
|
||||
uv__loops[uv__loops_size] = loop;
|
||||
++uv__loops_size;
|
||||
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return 0;
|
||||
|
||||
failed_loops_realloc:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
static void uv__loops_remove(uv_loop_t* loop) {
|
||||
int loop_index;
|
||||
int smaller_capacity;
|
||||
uv_loop_t** new_loops;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
|
||||
if (uv__loops[loop_index] == loop)
|
||||
break;
|
||||
}
|
||||
/* If loop was not found, ignore */
|
||||
if (loop_index == uv__loops_size)
|
||||
goto loop_removed;
|
||||
|
||||
uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
|
||||
uv__loops[uv__loops_size - 1] = NULL;
|
||||
--uv__loops_size;
|
||||
|
||||
/* If we didn't grow to big skip downsizing */
|
||||
if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
|
||||
goto loop_removed;
|
||||
|
||||
/* Downsize only if more than half of buffer is free */
|
||||
smaller_capacity = uv__loops_capacity / 2;
|
||||
if (uv__loops_size >= smaller_capacity)
|
||||
goto loop_removed;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
|
||||
if (!new_loops)
|
||||
goto loop_removed;
|
||||
uv__loops = new_loops;
|
||||
uv__loops_capacity = smaller_capacity;
|
||||
|
||||
loop_removed:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
void uv__wake_all_loops() {
|
||||
int i;
|
||||
uv_loop_t* loop;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
for (i = 0; i < uv__loops_size; ++i) {
|
||||
loop = uv__loops[i];
|
||||
assert(loop);
|
||||
if (loop->iocp != INVALID_HANDLE_VALUE)
|
||||
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
|
||||
}
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
static void uv_init(void) {
|
||||
/* Tell Windows that we will handle critical errors. */
|
||||
@ -99,6 +192,9 @@ static void uv_init(void) {
|
||||
_CrtSetReportHook(uv__crt_dbg_report_handler);
|
||||
#endif
|
||||
|
||||
/* Initialize tracking of all uv loops */
|
||||
uv__loops_init();
|
||||
|
||||
/* Fetch winapi function pointers. This must be done first because other
|
||||
* initialization code might need these function pointers to be loaded.
|
||||
*/
|
||||
@ -118,6 +214,9 @@ static void uv_init(void) {
|
||||
|
||||
/* Initialize utilities */
|
||||
uv__util_init();
|
||||
|
||||
/* Initialize system wakeup detection */
|
||||
uv__init_detect_system_wakeup();
|
||||
}
|
||||
|
||||
|
||||
@ -173,6 +272,10 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
|
||||
err = uv__loops_add(loop);
|
||||
if (err)
|
||||
goto fail_async_init;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_async_init:
|
||||
@ -194,6 +297,8 @@ void uv__once_init(void) {
|
||||
void uv__loop_close(uv_loop_t* loop) {
|
||||
size_t i;
|
||||
|
||||
uv__loops_remove(loop);
|
||||
|
||||
/* close the async handle without needing an extra loop iteration */
|
||||
assert(!loop->wq_async.async_sent);
|
||||
loop->wq_async.close_cb = NULL;
|
||||
@ -267,9 +372,13 @@ static void uv__loop_poll(uv_loop_t* loop, DWORD timeout) {
|
||||
|
||||
if (success) {
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Package was dequeued */
|
||||
req = container_of(overlappeds[i].lpOverlapped, uv_req_t, u.io.overlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
/* Package was dequeued, but see if it is not a empty package
|
||||
* meant only to wake us up.
|
||||
*/
|
||||
if (overlappeds[i].lpOverlapped) {
|
||||
req = container_of(overlappeds[i].lpOverlapped, uv_req_t, u.io.overlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
/* Some time might have passed waiting for I/O,
|
||||
|
||||
35
src/win/detect-wakeup.c
Normal file
35
src/win/detect-wakeup.c
Normal file
@ -0,0 +1,35 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "winapi.h"
|
||||
|
||||
static void uv__register_system_resume_callback();
|
||||
|
||||
void uv__init_detect_system_wakeup() {
|
||||
/* Try registering system power event callback. This is the cleanest
|
||||
* method, but it will only work on Win8 and above.
|
||||
*/
|
||||
uv__register_system_resume_callback();
|
||||
}
|
||||
|
||||
static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
|
||||
ULONG Type,
|
||||
PVOID Setting) {
|
||||
if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
|
||||
uv__wake_all_loops();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uv__register_system_resume_callback() {
|
||||
_DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
|
||||
_HPOWERNOTIFY registration_handle;
|
||||
|
||||
if (pPowerRegisterSuspendResumeNotification == NULL)
|
||||
return;
|
||||
|
||||
recipient.Callback = uv__system_resume_callback;
|
||||
recipient.Context = NULL;
|
||||
(*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
|
||||
&recipient,
|
||||
®istration_handle);
|
||||
}
|
||||
29
src/win/fs.c
29
src/win/fs.c
@ -1088,17 +1088,28 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
|
||||
statbuf->st_mode = 0;
|
||||
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
statbuf->st_mode |= S_IFLNK;
|
||||
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
|
||||
/*
|
||||
* It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
|
||||
* any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
|
||||
* the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
|
||||
* calculated below will indicate a normal directory or file, as if
|
||||
* FILE_ATTRIBUTE_REPARSE_POINT was not present.
|
||||
*/
|
||||
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
|
||||
statbuf->st_mode |= S_IFLNK;
|
||||
} else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
statbuf->st_mode |= _S_IFDIR;
|
||||
statbuf->st_size = 0;
|
||||
|
||||
} else {
|
||||
statbuf->st_mode |= _S_IFREG;
|
||||
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
if (statbuf->st_mode == 0) {
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
statbuf->st_mode |= _S_IFDIR;
|
||||
statbuf->st_size = 0;
|
||||
} else {
|
||||
statbuf->st_mode |= _S_IFREG;
|
||||
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
|
||||
@ -379,4 +379,14 @@ extern int uv_tcp_non_ifs_lsp_ipv6;
|
||||
extern struct sockaddr_in uv_addr_ip4_any_;
|
||||
extern struct sockaddr_in6 uv_addr_ip6_any_;
|
||||
|
||||
/*
|
||||
* Wake all loops with fake message
|
||||
*/
|
||||
void uv__wake_all_loops();
|
||||
|
||||
/*
|
||||
* Init system wake-up detection
|
||||
*/
|
||||
void uv__init_detect_system_wakeup();
|
||||
|
||||
#endif /* UV_WIN_INTERNAL_H_ */
|
||||
|
||||
@ -1633,8 +1633,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -476,7 +476,6 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
|
||||
req = &handle->read_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
handle->flags |= UV_HANDLE_ZERO_READ;
|
||||
buf.base = "";
|
||||
buf.len = 0;
|
||||
@ -974,8 +973,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
|
||||
/* Do nonblocking reads until the buffer is empty */
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -502,8 +502,10 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
req = &handle->read_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
|
||||
if (handle->tty.rd.read_line_buffer.len == 0) {
|
||||
if (handle->tty.rd.read_line_buffer.base == NULL ||
|
||||
handle->tty.rd.read_line_buffer.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle,
|
||||
UV_ENOBUFS,
|
||||
&handle->tty.rd.read_line_buffer);
|
||||
@ -826,8 +828,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
|
||||
/* Allocate a buffer if needed */
|
||||
if (buf_used == 0) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -270,9 +270,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
|
||||
req = &handle->recv_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
handle->flags |= UV_HANDLE_ZERO_READ;
|
||||
|
||||
buf.base = "";
|
||||
buf.len = 0;
|
||||
flags = MSG_PEEK;
|
||||
@ -445,8 +443,9 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
|
||||
/* Do a nonblocking receive */
|
||||
/* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -38,9 +38,14 @@ sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
/* Kernel32 function pointers */
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
|
||||
void uv_winapi_init() {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE powrprof_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
@ -99,4 +104,9 @@ void uv_winapi_init() {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
}
|
||||
|
||||
powrprof_module = LoadLibraryA("powrprof.dll");
|
||||
if (powrprof_module != NULL) {
|
||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4620,6 +4620,40 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
|
||||
# define ERROR_MUI_FILE_NOT_LOADED 15105
|
||||
#endif
|
||||
|
||||
/* from powerbase.h */
|
||||
#ifndef DEVICE_NOTIFY_CALLBACK
|
||||
# define DEVICE_NOTIFY_CALLBACK 2
|
||||
#endif
|
||||
|
||||
#ifndef PBT_APMRESUMEAUTOMATIC
|
||||
# define PBT_APMRESUMEAUTOMATIC 18
|
||||
#endif
|
||||
|
||||
#ifndef PBT_APMRESUMESUSPEND
|
||||
# define PBT_APMRESUMESUSPEND 7
|
||||
#endif
|
||||
|
||||
typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE(
|
||||
PVOID Context,
|
||||
ULONG Type,
|
||||
PVOID Setting
|
||||
);
|
||||
typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE;
|
||||
|
||||
typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
|
||||
_PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;
|
||||
PVOID Context;
|
||||
} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;
|
||||
|
||||
typedef PVOID _HPOWERNOTIFY;
|
||||
typedef _HPOWERNOTIFY *_PHPOWERNOTIFY;
|
||||
|
||||
typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
|
||||
(DWORD Flags,
|
||||
HANDLE Recipient,
|
||||
_PHPOWERNOTIFY RegistrationHandle);
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
@ -4633,4 +4667,8 @@ extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
/* Kernel32 function pointers */
|
||||
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
#endif /* UV_WIN_WINAPI_H_ */
|
||||
|
||||
@ -61,6 +61,7 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess)
|
||||
TEST_DECLARE (ipc_send_recv_tcp)
|
||||
TEST_DECLARE (ipc_send_recv_tcp_inprocess)
|
||||
TEST_DECLARE (ipc_tcp_connection)
|
||||
TEST_DECLARE (tcp_alloc_cb_fail)
|
||||
TEST_DECLARE (tcp_ping_pong)
|
||||
TEST_DECLARE (tcp_ping_pong_v6)
|
||||
TEST_DECLARE (pipe_ping_pong)
|
||||
@ -106,6 +107,7 @@ TEST_DECLARE (tcp_bind6_error_addrnotavail)
|
||||
TEST_DECLARE (tcp_bind6_error_fault)
|
||||
TEST_DECLARE (tcp_bind6_error_inval)
|
||||
TEST_DECLARE (tcp_bind6_localhost_ok)
|
||||
TEST_DECLARE (udp_alloc_cb_fail)
|
||||
TEST_DECLARE (udp_bind)
|
||||
TEST_DECLARE (udp_bind_reuseaddr)
|
||||
TEST_DECLARE (udp_create_early)
|
||||
@ -416,6 +418,8 @@ TASK_LIST_START
|
||||
TEST_ENTRY (ipc_send_recv_tcp_inprocess)
|
||||
TEST_ENTRY (ipc_tcp_connection)
|
||||
|
||||
TEST_ENTRY (tcp_alloc_cb_fail)
|
||||
|
||||
TEST_ENTRY (tcp_ping_pong)
|
||||
TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
|
||||
|
||||
@ -483,6 +487,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (tcp_bind6_error_inval)
|
||||
TEST_ENTRY (tcp_bind6_localhost_ok)
|
||||
|
||||
TEST_ENTRY (udp_alloc_cb_fail)
|
||||
TEST_ENTRY (udp_bind)
|
||||
TEST_ENTRY (udp_bind_reuseaddr)
|
||||
TEST_ENTRY (udp_create_early)
|
||||
|
||||
123
test/test-tcp-alloc-cb-fail.c
Normal file
123
test/test-tcp-alloc-cb-fail.c
Normal file
@ -0,0 +1,123 @@
|
||||
/* Copyright libuv project and 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
static uv_tcp_t server;
|
||||
static uv_tcp_t client;
|
||||
static uv_tcp_t incoming;
|
||||
static int connect_cb_called;
|
||||
static int close_cb_called;
|
||||
static int connection_cb_called;
|
||||
static uv_write_t write_req;
|
||||
|
||||
static char hello[] = "HELLO!";
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
ASSERT(status == 0);
|
||||
}
|
||||
|
||||
static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
/* Do nothing, read_cb should be called with UV_ENOBUFS. */
|
||||
}
|
||||
|
||||
static void conn_read_cb(uv_stream_t* stream,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) {
|
||||
ASSERT(nread == UV_ENOBUFS);
|
||||
ASSERT(buf->base == NULL);
|
||||
ASSERT(buf->len == 0);
|
||||
|
||||
uv_close((uv_handle_t*) &incoming, close_cb);
|
||||
uv_close((uv_handle_t*) &client, close_cb);
|
||||
uv_close((uv_handle_t*) &server, close_cb);
|
||||
}
|
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) {
|
||||
int r;
|
||||
uv_buf_t buf;
|
||||
|
||||
ASSERT(status == 0);
|
||||
connect_cb_called++;
|
||||
|
||||
buf = uv_buf_init(hello, sizeof(hello));
|
||||
r = uv_write(&write_req, req->handle, &buf, 1, write_cb);
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
|
||||
|
||||
static void connection_cb(uv_stream_t* tcp, int status) {
|
||||
ASSERT(status == 0);
|
||||
|
||||
ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
|
||||
ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
|
||||
ASSERT(0 == uv_read_start((uv_stream_t*) &incoming,
|
||||
conn_alloc_cb,
|
||||
conn_read_cb));
|
||||
|
||||
connection_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void start_server(void) {
|
||||
struct sockaddr_in addr;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
|
||||
ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
|
||||
ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(tcp_alloc_cb_fail) {
|
||||
uv_connect_t connect_req;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
start_server();
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
|
||||
ASSERT(0 == uv_tcp_connect(&connect_req,
|
||||
&client,
|
||||
(struct sockaddr*) &addr,
|
||||
connect_cb));
|
||||
|
||||
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||
|
||||
ASSERT(connect_cb_called == 1);
|
||||
ASSERT(connection_cb_called == 1);
|
||||
ASSERT(close_cb_called == 3);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
@ -46,13 +46,13 @@ static void close_cb(uv_handle_t* handle) {
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
void timer_cb(uv_timer_t* handle) {
|
||||
static void timer_cb(uv_timer_t* handle) {
|
||||
uv_close((uv_handle_t*) &client, close_cb);
|
||||
uv_close((uv_handle_t*) &server, close_cb);
|
||||
uv_close((uv_handle_t*) &incoming, close_cb);
|
||||
}
|
||||
|
||||
void write_cb(uv_write_t* req, int status) {
|
||||
static void write_cb(uv_write_t* req, int status) {
|
||||
if (status == 0)
|
||||
write_callbacks++;
|
||||
else if (status == UV_ECANCELED)
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
#else /* Unix */
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# if defined(__linux__)
|
||||
# if defined(__linux__) && !defined(__ANDROID__)
|
||||
# include <pty.h>
|
||||
# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||
# include <util.h>
|
||||
@ -260,7 +260,7 @@ TEST_IMPL(tty_file) {
|
||||
}
|
||||
|
||||
TEST_IMPL(tty_pty) {
|
||||
# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
|
||||
# if defined(__linux__) && !defined(__ANDROID__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
|
||||
defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
int master_fd, slave_fd, r;
|
||||
struct winsize w;
|
||||
|
||||
197
test/test-udp-alloc-cb-fail.c
Normal file
197
test/test-udp-alloc-cb-fail.c
Normal file
@ -0,0 +1,197 @@
|
||||
/* Copyright libuv project and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CHECK_HANDLE(handle) \
|
||||
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
|
||||
|
||||
static uv_udp_t server;
|
||||
static uv_udp_t client;
|
||||
|
||||
static int cl_send_cb_called;
|
||||
static int cl_recv_cb_called;
|
||||
|
||||
static int sv_send_cb_called;
|
||||
static int sv_recv_cb_called;
|
||||
|
||||
static int close_cb_called;
|
||||
|
||||
|
||||
static void sv_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
static char slab[65536];
|
||||
CHECK_HANDLE(handle);
|
||||
buf->base = slab;
|
||||
buf->len = sizeof(slab);
|
||||
}
|
||||
|
||||
|
||||
static void cl_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
/* Do nothing, recv_cb should be called with UV_ENOBUFS. */
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_handle_t* handle) {
|
||||
CHECK_HANDLE(handle);
|
||||
ASSERT(1 == uv_is_closing(handle));
|
||||
close_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void cl_recv_cb(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
CHECK_HANDLE(handle);
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(nread == UV_ENOBUFS);
|
||||
|
||||
cl_recv_cb_called++;
|
||||
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
}
|
||||
|
||||
|
||||
static void cl_send_cb(uv_udp_send_t* req, int status) {
|
||||
int r;
|
||||
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
CHECK_HANDLE(req->handle);
|
||||
|
||||
r = uv_udp_recv_start(req->handle, cl_alloc_cb, cl_recv_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
cl_send_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void sv_send_cb(uv_udp_send_t* req, int status) {
|
||||
ASSERT(req != NULL);
|
||||
ASSERT(status == 0);
|
||||
CHECK_HANDLE(req->handle);
|
||||
|
||||
uv_close((uv_handle_t*) req->handle, close_cb);
|
||||
free(req);
|
||||
|
||||
sv_send_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void sv_recv_cb(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* rcvbuf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
uv_udp_send_t* req;
|
||||
uv_buf_t sndbuf;
|
||||
int r;
|
||||
|
||||
if (nread < 0) {
|
||||
ASSERT(0 && "unexpected error");
|
||||
}
|
||||
|
||||
if (nread == 0) {
|
||||
/* Returning unused buffer */
|
||||
/* Don't count towards sv_recv_cb_called */
|
||||
ASSERT(addr == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_HANDLE(handle);
|
||||
ASSERT(flags == 0);
|
||||
|
||||
ASSERT(addr != NULL);
|
||||
ASSERT(nread == 4);
|
||||
ASSERT(!memcmp("PING", rcvbuf->base, nread));
|
||||
|
||||
r = uv_udp_recv_stop(handle);
|
||||
ASSERT(r == 0);
|
||||
|
||||
req = malloc(sizeof *req);
|
||||
ASSERT(req != NULL);
|
||||
|
||||
sndbuf = uv_buf_init("PONG", 4);
|
||||
r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
sv_recv_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(udp_alloc_cb_fail) {
|
||||
struct sockaddr_in addr;
|
||||
uv_udp_send_t req;
|
||||
uv_buf_t buf;
|
||||
int r;
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
|
||||
r = uv_udp_init(uv_default_loop(), &server);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_udp_recv_start(&server, sv_alloc_cb, sv_recv_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
|
||||
r = uv_udp_init(uv_default_loop(), &client);
|
||||
ASSERT(r == 0);
|
||||
|
||||
buf = uv_buf_init("PING", 4);
|
||||
r = uv_udp_send(&req,
|
||||
&client,
|
||||
&buf,
|
||||
1,
|
||||
(const struct sockaddr*) &addr,
|
||||
cl_send_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(close_cb_called == 0);
|
||||
ASSERT(cl_send_cb_called == 0);
|
||||
ASSERT(cl_recv_cb_called == 0);
|
||||
ASSERT(sv_send_cb_called == 0);
|
||||
ASSERT(sv_recv_cb_called == 0);
|
||||
|
||||
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
ASSERT(cl_send_cb_called == 1);
|
||||
ASSERT(cl_recv_cb_called == 1);
|
||||
ASSERT(sv_send_cb_called == 1);
|
||||
ASSERT(sv_recv_cb_called == 1);
|
||||
ASSERT(close_cb_called == 2);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
3
uv.gyp
3
uv.gyp
@ -75,6 +75,7 @@
|
||||
'include/uv-win.h',
|
||||
'src/win/async.c',
|
||||
'src/win/core.c',
|
||||
'src/win/detect-wakeup.c',
|
||||
'src/win/dl.c',
|
||||
'src/win/error.c',
|
||||
'src/win/fs.c',
|
||||
@ -360,6 +361,7 @@
|
||||
'test/test-spawn.c',
|
||||
'test/test-fs-poll.c',
|
||||
'test/test-stdio-over-pipes.c',
|
||||
'test/test-tcp-alloc-cb-fail.c',
|
||||
'test/test-tcp-bind-error.c',
|
||||
'test/test-tcp-bind6-error.c',
|
||||
'test/test-tcp-close.c',
|
||||
@ -394,6 +396,7 @@
|
||||
'test/test-timer-from-check.c',
|
||||
'test/test-timer.c',
|
||||
'test/test-tty.c',
|
||||
'test/test-udp-alloc-cb-fail.c',
|
||||
'test/test-udp-bind.c',
|
||||
'test/test-udp-create-socket-early.c',
|
||||
'test/test-udp-dgram-too-big.c',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user