From 653545fd35d5c913fdfc6ff70c23a98cd835a514 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sat, 17 Nov 2018 02:02:49 -0800 Subject: [PATCH 01/14] test: make test-connect-success-events more robust --- test/test-connect-success-events.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/test-connect-success-events.c b/test/test-connect-success-events.c index 3f55cc3..525fb71 100644 --- a/test/test-connect-success-events.c +++ b/test/test-connect-success-events.c @@ -76,23 +76,29 @@ int main(void) { /* Wait for client end to become writable. */ r = epoll_wait(ephnd, evs, array_count(evs), -1); - check(r == 1); - check(evs[0].data.sock == client_sock); - check(evs[0].events == EPOLLOUT); /* Try to send data until the kernel buffer is full. */ memset(buf, round, sizeof buf); bytes_sent = 0; do { + /* We shouldn't get here unless epoll_wait() reported that the client + * socket is writable. */ + check(r == 1); + check(evs[0].data.sock == client_sock); + check(evs[0].events == EPOLLOUT); + + /* The actual send() call should never fail, because epoll_wait() just + * reported the socket as writable. */ r = send(client_sock, buf, sizeof buf, 0); - if (r >= 0) - bytes_sent += r; - else - check(WSAGetLastError() == WSAEWOULDBLOCK); + check(r > 0); + bytes_sent += r; + + /* Call epoll_wait() without blocking to see if there's more space in the + * kernel write buffer. */ + r = epoll_wait(ephnd, evs, array_count(evs), 0); } while (r > 0); - /* The client end should not be writable now. */ - r = epoll_wait(ephnd, evs, array_count(evs), 0); + /* Verify that epoll_wait() reported no events, but did not fail. */ check(r == 0); /* Read all data incoming on the server end of the connection. */ From a82802933afe600166da2d4fcf5cf05148141434 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 18 Nov 2018 03:06:13 -0800 Subject: [PATCH 02/14] build: strip clang-format on/off directives from combined source --- tools/combine.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/combine.js b/tools/combine.js index 808f574..e08b66a 100644 --- a/tools/combine.js +++ b/tools/combine.js @@ -141,7 +141,8 @@ restart: for (let lno = 0; lno < source.length;) { } source = source - .map((line) => line.replace(/\s+$/, '')) + .map(line => line.replace(/\/\* clang-format (on|off) \*\//g, '')) + .map(line => line.replace(/\s+$/, '')) .join('\n') .replace(/\n{3,}/g, '\n\n') .replace(/\n*$/, '\n'); From 97276ce4ddaeca292a9e5d735b19d50565cef773 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 25 Nov 2018 23:25:13 -0700 Subject: [PATCH 03/14] nt: remove unused LSA_UNICODE_STRING type --- src/nt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nt.h b/src/nt.h index 89c7eac..71ea0fe 100644 --- a/src/nt.h +++ b/src/nt.h @@ -34,11 +34,11 @@ typedef VOID(NTAPI* PIO_APC_ROUTINE)(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved); -typedef struct _LSA_UNICODE_STRING { +typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; -} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING; +} UNICODE_STRING, *PUNICODE_STRING; #define RTL_CONSTANT_STRING(s) \ { sizeof(s) - sizeof((s)[0]), sizeof(s), s } From 1bc78625f01244193a1eff2bf8b4ec3084db0c62 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 26 Nov 2018 15:49:04 -0700 Subject: [PATCH 04/14] tools/release: simplify regex --- tools/release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release.js b/tools/release.js index 4249995..f452e10 100644 --- a/tools/release.js +++ b/tools/release.js @@ -1,7 +1,7 @@ const exec = require('child_process').execSync; const resolve = require('path').resolve; -const getSHA = (s) => s.match(/^\s*([0-9a-fA-F]{40})\s*$/)[1]; +const getSHA = (s) => s.match(/^\s*([0-9a-f]{40})\s*$/i)[1]; const inherit = { stdio: 'inherit' }; const utf8 = { encoding: 'utf8' }; From 11633bf4033913e7a2b1002dc86c894e92e85a78 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 26 Nov 2018 15:52:07 -0700 Subject: [PATCH 05/14] tools/combine: use arrow functions for Array.map closures --- tools/combine.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/combine.js b/tools/combine.js index e08b66a..68ecf0b 100644 --- a/tools/combine.js +++ b/tools/combine.js @@ -105,12 +105,9 @@ source = source.concat('/*') .concat(fs.readFileSync('LICENSE', 'utf8') .replace(/^\s+|\s+$/g, '') .split(/\r?\n/g) - .map(function(s) { - return ' * ' + s; - }) - .map(function(s) { - return s.replace(/\s+$/, ''); - })) + .map(line => ' * ' + line) + .map(line => line.replace(/\s+$/, '')) + ) .concat(' */') .concat(''); From fca062c60df8811ab7753fded38cdf040979b92e Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 26 Nov 2018 15:52:34 -0700 Subject: [PATCH 06/14] tools: remove optional parentheses around arrow function parameters --- tools/combine.js | 2 +- tools/release.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/combine.js b/tools/combine.js index 68ecf0b..762b4a9 100644 --- a/tools/combine.js +++ b/tools/combine.js @@ -11,7 +11,7 @@ let stripGuardsEnabled = false; process.argv .slice(2) - .forEach((arg) => { + .forEach(arg => { let match; if ((match = /^-I(.*)$/.exec(arg))) includeDirs.push(match[1]); diff --git a/tools/release.js b/tools/release.js index f452e10..1f2c98b 100644 --- a/tools/release.js +++ b/tools/release.js @@ -1,7 +1,7 @@ const exec = require('child_process').execSync; const resolve = require('path').resolve; -const getSHA = (s) => s.match(/^\s*([0-9a-f]{40})\s*$/i)[1]; +const getSHA = s => s.match(/^\s*([0-9a-f]{40})\s*$/i)[1]; const inherit = { stdio: 'inherit' }; const utf8 = { encoding: 'utf8' }; From 210f4f8fbaece0b28d5e549c71fa96fc72e86cf5 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 26 Nov 2018 16:43:01 -0700 Subject: [PATCH 07/14] init: fix grammar and clarify comment --- src/init.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/init.c b/src/init.c index 0deae84..db237d4 100644 --- a/src/init.c +++ b/src/init.c @@ -30,7 +30,11 @@ static BOOL CALLBACK init__once_callback(INIT_ONCE* once, int init(void) { if (!init__done && !InitOnceExecuteOnce(&init__once, init__once_callback, NULL, NULL)) - return -1; /* LastError and errno aren't touched InitOnceExecuteOnce. */ + /* `InitOnceExecuteOnce()` itself is infallible, and it doesn't set any + * error code when the once-callback returns FALSE. We return -1 here to + * indicate that global initialization failed; the failing init function is + * resposible for setting `errno` and calling `SetLastError()`. */ + return -1; return 0; } From b55b10a934c4d5b1f2f59e3137e955f4950d6ffc Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 4 Dec 2018 12:28:46 -0800 Subject: [PATCH 08/14] reflock: use lowercase for hex digits consistently --- src/reflock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reflock.c b/src/reflock.c index 6e2af8c..4412aca 100644 --- a/src/reflock.c +++ b/src/reflock.c @@ -13,7 +13,7 @@ static const long REFLOCK__REF = (long) 0x00000001; static const long REFLOCK__REF_MASK = (long) 0x0fffffff; static const long REFLOCK__DESTROY = (long) 0x10000000; static const long REFLOCK__DESTROY_MASK = (long) 0xf0000000; -static const long REFLOCK__POISON = (long) 0x300DEAD0; +static const long REFLOCK__POISON = (long) 0x300dead0; /* clang-format on */ static HANDLE reflock__keyed_event = NULL; From b7289278e1fdfdc6170e4696f1c04965e6ba0684 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 4 Dec 2018 13:19:40 -0800 Subject: [PATCH 09/14] reflock: make assert in reflock_unref() more strict, improve comments --- src/reflock.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/reflock.c b/src/reflock.c index 4412aca..67ff48b 100644 --- a/src/reflock.c +++ b/src/reflock.c @@ -46,22 +46,20 @@ static void reflock__await_event(void* address) { void reflock_ref(reflock_t* reflock) { long state = InterlockedAdd(&reflock->state, REFLOCK__REF); + + /* Verify that the counter didn't overflow and the lock isn't destroyed. */ + assert((state & REFLOCK__DESTROY_MASK) == 0); unused_var(state); - assert((state & REFLOCK__DESTROY_MASK) == 0); /* Overflow or destroyed. */ } void reflock_unref(reflock_t* reflock) { long state = InterlockedAdd(&reflock->state, -REFLOCK__REF); - long ref_count = state & REFLOCK__REF_MASK; - long destroy = state & REFLOCK__DESTROY_MASK; - unused_var(ref_count); - unused_var(destroy); + /* Verify that the lock was referenced and not already destroyed. */ + assert((state & REFLOCK__DESTROY_MASK & ~REFLOCK__DESTROY) == 0); if (state == REFLOCK__DESTROY) reflock__signal_event(reflock); - else - assert(destroy == 0 || ref_count > 0); } void reflock_unref_and_destroy(reflock_t* reflock) { @@ -69,8 +67,8 @@ void reflock_unref_and_destroy(reflock_t* reflock) { InterlockedAdd(&reflock->state, REFLOCK__DESTROY - REFLOCK__REF); long ref_count = state & REFLOCK__REF_MASK; - assert((state & REFLOCK__DESTROY_MASK) == - REFLOCK__DESTROY); /* Underflow or already destroyed. */ + /* Verify that the lock was referenced and not already destroyed. */ + assert((state & REFLOCK__DESTROY_MASK) == REFLOCK__DESTROY); if (ref_count != 0) reflock__await_event(reflock); From 2cd1a594d4583818db9a179d39c82ed0200e01a4 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 6 Dec 2018 07:11:11 +0100 Subject: [PATCH 10/14] nt: sort NT_NTDLL_IMPORT_LIST --- src/nt.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/nt.h b/src/nt.h index 71ea0fe..2e7ef05 100644 --- a/src/nt.h +++ b/src/nt.h @@ -75,6 +75,14 @@ typedef struct _OBJECT_ATTRIBUTES { PVOID EaBuffer, \ ULONG EaLength)) \ \ + X(NTSTATUS, \ + NTAPI, \ + NtCreateKeyedEvent, \ + (PHANDLE handle, \ + ACCESS_MASK access, \ + POBJECT_ATTRIBUTES attr, \ + ULONG flags)) \ + \ X(NTSTATUS, \ NTAPI, \ NtDeviceIoControlFile, \ @@ -89,25 +97,17 @@ typedef struct _OBJECT_ATTRIBUTES { PVOID OutputBuffer, \ ULONG OutputBufferLength)) \ \ - X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status)) \ - \ X(NTSTATUS, \ NTAPI, \ - NtCreateKeyedEvent, \ - (PHANDLE handle, \ - ACCESS_MASK access, \ - POBJECT_ATTRIBUTES attr, \ - ULONG flags)) \ + NtReleaseKeyedEvent, \ + (HANDLE handle, PVOID key, BOOLEAN alertable, PLARGE_INTEGER mstimeout)) \ \ X(NTSTATUS, \ NTAPI, \ NtWaitForKeyedEvent, \ (HANDLE handle, PVOID key, BOOLEAN alertable, PLARGE_INTEGER mstimeout)) \ \ - X(NTSTATUS, \ - NTAPI, \ - NtReleaseKeyedEvent, \ - (HANDLE handle, PVOID key, BOOLEAN alertable, PLARGE_INTEGER mstimeout)) + X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status)) #define X(return_type, attributes, name, parameters) \ WEPOLL_INTERNAL_VAR return_type(attributes* name) parameters; From ec78f05d70bb963725ae20c3e6be6058440ed1a1 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 6 Dec 2018 07:23:46 +0100 Subject: [PATCH 11/14] nt: use documented parameter names for keyed event functions --- src/nt.h | 102 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/src/nt.h b/src/nt.h index 2e7ef05..ec9bfab 100644 --- a/src/nt.h +++ b/src/nt.h @@ -59,54 +59,60 @@ typedef struct _OBJECT_ATTRIBUTES { #define FILE_OPEN 0x00000001UL #endif -#define NT_NTDLL_IMPORT_LIST(X) \ - X(NTSTATUS, \ - NTAPI, \ - NtCreateFile, \ - (PHANDLE FileHandle, \ - ACCESS_MASK DesiredAccess, \ - POBJECT_ATTRIBUTES ObjectAttributes, \ - PIO_STATUS_BLOCK IoStatusBlock, \ - PLARGE_INTEGER AllocationSize, \ - ULONG FileAttributes, \ - ULONG ShareAccess, \ - ULONG CreateDisposition, \ - ULONG CreateOptions, \ - PVOID EaBuffer, \ - ULONG EaLength)) \ - \ - X(NTSTATUS, \ - NTAPI, \ - NtCreateKeyedEvent, \ - (PHANDLE handle, \ - ACCESS_MASK access, \ - POBJECT_ATTRIBUTES attr, \ - ULONG flags)) \ - \ - X(NTSTATUS, \ - NTAPI, \ - NtDeviceIoControlFile, \ - (HANDLE FileHandle, \ - HANDLE Event, \ - PIO_APC_ROUTINE ApcRoutine, \ - PVOID ApcContext, \ - PIO_STATUS_BLOCK IoStatusBlock, \ - ULONG IoControlCode, \ - PVOID InputBuffer, \ - ULONG InputBufferLength, \ - PVOID OutputBuffer, \ - ULONG OutputBufferLength)) \ - \ - X(NTSTATUS, \ - NTAPI, \ - NtReleaseKeyedEvent, \ - (HANDLE handle, PVOID key, BOOLEAN alertable, PLARGE_INTEGER mstimeout)) \ - \ - X(NTSTATUS, \ - NTAPI, \ - NtWaitForKeyedEvent, \ - (HANDLE handle, PVOID key, BOOLEAN alertable, PLARGE_INTEGER mstimeout)) \ - \ +#define NT_NTDLL_IMPORT_LIST(X) \ + X(NTSTATUS, \ + NTAPI, \ + NtCreateFile, \ + (PHANDLE FileHandle, \ + ACCESS_MASK DesiredAccess, \ + POBJECT_ATTRIBUTES ObjectAttributes, \ + PIO_STATUS_BLOCK IoStatusBlock, \ + PLARGE_INTEGER AllocationSize, \ + ULONG FileAttributes, \ + ULONG ShareAccess, \ + ULONG CreateDisposition, \ + ULONG CreateOptions, \ + PVOID EaBuffer, \ + ULONG EaLength)) \ + \ + X(NTSTATUS, \ + NTAPI, \ + NtCreateKeyedEvent, \ + (PHANDLE KeyedEventHandle, \ + ACCESS_MASK DesiredAccess, \ + POBJECT_ATTRIBUTES ObjectAttributes, \ + ULONG Flags)) \ + \ + X(NTSTATUS, \ + NTAPI, \ + NtDeviceIoControlFile, \ + (HANDLE FileHandle, \ + HANDLE Event, \ + PIO_APC_ROUTINE ApcRoutine, \ + PVOID ApcContext, \ + PIO_STATUS_BLOCK IoStatusBlock, \ + ULONG IoControlCode, \ + PVOID InputBuffer, \ + ULONG InputBufferLength, \ + PVOID OutputBuffer, \ + ULONG OutputBufferLength)) \ + \ + X(NTSTATUS, \ + NTAPI, \ + NtReleaseKeyedEvent, \ + (HANDLE KeyedEventHandle, \ + PVOID KeyValue, \ + BOOLEAN Alertable, \ + PLARGE_INTEGER Timeout)) \ + \ + X(NTSTATUS, \ + NTAPI, \ + NtWaitForKeyedEvent, \ + (HANDLE KeyedEventHandle, \ + PVOID KeyValue, \ + BOOLEAN Alertable, \ + PLARGE_INTEGER Timeout)) \ + \ X(ULONG, WINAPI, RtlNtStatusToDosError, (NTSTATUS Status)) #define X(return_type, attributes, name, parameters) \ From 870273c60d725d951b4e9e7b7a44200cb94b9e8d Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 6 Dec 2018 08:53:27 +0100 Subject: [PATCH 12/14] reflock: use proper access mask when creating keyed event --- src/nt.h | 5 +++++ src/reflock.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nt.h b/src/nt.h index ec9bfab..07a9eb6 100644 --- a/src/nt.h +++ b/src/nt.h @@ -59,6 +59,11 @@ typedef struct _OBJECT_ATTRIBUTES { #define FILE_OPEN 0x00000001UL #endif +#define KEYEDEVENT_WAIT 0x00000001UL +#define KEYEDEVENT_WAKE 0x00000002UL +#define KEYEDEVENT_ALL_ACCESS \ + (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE) + #define NT_NTDLL_IMPORT_LIST(X) \ X(NTSTATUS, \ NTAPI, \ diff --git a/src/reflock.c b/src/reflock.c index 67ff48b..fe5ac12 100644 --- a/src/reflock.c +++ b/src/reflock.c @@ -20,7 +20,7 @@ static HANDLE reflock__keyed_event = NULL; int reflock_global_init(void) { NTSTATUS status = - NtCreateKeyedEvent(&reflock__keyed_event, ~(ACCESS_MASK) 0, NULL, 0); + NtCreateKeyedEvent(&reflock__keyed_event, KEYEDEVENT_ALL_ACCESS, NULL, 0); if (status != STATUS_SUCCESS) return_set_error(-1, RtlNtStatusToDosError(status)); return 0; From f196d9fc31b2406b034a4ebfbd70a2d57d2cff4a Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 5 May 2019 04:45:29 +0200 Subject: [PATCH 13/14] doc: update copyright years --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 31ad7c2..6c8b1c8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ wepoll - epoll for Windows https://github.com/piscisaureus/wepoll -Copyright 2012-2018, Bert Belder +Copyright 2012-2019, Bert Belder All rights reserved. Redistribution and use in source and binary forms, with or without From adf44ab203ae0e5cb869671b638dcbe1ec414fe8 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 5 May 2019 04:52:33 +0200 Subject: [PATCH 14/14] test: remove unnecessary semicolon from test-tree --- test/test-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-tree.c b/test/test-tree.c index 1b8682d..a2cd956 100644 --- a/test/test-tree.c +++ b/test/test-tree.c @@ -78,7 +78,7 @@ static void keys_random(tree_t* tree, test_op_t op) { key = keys[index]; keys[index] = keys[left]; op(tree, key); - }; + } } static void add(tree_t* tree, uintptr_t key) {