[PATCH 0/7] MR6911: ntdll: Add WaitCompletionPacket.
WaitCompletionPacket is a kernel object that, when associated with a target object and a completion object and when the target object is signaled, adds the completion information stored in itself to the completion object. For React Native. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/ntdll/tests/om.c | 5 ++++- include/winternl.h | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index df62bffe2c7..8f38b3eecd7 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -2329,6 +2329,7 @@ static void test_object_types(void) TYPE( L"Token", TOKEN, SYNCHRONIZE, 0 ), TYPE( L"Type", TYPE, SYNCHRONIZE, 0 ), TYPE( L"UserApcReserve", USER_APC_RESERVE, 0, 0 ), + TYPE( L"WaitCompletionPacket", WAIT_COMPLETION_PACKET, SYNCHRONIZE, 1), TYPE( L"WindowStation", WINSTA, 0, 0 ), #undef TYPE }; @@ -2390,7 +2391,9 @@ static void test_object_types(void) break; } - ok( j < ARRAY_SIZE(all_types), "type %s not found\n", debugstr_w(tests[i].name) ); + todo_wine_if(!lstrcmpW(tests[i].name, L"WaitCompletionPacket")) + ok( broken(!lstrcmpW(tests[i].name, L"WaitCompletionPacket") && j == ARRAY_SIZE(all_types)) /* Win7 doesn't have WaitCompletionPacket */ + || j < ARRAY_SIZE(all_types), "type %s not found\n", debugstr_w(tests[i].name) ); } for (j = 0; j < ARRAY_SIZE(all_types); j++) { diff --git a/include/winternl.h b/include/winternl.h index 585349905f5..4926bd1bf82 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3690,6 +3690,12 @@ typedef struct _FILE_IO_COMPLETION_INFORMATION { IO_STATUS_BLOCK IoStatusBlock; } FILE_IO_COMPLETION_INFORMATION, *PFILE_IO_COMPLETION_INFORMATION; +#define WAIT_COMPLETION_PACKET_QUERY_STATE 0x0001 +#define WAIT_COMPLETION_PACKET_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE|WAIT_COMPLETION_PACKET_QUERY_STATE) +#define WAIT_COMPLETION_PACKET_GENERIC_READ (STANDARD_RIGHTS_READ|WAIT_COMPLETION_PACKET_QUERY_STATE) +#define WAIT_COMPLETION_PACKET_GENERIC_WRITE (STANDARD_RIGHTS_WRITE|WAIT_COMPLETION_PACKET_QUERY_STATE) +#define WAIT_COMPLETION_PACKET_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|WAIT_COMPLETION_PACKET_QUERY_STATE) + typedef enum _HARDERROR_RESPONSE_OPTION { OptionAbortRetryIgnore, OptionOk, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/ntdll/tests/file.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 02bdf67796d..7e006541cbd 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -55,6 +55,7 @@ static NTSTATUS (WINAPI *pNtAllocateReserveObject)( HANDLE *, const OBJECT_ATTRI static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG, ULONG, PLARGE_INTEGER ); static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG); +static NTSTATUS (WINAPI *pNtCreateWaitCompletionPacket)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI *pNtOpenFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG); static NTSTATUS (WINAPI *pNtDeleteFile)(POBJECT_ATTRIBUTES ObjectAttributes); static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent, @@ -6036,6 +6037,42 @@ static void test_set_io_completion_ex(void) CloseHandle(completion); } +static void test_create_wait_completion_packet(void) +{ + UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\test_create_waitcompletionpacket"); + HANDLE handle, handle2; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + + if (!pNtCreateWaitCompletionPacket) + { + todo_wine + win_skip("NtCreateWaitCompletionPacket is unavailable.\n"); + return; + } + + InitializeObjectAttributes(&attr, &name, 0, NULL, NULL); + + /* Parameter checks */ + status = pNtCreateWaitCompletionPacket(NULL, GENERIC_ALL, &attr); + ok(status == STATUS_ACCESS_VIOLATION, "Got unexpected status %#lx.\n", status); + + status = pNtCreateWaitCompletionPacket(&handle, 0, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + pNtClose(handle); + + status = pNtCreateWaitCompletionPacket(&handle, GENERIC_ALL, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + pNtClose(handle); + + status = pNtCreateWaitCompletionPacket(&handle, GENERIC_ALL, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + status = pNtCreateWaitCompletionPacket(&handle2, GENERIC_ALL, &attr); + ok(status == STATUS_OBJECT_NAME_COLLISION, "Got unexpected status %#lx.\n", status); + pNtClose(handle); +} + START_TEST(file) { HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); @@ -6056,6 +6093,7 @@ START_TEST(file) pNtAllocateReserveObject= (void *)GetProcAddress(hntdll, "NtAllocateReserveObject"); pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); pNtCreateFile = (void *)GetProcAddress(hntdll, "NtCreateFile"); + pNtCreateWaitCompletionPacket = (void *)GetProcAddress(hntdll, "NtCreateWaitCompletionPacket"); pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); pNtDeleteFile = (void *)GetProcAddress(hntdll, "NtDeleteFile"); pNtReadFile = (void *)GetProcAddress(hntdll, "NtReadFile"); @@ -6119,4 +6157,5 @@ START_TEST(file) test_flush_buffers_file(); test_mailslot_name(); test_reparse_points(); + test_create_wait_completion_packet(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/ntdll/tests/file.c | 486 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 486 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 7e006541cbd..a372bd170e1 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -52,6 +52,9 @@ static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRIN static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG, ULONG * ); static NTSTATUS (WINAPI *pNtAllocateReserveObject)( HANDLE *, const OBJECT_ATTRIBUTES *, MEMORY_RESERVE_OBJECT_TYPE ); +static NTSTATUS (WINAPI *pNtAssociateWaitCompletionPacket)(HANDLE, HANDLE, HANDLE, PVOID, PVOID, + NTSTATUS, ULONG_PTR, PBOOLEAN); +static NTSTATUS (WINAPI *pNtCreateEvent)(PHANDLE, ACCESS_MASK, const OBJECT_ATTRIBUTES *, EVENT_TYPE, BOOLEAN); static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG, ULONG, PLARGE_INTEGER ); static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG); @@ -74,6 +77,7 @@ static NTSTATUS (WINAPI *pNtFsControlFile) (HANDLE handle, HANDLE event, PIO_APC static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); static NTSTATUS (WINAPI *pNtOpenIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); +static NTSTATUS (WINAPI *pNtPulseEvent)(HANDLE, LONG *); static NTSTATUS (WINAPI *pNtQueryIoCompletion)(HANDLE, IO_COMPLETION_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER); static NTSTATUS (WINAPI *pNtRemoveIoCompletionEx)(HANDLE,FILE_IO_COMPLETION_INFORMATION*,ULONG,ULONG*,LARGE_INTEGER*,BOOLEAN); @@ -6073,6 +6077,484 @@ static void test_create_wait_completion_packet(void) pNtClose(handle); } +static void test_associate_wait_completion_packet(void) +{ + static const char pipe_name[] = "\\\\.\\pipe\\test_associate_wait_completion_packet"; + UNICODE_STRING packet_name = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\test_associate_wait_completion_packet"); + UNICODE_STRING packet_name2 = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\test_associate_wait_completion_packet2"); + BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN]; + HANDLE completion, packet, packet2, server, client; + FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info; + ULONG_PTR key_context, apc_context; + DWORD read_bytes, written_bytes; + FILE_COMPLETION_INFORMATION fci; + LARGE_INTEGER timeout = {{0}}; + OVERLAPPED overlapped = {0}; + OBJECT_ATTRIBUTES attr; + ULONG completion_count; + IO_STATUS_BLOCK iosb; + BOOLEAN signaled; + NTSTATUS status; + HANDLE event; + + if (!pNtAssociateWaitCompletionPacket) + { + todo_wine + win_skip("NtAssociateWaitCompletionPacket is unavailable.\n"); + return; + } + + status = pNtCreateIoCompletion(&completion, IO_COMPLETION_ALL_ACCESS, NULL, 0); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + server = CreateNamedPipeA(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, + 1000, NULL); + ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed, error %lu.\n", GetLastError()); + client = CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); + ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu.\n", GetLastError()); + + /* Test normal NtAssociateWaitCompletionPacket() calls */ + InitializeObjectAttributes(&attr, &packet_name, 0, NULL, NULL); + status = pNtCreateWaitCompletionPacket(&packet, GENERIC_ALL, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + /* ReadFile() should be called before NtAssociateWaitCompletionPacket(). Otherwise, the server + * object stays signaled */ + memset(send_buf, 0xa1, TEST_BUF_LEN); + memset(recv_buf, 0xb2, TEST_BUF_LEN); + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)1, (void *)2, + STATUS_SUCCESS, (ULONG_PTR)3, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + /* Associating an already associated wait completion packet */ + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)1, (void *)2, + STATUS_SUCCESS, (ULONG_PTR)3, &signaled); + ok(status == STATUS_INVALID_PARAMETER_1, "Got unexpected status %#lx.\n", status); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Got unexpected completion count %ld.\n", completion_count); + + /* Associating an already queued wait completion packet */ + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)1, (void *)2, + STATUS_SUCCESS, (ULONG_PTR)3, &signaled); + ok(status == STATUS_INVALID_PARAMETER_1, "Got unexpected status %#lx.\n", status); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 1, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 2, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 3, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) did not match send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == WAIT_TIMEOUT, "Got unexpected status %#lx.\n", status); + + /* Associating an already removed wait completion packet */ + memset(send_buf, 0xa2, TEST_BUF_LEN); + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)4, (void *)5, + STATUS_SUCCESS, (ULONG_PTR)6, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 4, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 5, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 6, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) did not match send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* Test associating wait completion packet before setting I/O completion */ + memset(send_buf, 0xa3, TEST_BUF_LEN); + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)7, (void *)8, + STATUS_SUCCESS, (ULONG_PTR)9, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + fci.CompletionPort = completion; + fci.CompletionKey = CKEY_FIRST; + iosb.Status = 0xdeadbeef; + status = pNtSetInformationFile(server, &iosb, &fci, sizeof(fci), FileCompletionInformation); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx.\n", iosb.Status); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Unexpected completion count %ld.\n", completion_count); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(completion_count == 2, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 7, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 8, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 9, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) matched send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == CKEY_FIRST, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == (ULONG_PTR)&overlapped, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == TEST_BUF_LEN, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) did not match send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* Test associating wait completion packet after setting I/O completion for the same file */ + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + signaled = FALSE; + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)10, (void *)11, + STATUS_SUCCESS, (ULONG_PTR)12, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == CKEY_FIRST, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == (ULONG_PTR)&overlapped, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == TEST_BUF_LEN, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) did not match send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 10, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 11, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 12, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) matched send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* Test associating wait completion packet after setting I/O completion for a new file */ + status = pNtClose(client); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(server); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + server = CreateNamedPipeA(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, + 1000, NULL); + ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed, error %lu.\n", GetLastError()); + client = CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); + ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu.\n", GetLastError()); + + memset(send_buf, 0xa4, TEST_BUF_LEN); + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + fci.CompletionPort = completion; + fci.CompletionKey = CKEY_SECOND; + iosb.Status = 0xdeadbeef; + status = pNtSetInformationFile(server, &iosb, &fci, sizeof(fci), FileCompletionInformation); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx.\n", iosb.Status); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + signaled = FALSE; + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)13, (void *)14, + STATUS_SUCCESS, (ULONG_PTR)15, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == TRUE, "Got unexpected signaled %d.\n", signaled); + + /* Notice the wait completion packet gets added immediately when there is a completion set, even + * without writing to the file */ + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 13, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 14, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 15, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) matched send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == CKEY_SECOND, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == (ULONG_PTR)&overlapped, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == TEST_BUF_LEN, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) did not match send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* Test file with FILE_SKIP_SET_EVENT_ON_HANDLE set */ + status = pNtClose(client); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(server); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + server = CreateNamedPipeA(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, + 1000, NULL); + ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed, error %lu.\n", GetLastError()); + client = CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); + ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu.\n", GetLastError()); + + info.Flags = FILE_SKIP_SET_EVENT_ON_HANDLE; + status = pNtSetInformationFile(server, &iosb, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08lx\n", status); + ok(!is_signaled(server), "Expected server not signaled\n"); + + memset(send_buf, 0xa4, TEST_BUF_LEN); + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + signaled = FALSE; + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)16, (void *)17, + STATUS_SUCCESS, (ULONG_PTR)18, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* Test associating two wait completion packets */ + status = pNtClose(packet); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(client); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(server); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + server = CreateNamedPipeA(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, + 1000, NULL); + ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed, error %lu.\n", GetLastError()); + client = CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); + ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu.\n", GetLastError()); + status = pNtCreateWaitCompletionPacket(&packet, GENERIC_ALL, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + InitializeObjectAttributes(&attr, &packet_name2, 0, NULL, NULL); + status = pNtCreateWaitCompletionPacket(&packet2, GENERIC_ALL, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + memset(send_buf, 0xa5, TEST_BUF_LEN); + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)19, (void *)20, + STATUS_SUCCESS, (ULONG_PTR)21, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + status = pNtAssociateWaitCompletionPacket(packet2, completion, server, (void *)22, (void *)23, + STATUS_SUCCESS, (ULONG_PTR)24, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(completion_count == 2, "Unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 19, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 20, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 21, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + ok(!memcmp(send_buf, recv_buf, TEST_BUF_LEN), + "Receive buffer (%02x %02x %02x) did not match send buffer (%02x %02x %02x)\n", recv_buf[0], + recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2]); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 22, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 23, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 24, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* Test associating non-file objects */ + status = pNtCreateEvent(&event, GENERIC_ALL, NULL, NotificationEvent, 0); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(packet, completion, event, (void *)25, (void *)26, + STATUS_SUCCESS, (ULONG_PTR)27, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtPulseEvent(event, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 25, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 26, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 27, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == STATUS_SUCCESS, "Got unexpected iosb.Status %#lx\n", iosb.Status); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* Test closing wait completion packets before the target object is signaled */ + status = pNtAssociateWaitCompletionPacket(packet, completion, event, (void *)28, (void *)29, + STATUS_SUCCESS, (ULONG_PTR)30, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtClose(packet); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + status = pNtPulseEvent(event, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + /* Test closing wait completion packets right after the target object is signaled */ + InitializeObjectAttributes(&attr, &packet_name, 0, NULL, NULL); + status = pNtCreateWaitCompletionPacket(&packet, GENERIC_ALL, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(packet, completion, event, (void *)31, (void *)32, + STATUS_SUCCESS, (ULONG_PTR)33, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtPulseEvent(event, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtClose(packet); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + /* Parameter checks */ + InitializeObjectAttributes(&attr, &packet_name, 0, NULL, NULL); + status = pNtCreateWaitCompletionPacket(&packet, GENERIC_ALL, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(NULL, completion, server, (void *)0xa, (void *)0xb, + STATUS_SUCCESS, (ULONG_PTR)0xc, &signaled); + ok(status == STATUS_INVALID_HANDLE, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(INVALID_HANDLE_VALUE, completion, server, (void *)0xa, + (void *)0xb, STATUS_SUCCESS, (ULONG_PTR)0xc, &signaled); + ok(status == STATUS_OBJECT_TYPE_MISMATCH, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(packet, NULL, server, (void *)0xa, (void *)0xb, + STATUS_SUCCESS, (ULONG_PTR)0xc, &signaled); + ok(status == STATUS_INVALID_HANDLE, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(packet, INVALID_HANDLE_VALUE, server, (void *)0xa, + (void *)0xb, STATUS_SUCCESS, (ULONG_PTR)0xc, &signaled); + ok(status == STATUS_OBJECT_TYPE_MISMATCH, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(packet, completion, NULL, (void *)0xa, (void *)0xb, + STATUS_SUCCESS, (ULONG_PTR)0xc, &signaled); + ok(status == STATUS_INVALID_HANDLE, "Got unexpected status %#lx.\n", status); + + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)0xa, (void *)0xb, + 0xdeadbeef, (ULONG_PTR)0xc, NULL); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(key_context == 0xa, "Got unexpected completion key %Id\n", key_context); + ok(apc_context == 0xb, "Got unexpected completion value %Id\n", apc_context); + ok(iosb.Information == 0xc, "Got unexpected iosb.Information %Id\n", iosb.Information); + ok(iosb.Status == 0xdeadbeef, "Got unexpected iosb.Status %#lx\n", iosb.Status); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Unexpected completion count %ld.\n", completion_count); + + /* This test associates the wait completion packet with INVALID_HANDLE_VALUE, which will never + * be signaled */ + status = pNtAssociateWaitCompletionPacket(packet, completion, INVALID_HANDLE_VALUE, (void *)0xa, + (void *)0xb, STATUS_SUCCESS, (ULONG_PTR)0xc, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + status = pNtRemoveIoCompletion(completion, &key_context, &apc_context, &iosb, &timeout); + ok(status == WAIT_TIMEOUT, "Got unexpected status %#lx.\n", status); + + status = pNtClose(event); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(packet2); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(packet); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(client); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(server); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(completion); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); +} + START_TEST(file) { HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); @@ -6091,6 +6573,8 @@ START_TEST(file) pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll, "RtlWow64EnableFsRedirectionEx"); pNtAllocateReserveObject= (void *)GetProcAddress(hntdll, "NtAllocateReserveObject"); + pNtAssociateWaitCompletionPacket = (void *)GetProcAddress(hntdll, "NtAssociateWaitCompletionPacket"); + pNtCreateEvent = (void *)GetProcAddress(hntdll, "NtCreateEvent"); pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); pNtCreateFile = (void *)GetProcAddress(hntdll, "NtCreateFile"); pNtCreateWaitCompletionPacket = (void *)GetProcAddress(hntdll, "NtCreateWaitCompletionPacket"); @@ -6104,6 +6588,7 @@ START_TEST(file) pNtFsControlFile = (void *)GetProcAddress(hntdll, "NtFsControlFile"); pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); + pNtPulseEvent = (void *)GetProcAddress(hntdll, "NtPulseEvent"); pNtQueryIoCompletion = (void *)GetProcAddress(hntdll, "NtQueryIoCompletion"); pNtRemoveIoCompletion = (void *)GetProcAddress(hntdll, "NtRemoveIoCompletion"); pNtRemoveIoCompletionEx = (void *)GetProcAddress(hntdll, "NtRemoveIoCompletionEx"); @@ -6158,4 +6643,5 @@ START_TEST(file) test_mailslot_name(); test_reparse_points(); test_create_wait_completion_packet(); + test_associate_wait_completion_packet(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/ntdll/tests/file.c | 108 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index a372bd170e1..4a308f3e577 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -54,6 +54,7 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG, ULONG * ); static NTSTATUS (WINAPI *pNtAllocateReserveObject)( HANDLE *, const OBJECT_ATTRIBUTES *, MEMORY_RESERVE_OBJECT_TYPE ); static NTSTATUS (WINAPI *pNtAssociateWaitCompletionPacket)(HANDLE, HANDLE, HANDLE, PVOID, PVOID, NTSTATUS, ULONG_PTR, PBOOLEAN); +static NTSTATUS (WINAPI *pNtCancelWaitCompletionPacket)(HANDLE, BOOLEAN); static NTSTATUS (WINAPI *pNtCreateEvent)(PHANDLE, ACCESS_MASK, const OBJECT_ATTRIBUTES *, EVENT_TYPE, BOOLEAN); static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG, ULONG, PLARGE_INTEGER ); @@ -6555,6 +6556,111 @@ static void test_associate_wait_completion_packet(void) ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); } +static void test_cancel_wait_completion_packet(void) +{ + static const char pipe_name[] = "\\\\.\\pipe\\test_cancel_wait_completion_packet"; + UNICODE_STRING packet_name = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\test_cancel_wait_completion_packet"); + BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN]; + HANDLE completion, packet, server, client; + DWORD read_bytes, written_bytes; + OVERLAPPED overlapped = {0}; + OBJECT_ATTRIBUTES attr; + ULONG completion_count; + BOOLEAN signaled; + NTSTATUS status; + + if (!pNtCancelWaitCompletionPacket) + { + todo_wine + win_skip("NtCancelWaitCompletionPacket is unavailable.\n"); + return; + } + + status = pNtCreateIoCompletion(&completion, IO_COMPLETION_ALL_ACCESS, NULL, 0); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + server = CreateNamedPipeA(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, + 1000, NULL); + ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed, error %lu.\n", GetLastError()); + client = CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); + ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu.\n", GetLastError()); + + InitializeObjectAttributes(&attr, &packet_name, 0, NULL, NULL); + status = pNtCreateWaitCompletionPacket(&packet, GENERIC_ALL, &attr); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + /* Remove not associated packets */ + status = pNtCancelWaitCompletionPacket(packet, TRUE); + ok(status == STATUS_CANCELLED, "Got unexpected status %#lx.\n", status); + + /* ReadFile() should be called before NtAssociateWaitCompletionPacket(). Otherwise, the server + * object stays signaled */ + memset(send_buf, 0xa1, TEST_BUF_LEN); + memset(recv_buf, 0xb2, TEST_BUF_LEN); + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + /* Cancel non-signaled packets */ + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)1, (void *)2, + STATUS_SUCCESS, (ULONG_PTR)3, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtCancelWaitCompletionPacket(packet, FALSE); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + /* Cancel signaled packets */ + ReadFile(server, recv_buf, TEST_BUF_LEN, &read_bytes, &overlapped); + + status = pNtAssociateWaitCompletionPacket(packet, completion, server, (void *)1, (void *)2, + STATUS_SUCCESS, (ULONG_PTR)3, &signaled); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + ok(signaled == FALSE, "Got unexpected signaled %d.\n", signaled); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + WriteFile(client, send_buf, TEST_BUF_LEN, &written_bytes, NULL); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtCancelWaitCompletionPacket(packet, FALSE); + ok(status == STATUS_PENDING, "Got unexpected status %#lx.\n", status); + completion_count = get_pending_msgs(completion); + ok(completion_count == 1, "Got unexpected completion count %ld.\n", completion_count); + + status = pNtCancelWaitCompletionPacket(packet, TRUE); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + completion_count = get_pending_msgs(completion); + ok(!completion_count, "Got unexpected completion count %ld.\n", completion_count); + + /* Remove already removed packets */ + status = pNtCancelWaitCompletionPacket(packet, TRUE); + ok(status == STATUS_CANCELLED, "Got unexpected status %#lx.\n", status); + + /* Parameter checks */ + status = pNtCancelWaitCompletionPacket(NULL, FALSE); + ok(status == STATUS_INVALID_HANDLE, "Got unexpected status %#lx.\n", status); + + status = pNtCancelWaitCompletionPacket(INVALID_HANDLE_VALUE, FALSE); + ok(status == STATUS_OBJECT_TYPE_MISMATCH, "Got unexpected status %#lx.\n", status); + + status = pNtClose(packet); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(client); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(server); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); + status = pNtClose(completion); + ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status); +} + START_TEST(file) { HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); @@ -6574,6 +6680,7 @@ START_TEST(file) pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll, "RtlWow64EnableFsRedirectionEx"); pNtAllocateReserveObject= (void *)GetProcAddress(hntdll, "NtAllocateReserveObject"); pNtAssociateWaitCompletionPacket = (void *)GetProcAddress(hntdll, "NtAssociateWaitCompletionPacket"); + pNtCancelWaitCompletionPacket = (void *)GetProcAddress(hntdll, "NtCancelWaitCompletionPacket"); pNtCreateEvent = (void *)GetProcAddress(hntdll, "NtCreateEvent"); pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); pNtCreateFile = (void *)GetProcAddress(hntdll, "NtCreateFile"); @@ -6644,4 +6751,5 @@ START_TEST(file) test_reparse_points(); test_create_wait_completion_packet(); test_associate_wait_completion_packet(); + test_cancel_wait_completion_packet(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/signal_arm64ec.c | 1 + dlls/ntdll/tests/om.c | 1 - dlls/ntdll/unix/sync.c | 24 ++++++++++++ dlls/wow64/sync.c | 20 ++++++++++ include/winternl.h | 1 + server/completion.c | 75 +++++++++++++++++++++++++++++++++++++ server/directory.c | 1 + server/file.h | 5 +++ server/object.h | 1 + server/protocol.def | 9 +++++ 11 files changed, 138 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 3bb20691208..e529bd623c8 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -199,6 +199,7 @@ @ stdcall -syscall NtCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall -syscall NtCreateTransaction(ptr long ptr ptr long long long long ptr ptr) @ stdcall -syscall NtCreateUserProcess(ptr ptr long long ptr ptr long long ptr ptr ptr) +@ stdcall -syscall NtCreateWaitCompletionPacket(ptr long ptr) # @ stub NtCreateWaitablePort @ stdcall -arch=i386 NtCurrentTeb() @ stdcall -syscall NtDebugActiveProcess(long long) diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index a2811c91af5..00195b41e88 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -294,6 +294,7 @@ DEFINE_SYSCALL(NtCreateThreadEx, (HANDLE *handle, ACCESS_MASK access, OBJECT_ATT DEFINE_SYSCALL(NtCreateTimer, (HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, TIMER_TYPE type)) DEFINE_SYSCALL(NtCreateToken, (HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, TOKEN_TYPE type, LUID *token_id, LARGE_INTEGER *expire, TOKEN_USER *user, TOKEN_GROUPS *groups, TOKEN_PRIVILEGES *privs, TOKEN_OWNER *owner, TOKEN_PRIMARY_GROUP *group, TOKEN_DEFAULT_DACL *dacl, TOKEN_SOURCE *source)) DEFINE_SYSCALL(NtCreateTransaction, (HANDLE *handle, ACCESS_MASK mask, OBJECT_ATTRIBUTES *obj_attr, GUID *guid, HANDLE tm, ULONG options, ULONG isol_level, ULONG isol_flags, PLARGE_INTEGER timeout, UNICODE_STRING *description)) +DEFINE_SYSCALL(NtCreateWaitCompletionPacket, (HANDLE *handle, ACCESS_MASK mask, OBJECT_ATTRIBUTES *obj_attr)) DEFINE_SYSCALL(NtCreateUserProcess, (HANDLE *process_handle_ptr, HANDLE *thread_handle_ptr, ACCESS_MASK process_access, ACCESS_MASK thread_access, OBJECT_ATTRIBUTES *process_attr, OBJECT_ATTRIBUTES *thread_attr, ULONG process_flags, ULONG thread_flags, RTL_USER_PROCESS_PARAMETERS *params, PS_CREATE_INFO *info, PS_ATTRIBUTE_LIST *ps_attr)) DEFINE_SYSCALL(NtDebugActiveProcess, (HANDLE process, HANDLE debug)) DEFINE_SYSCALL(NtDebugContinue, (HANDLE handle, CLIENT_ID *client, NTSTATUS status)) diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 8f38b3eecd7..55c838d066d 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -2391,7 +2391,6 @@ static void test_object_types(void) break; } - todo_wine_if(!lstrcmpW(tests[i].name, L"WaitCompletionPacket")) ok( broken(!lstrcmpW(tests[i].name, L"WaitCompletionPacket") && j == ARRAY_SIZE(all_types)) /* Win7 doesn't have WaitCompletionPacket */ || j < ARRAY_SIZE(all_types), "type %s not found\n", debugstr_w(tests[i].name) ); } diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index d486b50001d..b9b883205d8 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2794,6 +2794,30 @@ NTSTATUS WINAPI NtCreateTransaction( HANDLE *handle, ACCESS_MASK mask, OBJECT_AT return STATUS_SUCCESS; } +/*********************************************************************** + * NtCreateWaitCompletionPacket (NTDLL.@) + */ +NTSTATUS WINAPI NtCreateWaitCompletionPacket( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) +{ + struct object_attributes *objattr; + unsigned int ret; + data_size_t len; + + *handle = 0; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + SERVER_START_REQ( create_wait_completion_packet ) + { + req->access = access; + wine_server_add_data( req, objattr, len ); + if (!(ret = wine_server_call( req ))) + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + free( objattr ); + return ret; +} + /*********************************************************************** * NtCommitTransaction (NTDLL.@) */ diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index 54dca19dc1a..2f516b8f40c 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -1781,6 +1781,26 @@ NTSTATUS WINAPI wow64_NtCreateTransaction( UINT *args ) return status; } +/********************************************************************** + * wow64_NtCreateWaitCompletionPacket + */ +NTSTATUS WINAPI wow64_NtCreateWaitCompletionPacket( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + ACCESS_MASK access = get_ulong( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + + struct object_attr64 attr; + HANDLE handle = 0; + NTSTATUS status; + + *handle_ptr = 0; + status = NtCreateWaitCompletionPacket( &handle, access, objattr_32to64( &attr, attr32 )); + put_handle( handle_ptr, handle ); + + return status; +} + /********************************************************************** * wow64_NtCommitTransaction diff --git a/include/winternl.h b/include/winternl.h index 4926bd1bf82..aa2427b0f6a 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4528,6 +4528,7 @@ NTSYSAPI NTSTATUS WINAPI NtCreateThreadEx(HANDLE*,ACCESS_MASK,OBJECT_ATTRIBUTES NTSYSAPI NTSTATUS WINAPI NtCreateTimer(HANDLE*, ACCESS_MASK, const OBJECT_ATTRIBUTES*, TIMER_TYPE); NTSYSAPI NTSTATUS WINAPI NtCreateToken(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,TOKEN_TYPE,PLUID,PLARGE_INTEGER,PTOKEN_USER,PTOKEN_GROUPS,PTOKEN_PRIVILEGES,PTOKEN_OWNER,PTOKEN_PRIMARY_GROUP,PTOKEN_DEFAULT_DACL,PTOKEN_SOURCE); NTSYSAPI NTSTATUS WINAPI NtCreateTransaction(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,LPGUID,HANDLE,ULONG,ULONG,ULONG,PLARGE_INTEGER,PUNICODE_STRING); +NTSYSAPI NTSTATUS WINAPI NtCreateWaitCompletionPacket(HANDLE *,ACCESS_MASK,OBJECT_ATTRIBUTES *); NTSYSAPI NTSTATUS WINAPI NtCreateUserProcess(HANDLE*,HANDLE*,ACCESS_MASK,ACCESS_MASK,OBJECT_ATTRIBUTES*,OBJECT_ATTRIBUTES*,ULONG,ULONG,RTL_USER_PROCESS_PARAMETERS*,PS_CREATE_INFO*,PS_ATTRIBUTE_LIST*); NTSYSAPI NTSTATUS WINAPI NtDebugActiveProcess(HANDLE,HANDLE); NTSYSAPI NTSTATUS WINAPI NtDebugContinue(HANDLE,CLIENT_ID*,NTSTATUS); diff --git a/server/completion.c b/server/completion.c index f4fad9dbeca..9edc3d0e041 100644 --- a/server/completion.c +++ b/server/completion.c @@ -36,6 +36,61 @@ #include "handle.h" #include "request.h" +static const WCHAR wait_completion_packet_name[] = {'W','a','i','t','C','o','m','p','l','e','t','i','o','n','P','a','c','k','e','t'}; + +struct type_descr wait_completion_packet_type = +{ + { wait_completion_packet_name, sizeof(wait_completion_packet_name) }, /* name */ + WAIT_COMPLETION_PACKET_ALL_ACCESS, /* valid_access */ + { /* mapping */ + WAIT_COMPLETION_PACKET_GENERIC_READ, + WAIT_COMPLETION_PACKET_GENERIC_WRITE, + WAIT_COMPLETION_PACKET_GENERIC_EXECUTE, + WAIT_COMPLETION_PACKET_ALL_ACCESS + }, +}; + +static void wait_completion_packet_dump( struct object *, int ); + +static const struct object_ops wait_completion_packet_ops = +{ + sizeof(struct wait_completion_packet), /* size */ + &wait_completion_packet_type, /* type */ + wait_completion_packet_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + +static void wait_completion_packet_dump( struct object *obj, int verbose ) +{ + struct wait_completion_packet *packet = (struct wait_completion_packet *)obj; + + assert( obj->ops == &wait_completion_packet_ops ); + fprintf( stderr, "WaitCompletionPacket\n" ); +} + +static struct wait_completion_packet *create_wait_completion_packet( struct object *root, + const struct unicode_str *name, + unsigned int attr, + const struct security_descriptor *sd ) +{ + return create_named_object( root, &wait_completion_packet_ops, name, attr, sd ); +} static const WCHAR completion_name[] = {'I','o','C','o','m','p','l','e','t','i','o','n'}; @@ -310,6 +365,26 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ if (!list_empty( &completion->queue )) wake_up( &completion->obj, 0 ); } +/* create a wait completion packet */ +DECL_HANDLER(create_wait_completion_packet) +{ + struct wait_completion_packet *packet; + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + + if (!objattr) return; + if ((packet = create_wait_completion_packet( root, &name, objattr->attributes, sd )) + && get_error() != STATUS_OBJECT_NAME_EXISTS) + { + reply->handle = alloc_handle( current->process, packet, req->access, objattr->attributes ); + release_object( packet ); + } + + if (root) release_object( root ); +} + /* create a completion */ DECL_HANDLER(create_completion) { diff --git a/server/directory.c b/server/directory.c index b37ec969a9e..cbf53b12f3b 100644 --- a/server/directory.c +++ b/server/directory.c @@ -163,6 +163,7 @@ static struct type_descr *types[] = &key_type, &apc_reserve_type, &completion_reserve_type, + &wait_completion_packet_type, }; static void object_type_dump( struct object *obj, int verbose ) diff --git a/server/file.h b/server/file.h index 4f5fc7b26f1..5e988376e55 100644 --- a/server/file.h +++ b/server/file.h @@ -48,6 +48,11 @@ struct async_queue struct list queue; /* queue of async objects */ }; +struct wait_completion_packet +{ + struct object obj; /* object header */ +}; + /* operations valid on file descriptor objects */ struct fd_ops { diff --git a/server/object.h b/server/object.h index 7555f564a08..e02dbdc6b71 100644 --- a/server/object.h +++ b/server/object.h @@ -333,6 +333,7 @@ extern struct type_descr mapping_type; extern struct type_descr key_type; extern struct type_descr apc_reserve_type; extern struct type_descr completion_reserve_type; +extern struct type_descr wait_completion_packet_type; #define KEYEDEVENT_WAIT 0x0001 #define KEYEDEVENT_WAKE 0x0002 diff --git a/server/protocol.def b/server/protocol.def index bd0307c5d79..5f9431d9517 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3849,6 +3849,15 @@ struct handle_info @END +/* create a wait completion packet */ +(a)REQ(create_wait_completion_packet) + unsigned int access; /* desired access */ + VARARG(objattr,object_attributes); /* object attributes */ +(a)REPLY + obj_handle_t handle; /* wait completion packet handle */ +(a)END + + /* check for associated completion and push msg */ @REQ(add_fd_completion) obj_handle_t handle; /* async' object */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/signal_arm64ec.c | 1 + dlls/ntdll/tests/file.c | 1 - dlls/ntdll/unix/sync.c | 28 +++++++ dlls/wow64/sync.c | 20 +++++ include/winternl.h | 1 + server/async.c | 2 +- server/completion.c | 162 +++++++++++++++++++++++++++++++----- server/fd.c | 2 +- server/file.h | 12 ++- server/object.c | 1 + server/object.h | 1 + server/process.c | 2 +- server/protocol.def | 14 ++++ server/thread.c | 32 +++++++ server/thread.h | 1 + 16 files changed, 253 insertions(+), 28 deletions(-) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index e529bd623c8..2085be4aaf7 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -152,6 +152,7 @@ @ stdcall -syscall NtAllocateVirtualMemoryEx(long ptr ptr long long ptr long) @ stdcall -syscall NtAreMappedFilesTheSame(ptr ptr) @ stdcall -syscall NtAssignProcessToJobObject(long long) +@ stdcall -syscall NtAssociateWaitCompletionPacket(ptr ptr ptr ptr ptr long ptr ptr) @ stdcall -syscall NtCallbackReturn(ptr long long) # @ stub NtCancelDeviceWakeupRequest @ stdcall -syscall NtCancelIoFile(long ptr) diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 00195b41e88..c33757b7ec0 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -257,6 +257,7 @@ DEFINE_WRAPPED_SYSCALL(NtAllocateVirtualMemory, (HANDLE process, PVOID *ret, ULO DEFINE_WRAPPED_SYSCALL(NtAllocateVirtualMemoryEx, (HANDLE process, PVOID *ret, SIZE_T *size_ptr, ULONG type, ULONG protect, MEM_EXTENDED_PARAMETER *parameters, ULONG count)) DEFINE_SYSCALL(NtAreMappedFilesTheSame, (PVOID addr1, PVOID addr2)) DEFINE_SYSCALL(NtAssignProcessToJobObject, (HANDLE job, HANDLE process)) +DEFINE_SYSCALL(NtAssociateWaitCompletionPacket,(HANDLE packet, HANDLE completion, HANDLE target, void *key_context, void *apc_context, NTSTATUS io_status, ULONG_PTR io_status_information, BOOLEAN *already_signaled)) DEFINE_SYSCALL(NtCallbackReturn, (void *ret_ptr, ULONG ret_len, NTSTATUS status)) DEFINE_SYSCALL(NtCancelIoFile, (HANDLE handle, IO_STATUS_BLOCK *io_status)) DEFINE_SYSCALL(NtCancelIoFileEx, (HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status)) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 4a308f3e577..056167b7309 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6100,7 +6100,6 @@ static void test_associate_wait_completion_packet(void) if (!pNtAssociateWaitCompletionPacket) { - todo_wine win_skip("NtAssociateWaitCompletionPacket is unavailable.\n"); return; } diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index b9b883205d8..16337a64daa 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2794,6 +2794,34 @@ NTSTATUS WINAPI NtCreateTransaction( HANDLE *handle, ACCESS_MASK mask, OBJECT_AT return STATUS_SUCCESS; } +/*********************************************************************** + * NtAssociateWaitCompletionPacket (NTDLL.@) + */ +NTSTATUS WINAPI NtAssociateWaitCompletionPacket( HANDLE packet, HANDLE completion, HANDLE target, + void *key_context, void *apc_context, NTSTATUS status, ULONG_PTR information, + BOOLEAN *already_signaled ) +{ + NTSTATUS ret; + + TRACE( "%p, %p, %p, %p, %p, %#x, %ld, %p stub.\n", packet, completion, target, key_context, + apc_context, (int)status, information, already_signaled ); + + SERVER_START_REQ( associate_wait_completion_packet ) + { + req->packet = wine_server_obj_handle( packet ); + req->completion = wine_server_obj_handle( completion ); + req->target = wine_server_obj_handle( target ); + req->ckey = wine_server_client_ptr( key_context ); + req->cvalue = wine_server_client_ptr( apc_context ); + req->information = information; + req->status = status; + if (!(ret = wine_server_call( req )) && already_signaled) + *already_signaled = reply->signaled; + } + SERVER_END_REQ; + return ret; +} + /*********************************************************************** * NtCreateWaitCompletionPacket (NTDLL.@) */ diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index 2f516b8f40c..d9bea95fd5e 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -1781,6 +1781,26 @@ NTSTATUS WINAPI wow64_NtCreateTransaction( UINT *args ) return status; } + +/********************************************************************** + * wow64_NtAssociateWaitCompletionPacket + */ +NTSTATUS WINAPI wow64_NtAssociateWaitCompletionPacket( UINT *args ) +{ + HANDLE packet = get_handle( &args ); + HANDLE completion = get_handle( &args ); + HANDLE target = get_handle( &args ); + void *key_context = get_ptr( &args ); + void *apc_context = get_ptr( &args ); + LONG io_status = get_ulong( &args ); + ULONG_PTR io_status_information = get_ulong( &args ); + BOOLEAN *already_signaled = get_ptr( &args ); + + return NtAssociateWaitCompletionPacket( packet, completion, target, key_context, apc_context, + io_status, io_status_information, already_signaled ); +} + + /********************************************************************** * wow64_NtCreateWaitCompletionPacket */ diff --git a/include/winternl.h b/include/winternl.h index aa2427b0f6a..6105cef9528 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4487,6 +4487,7 @@ NTSYSAPI NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE,PVOID*,ULONG_PTR,SIZE_T NTSYSAPI NTSTATUS WINAPI NtAllocateVirtualMemoryEx(HANDLE,PVOID*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG); NTSYSAPI NTSTATUS WINAPI NtAreMappedFilesTheSame(PVOID,PVOID); NTSYSAPI NTSTATUS WINAPI NtAssignProcessToJobObject(HANDLE,HANDLE); +NTSYSAPI NTSTATUS WINAPI NtAssociateWaitCompletionPacket(HANDLE,HANDLE,HANDLE,void *,void *,NTSTATUS,ULONG_PTR,BOOLEAN *); NTSYSAPI NTSTATUS WINAPI NtCallbackReturn(PVOID,ULONG,NTSTATUS); NTSYSAPI NTSTATUS WINAPI NtCancelIoFile(HANDLE,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelIoFileEx(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK); diff --git a/server/async.c b/server/async.c index d2d929c9709..67f7e6f47c9 100644 --- a/server/async.c +++ b/server/async.c @@ -481,7 +481,7 @@ static void add_async_completion( struct async *async, apc_param_t cvalue, unsig apc_param_t information ) { if (async->fd && !async->completion) async->completion = fd_get_completion( async->fd, &async->comp_key ); - if (async->completion) add_completion( async->completion, async->comp_key, cvalue, status, information ); + if (async->completion) add_completion( async->completion, async->comp_key, cvalue, status, information, NULL ); } /* store the result of the client-side async callback */ diff --git a/server/completion.c b/server/completion.c index 9edc3d0e041..0c5b98851a9 100644 --- a/server/completion.c +++ b/server/completion.c @@ -36,6 +36,25 @@ #include "handle.h" #include "request.h" +struct comp_msg +{ + struct wait_completion_packet *packet; /* if this is from a wait completion packet, store its pointer here */ + struct list queue_entry; + apc_param_t ckey; + apc_param_t cvalue; + apc_param_t information; + unsigned int status; +}; + +struct completion +{ + struct object obj; + struct list queue; + struct list wait_queue; + unsigned int depth; + int closed; +}; + static const WCHAR wait_completion_packet_name[] = {'W','a','i','t','C','o','m','p','l','e','t','i','o','n','P','a','c','k','e','t'}; struct type_descr wait_completion_packet_type = @@ -51,6 +70,7 @@ struct type_descr wait_completion_packet_type = }; static void wait_completion_packet_dump( struct object *, int ); +static void wait_completion_packet_destroy( struct object * ); static const struct object_ops wait_completion_packet_ops = { @@ -73,7 +93,7 @@ static const struct object_ops wait_completion_packet_ops = no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ no_close_handle, /* close_handle */ - no_destroy /* destroy */ + wait_completion_packet_destroy /* destroy */ }; static void wait_completion_packet_dump( struct object *obj, int verbose ) @@ -81,7 +101,16 @@ static void wait_completion_packet_dump( struct object *obj, int verbose ) struct wait_completion_packet *packet = (struct wait_completion_packet *)obj; assert( obj->ops == &wait_completion_packet_ops ); - fprintf( stderr, "WaitCompletionPacket\n" ); + fprintf( stderr, "WaitCompletionPacket target=%p completion=%p ckey=%llx cvalue=%llx " + "information=%llx status=%#x in_object_packet_queue=%d in_completion_queue=%d\n", + packet->target, packet->completion, (long long unsigned int)packet->ckey, + (long long unsigned int)packet->cvalue, (long long unsigned int)packet->information, + packet->status, packet->in_object_packet_queue, packet->in_completion_queue ); +} + +struct wait_completion_packet *get_wait_completion_packet_obj( struct process *process, obj_handle_t handle, unsigned int access ) +{ + return (struct wait_completion_packet *)get_handle_obj( process, handle, access, &wait_completion_packet_ops ); } static struct wait_completion_packet *create_wait_completion_packet( struct object *root, @@ -89,7 +118,46 @@ static struct wait_completion_packet *create_wait_completion_packet( struct obje unsigned int attr, const struct security_descriptor *sd ) { - return create_named_object( root, &wait_completion_packet_ops, name, attr, sd ); + struct wait_completion_packet *packet; + + if ((packet = create_named_object( root, &wait_completion_packet_ops, name, attr, sd )) + && get_error() != STATUS_OBJECT_NAME_EXISTS) + { + packet->target = NULL; + packet->completion = NULL; + packet->ckey = 0; + packet->cvalue = 0; + packet->information = 0; + packet->status = 0; + packet->in_object_packet_queue = 0; + packet->in_completion_queue = 0; + } + return packet; +} + +static void wait_completion_packet_destroy( struct object *obj ) +{ + struct wait_completion_packet *packet = (struct wait_completion_packet *)obj; + struct comp_msg *comp_msg; + + if (packet->in_object_packet_queue) list_remove( &packet->entry ); + + if (packet->in_completion_queue) + { + LIST_FOR_EACH_ENTRY( comp_msg, &packet->completion->queue, struct comp_msg, queue_entry ) + { + if (comp_msg->packet == packet) + { + list_remove( &comp_msg->queue_entry ); + free( comp_msg ); + packet->completion->depth--; + break; + } + } + } + + if (packet->target) release_object( packet->target ); + if (packet->completion) release_object( packet->completion ); } static const WCHAR completion_name[] = {'I','o','C','o','m','p','l','e','t','i','o','n'}; @@ -106,15 +174,6 @@ struct type_descr completion_type = }, }; -struct comp_msg -{ - struct list queue_entry; - apc_param_t ckey; - apc_param_t cvalue; - apc_param_t information; - unsigned int status; -}; - struct completion_wait { struct object obj; @@ -125,15 +184,6 @@ struct completion_wait struct list wait_queue_entry; }; -struct completion -{ - struct object obj; - struct list queue; - struct list wait_queue; - unsigned int depth; - int closed; -}; - static void completion_wait_dump( struct object*, int ); static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ); @@ -342,7 +392,7 @@ struct completion *get_completion_obj( struct process *process, obj_handle_t han } void add_completion( struct completion *completion, apc_param_t ckey, apc_param_t cvalue, - unsigned int status, apc_param_t information ) + unsigned int status, apc_param_t information, struct wait_completion_packet *packet ) { struct comp_msg *msg = mem_alloc( sizeof( *msg ) ); struct completion_wait *wait; @@ -350,6 +400,7 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ if (!msg) return; + msg->packet = packet; msg->ckey = ckey; msg->cvalue = cvalue; msg->status = status; @@ -385,6 +436,65 @@ DECL_HANDLER(create_wait_completion_packet) if (root) release_object( root ); } +/* associate a wait completion packet */ +DECL_HANDLER(associate_wait_completion_packet) +{ + struct wait_completion_packet *packet; + struct completion *completion; + struct object *target; + + packet = get_wait_completion_packet_obj( current->process, req->packet, WAIT_COMPLETION_PACKET_QUERY_STATE ); + if (!packet) + return; + + if (packet->in_object_packet_queue || packet->in_completion_queue) + { + release_object( packet ); + set_error( STATUS_INVALID_PARAMETER_1 ); + return; + } + + completion = get_completion_obj( current->process, req->completion, IO_COMPLETION_MODIFY_STATE ); + if (!completion) + { + release_object( packet ); + return; + } + + target = get_handle_obj( current->process, req->target, 0, NULL ); + if (!target) + { + release_object( completion ); + release_object( packet ); + return; + } + + packet->completion = (struct completion *)grab_object( completion ); + packet->ckey = req->ckey; + packet->cvalue = req->cvalue; + packet->information = req->information; + packet->status = req->status; + + if (is_obj_signaled( target )) + { + add_completion( packet->completion, packet->ckey, packet->cvalue, packet->status, + packet->information, packet ); + packet->in_completion_queue = 1; + reply->signaled = 1; + } + else + { + packet->target = grab_object( target ); + list_add_tail( &target->wait_completion_packet_queue, &packet->entry ); + packet->in_object_packet_queue = 1; + reply->signaled = 0; + } + + release_object( packet ); + release_object( target ); + release_object( completion ); +} + /* create a completion */ DECL_HANDLER(create_completion) { @@ -429,7 +539,7 @@ DECL_HANDLER(add_completion) return; } - add_completion( completion, req->ckey, req->cvalue, req->status, req->information ); + add_completion( completion, req->ckey, req->cvalue, req->status, req->information, NULL ); if (reserve) release_object( reserve ); release_object( completion ); @@ -477,6 +587,12 @@ DECL_HANDLER(remove_completion) reply->cvalue = msg->cvalue; reply->status = msg->status; reply->information = msg->information; + if (msg->packet) + { + release_object( msg->packet->completion ); + msg->packet->completion = NULL; + msg->packet->in_completion_queue = 0; + } free( msg ); reply->wait_handle = 0; } diff --git a/server/fd.c b/server/fd.c index dc2475b2d28..f5fbab6c224 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2925,7 +2925,7 @@ DECL_HANDLER(add_fd_completion) if (fd) { if (fd->completion && (req->async || !(fd->comp_flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS))) - add_completion( fd->completion, fd->comp_key, req->cvalue, req->status, req->information ); + add_completion( fd->completion, fd->comp_key, req->cvalue, req->status, req->information, NULL ); release_object( fd ); } } diff --git a/server/file.h b/server/file.h index 5e988376e55..557edaefc88 100644 --- a/server/file.h +++ b/server/file.h @@ -51,6 +51,16 @@ struct async_queue struct wait_completion_packet { struct object obj; /* object header */ + struct list entry; /* list entry in the target object packet list */ + struct object *target; /* target object */ + struct completion *completion; /* completion object */ + apc_param_t ckey; /* key context */ + apc_param_t cvalue; /* apc context */ + apc_param_t information; /* IO_STATUS_BLOCK information */ + unsigned int status; /* completion status */ + unsigned int in_object_packet_queue: 1; /* whether the packet is in the target object queue */ + unsigned int in_completion_queue: 1; /* whether the packet is in the completion queue */ + unsigned int pad: 30; /* padding */ }; /* operations valid on file descriptor objects */ @@ -244,7 +254,7 @@ extern struct dir *get_dir_obj( struct process *process, obj_handle_t handle, un extern struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern struct reserve *get_completion_reserve_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern void add_completion( struct completion *completion, apc_param_t ckey, apc_param_t cvalue, - unsigned int status, apc_param_t information ); + unsigned int status, apc_param_t information, struct wait_completion_packet *packet ); extern void cleanup_thread_completion( struct thread *thread ); /* serial port functions */ diff --git a/server/object.c b/server/object.c index cd368ef724a..8c9708abf7d 100644 --- a/server/object.c +++ b/server/object.c @@ -308,6 +308,7 @@ void *alloc_object( const struct object_ops *ops ) obj->name = NULL; obj->sd = NULL; list_init( &obj->wait_queue ); + list_init( &obj->wait_completion_packet_queue ); #ifdef DEBUG_OBJECTS list_add_head( &object_list, &obj->obj_list ); #endif diff --git a/server/object.h b/server/object.h index e02dbdc6b71..d29aa4c346a 100644 --- a/server/object.h +++ b/server/object.h @@ -115,6 +115,7 @@ struct object unsigned int handle_count;/* handle count */ const struct object_ops *ops; struct list wait_queue; + struct list wait_completion_packet_queue; struct object_name *name; struct security_descriptor *sd; unsigned int is_permanent:1; diff --git a/server/process.c b/server/process.c index 737b37d9441..c0ab5ed7663 100644 --- a/server/process.c +++ b/server/process.c @@ -266,7 +266,7 @@ static struct job *get_job_obj( struct process *process, obj_handle_t handle, un static void add_job_completion( struct job *job, apc_param_t msg, apc_param_t pid ) { if (job->completion_port) - add_completion( job->completion_port, job->completion_key, pid, STATUS_SUCCESS, msg ); + add_completion( job->completion_port, job->completion_key, pid, STATUS_SUCCESS, msg, NULL ); } static void add_job_completion_existing_processes( struct job *job, struct job *completion_job ) diff --git a/server/protocol.def b/server/protocol.def index 5f9431d9517..1c5ac39cce9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3858,6 +3858,20 @@ struct handle_info @END +/* Associate a wait completion packet */ +(a)REQ(associate_wait_completion_packet) + obj_handle_t packet; /* wait completion packet handle */ + obj_handle_t completion; /* completion handle */ + obj_handle_t target; /* target object handle */ + apc_param_t ckey; /* completion key */ + apc_param_t cvalue; /* completion value */ + apc_param_t information; /* IO_STATUS_BLOCK information */ + unsigned int status; /* completion status */ +(a)REPLY + int signaled; /* whether the object is already signaled */ +(a)END + + /* check for associated completion and push msg */ @REQ(add_fd_completion) obj_handle_t handle; /* async' object */ diff --git a/server/thread.c b/server/thread.c index b3ce5d9ac95..2f25859d7a1 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1059,12 +1059,44 @@ static int select_on( const union select_op *select_op, data_size_t op_size, cli return 0; } +int is_obj_signaled( struct object *obj ) +{ + struct wait_queue_entry wait_entry; + struct thread_wait wait = {0}; + + if (!obj->ops->signaled) + return 0; + + wait.thread = current; + list_init( &wait_entry.entry ); + wait_entry.obj = obj; + wait_entry.wait = &wait; + return obj->ops->signaled( obj, &wait_entry ); +} + /* attempt to wake threads sleeping on the object wait queue */ void wake_up( struct object *obj, int max ) { struct list *ptr; int ret; + if (is_obj_signaled( obj )) + { + struct wait_completion_packet *packet; + + LIST_FOR_EACH_ENTRY( packet, &obj->wait_completion_packet_queue, struct wait_completion_packet, entry ) + { + list_remove( &packet->entry ); + release_object( packet->target ); + packet->in_object_packet_queue = 0; + packet->target = NULL; + + add_completion( packet->completion, packet->ckey, packet->cvalue, packet->status, + packet->information, packet ); + packet->in_completion_queue = 1; + } + } + LIST_FOR_EACH( ptr, &obj->wait_queue ) { struct wait_queue_entry *entry = LIST_ENTRY( ptr, struct wait_queue_entry, entry ); diff --git a/server/thread.h b/server/thread.h index 754e617b484..26eb17866e4 100644 --- a/server/thread.h +++ b/server/thread.h @@ -116,6 +116,7 @@ extern int wake_thread_queue_entry( struct wait_queue_entry *entry ); extern int add_queue( struct object *obj, struct wait_queue_entry *entry ); extern void remove_queue( struct object *obj, struct wait_queue_entry *entry ); extern void kill_thread( struct thread *thread, int violent_death ); +extern int is_obj_signaled( struct object *obj ); extern void wake_up( struct object *obj, int max ); extern int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const union apc_call *call_data ); extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/signal_arm64ec.c | 1 + dlls/ntdll/tests/file.c | 1 - dlls/ntdll/unix/sync.c | 20 ++++++++++++ dlls/wow64/sync.c | 12 +++++++ include/winternl.h | 1 + server/completion.c | 62 +++++++++++++++++++++++++++++++++++++ server/protocol.def | 7 +++++ 8 files changed, 104 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 2085be4aaf7..8132ff23cea 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -159,6 +159,7 @@ @ stdcall -syscall NtCancelIoFileEx(long ptr ptr) @ stdcall -syscall NtCancelSynchronousIoFile(long ptr ptr) @ stdcall -syscall NtCancelTimer(long ptr) +@ stdcall -syscall NtCancelWaitCompletionPacket(ptr long) @ stdcall -syscall NtClearEvent(long) @ stdcall -syscall NtClose(long) # @ stub NtCloseObjectAuditAlarm diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index c33757b7ec0..0662bc300a6 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -263,6 +263,7 @@ DEFINE_SYSCALL(NtCancelIoFile, (HANDLE handle, IO_STATUS_BLOCK *io_status)) DEFINE_SYSCALL(NtCancelIoFileEx, (HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status)) DEFINE_SYSCALL(NtCancelSynchronousIoFile, (HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_BLOCK *io_status)) DEFINE_SYSCALL(NtCancelTimer, (HANDLE handle, BOOLEAN *state)) +DEFINE_SYSCALL(NtCancelWaitCompletionPacket, (HANDLE packet, BOOLEAN remove_signaled)) DEFINE_SYSCALL(NtClearEvent, (HANDLE handle)) DEFINE_SYSCALL(NtClose, (HANDLE handle)) DEFINE_SYSCALL(NtCommitTransaction, (HANDLE transaction, BOOLEAN wait)) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 056167b7309..2cb0c02a83d 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -6570,7 +6570,6 @@ static void test_cancel_wait_completion_packet(void) if (!pNtCancelWaitCompletionPacket) { - todo_wine win_skip("NtCancelWaitCompletionPacket is unavailable.\n"); return; } diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 16337a64daa..6fa28225cb9 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2822,6 +2822,26 @@ NTSTATUS WINAPI NtAssociateWaitCompletionPacket( HANDLE packet, HANDLE completio return ret; } +/*********************************************************************** + * NtCancelWaitCompletionPacket (NTDLL.@) + */ +NTSTATUS WINAPI NtCancelWaitCompletionPacket( HANDLE packet, BOOLEAN remove_signaled ) +{ + NTSTATUS status; + + TRACE("packet %p, remove_signaled %d.\n", packet, remove_signaled); + + SERVER_START_REQ( cancel_wait_completion_packet ) + { + req->packet = wine_server_obj_handle( packet ); + req->remove_signaled = remove_signaled; + status = wine_server_call( req ); + } + SERVER_END_REQ; + return status; +} + + /*********************************************************************** * NtCreateWaitCompletionPacket (NTDLL.@) */ diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index d9bea95fd5e..7362adde7a4 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -1801,6 +1801,18 @@ NTSTATUS WINAPI wow64_NtAssociateWaitCompletionPacket( UINT *args ) } +/********************************************************************** + * wow64_NtCancelWaitCompletionPacket + */ +NTSTATUS WINAPI wow64_NtCancelWaitCompletionPacket( UINT *args ) +{ + HANDLE packet = get_handle( &args ); + BOOLEAN remove_signaled = get_ulong( &args ); + + return NtCancelWaitCompletionPacket( packet, remove_signaled ); +} + + /********************************************************************** * wow64_NtCreateWaitCompletionPacket */ diff --git a/include/winternl.h b/include/winternl.h index 6105cef9528..3f74a18c4aa 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4493,6 +4493,7 @@ NTSYSAPI NTSTATUS WINAPI NtCancelIoFile(HANDLE,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelIoFileEx(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelSynchronousIoFile(HANDLE,PIO_STATUS_BLOCK,PIO_STATUS_BLOCK); NTSYSAPI NTSTATUS WINAPI NtCancelTimer(HANDLE, BOOLEAN*); +NTSYSAPI NTSTATUS WINAPI NtCancelWaitCompletionPacket(HANDLE, BOOLEAN); NTSYSAPI NTSTATUS WINAPI NtClearEvent(HANDLE); NTSYSAPI NTSTATUS WINAPI NtClose(HANDLE); NTSYSAPI NTSTATUS WINAPI NtCloseObjectAuditAlarm(PUNICODE_STRING,HANDLE,BOOLEAN); diff --git a/server/completion.c b/server/completion.c index 0c5b98851a9..8de1d8f6d72 100644 --- a/server/completion.c +++ b/server/completion.c @@ -495,6 +495,68 @@ DECL_HANDLER(associate_wait_completion_packet) release_object( completion ); } +/* cancel a wait completion packet */ +DECL_HANDLER(cancel_wait_completion_packet) +{ + struct wait_completion_packet *packet; + + packet = get_wait_completion_packet_obj( current->process, req->packet, WAIT_COMPLETION_PACKET_QUERY_STATE ); + if (!packet) + return; + + if (!packet->in_object_packet_queue && !packet->in_completion_queue) + { + set_error( STATUS_CANCELLED ); + release_object( packet ); + return; + } + + if (packet->in_completion_queue && !req->remove_signaled) + { + set_error( STATUS_PENDING ); + release_object( packet ); + return; + } + + if (packet->in_object_packet_queue) + { + list_remove( &packet->entry ); + packet->in_object_packet_queue = 0; + } + + if (packet->in_completion_queue) + { + struct comp_msg *comp_msg; + + LIST_FOR_EACH_ENTRY( comp_msg, &packet->completion->queue, struct comp_msg, queue_entry ) + { + if (comp_msg->packet == packet) + { + list_remove( &comp_msg->queue_entry ); + free( comp_msg ); + packet->completion->depth--; + break; + } + } + + packet->in_completion_queue = 0; + } + + if (packet->target) + { + release_object( packet->target ); + packet->target = NULL; + } + + if (packet->completion) + { + release_object( packet->completion ); + packet->completion = NULL; + } + + release_object( packet ); +} + /* create a completion */ DECL_HANDLER(create_completion) { diff --git a/server/protocol.def b/server/protocol.def index 1c5ac39cce9..cca69edef17 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3872,6 +3872,13 @@ struct handle_info @END +/* Cancel a wait completion packet */ +(a)REQ(cancel_wait_completion_packet) + obj_handle_t packet; /* wait completion packet handle */ + int remove_signaled;/* whether to remove signaled packet */ +(a)END + + /* check for associated completion and push msg */ @REQ(add_fd_completion) obj_handle_t handle; /* async' object */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6911
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=149982 Your paranoid android. === debian11 (build log) === /usr/bin/i686-w64-mingw32-ld: tmp677dd032/ntdll-00000000.spec.o:fake:(.edata+0x218): undefined reference to `NtAssociateWaitCompletionPacket(a)32' /usr/bin/i686-w64-mingw32-ld: tmp677dd032/ntdll-00000000.spec.o:fake:(.edata+0x230): undefined reference to `NtCancelWaitCompletionPacket(a)8' /usr/bin/i686-w64-mingw32-ld: tmp677dd032/ntdll-00000000.spec.o:fake:(.edata+0x2b8): undefined reference to `NtCreateWaitCompletionPacket(a)12' collect2: error: ld returned 1 exit status Task: The win32 Wine build failed === debian11b (build log) === /usr/bin/x86_64-w64-mingw32-ld: tmp6774308b/ntdll-00000000.spec.o:fake:(.edata+0x218): undefined reference to `NtAssociateWaitCompletionPacket' /usr/bin/x86_64-w64-mingw32-ld: tmp6774308b/ntdll-00000000.spec.o:fake:(.edata+0x230): undefined reference to `NtCancelWaitCompletionPacket' /usr/bin/x86_64-w64-mingw32-ld: tmp6774308b/ntdll-00000000.spec.o:fake:(.edata+0x2b8): undefined reference to `NtCreateWaitCompletionPacket' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed
participants (3)
-
Marvin -
Zhiyi Zhang -
Zhiyi Zhang (@zhiyi)