From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/ntdll.spec | 2 ++ dlls/ntdll/signal_arm64ec.c | 1 + dlls/ntdll/tests/file.c | 1 - dlls/ntdll/unix/sync.c | 29 +++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 1 + dlls/wow64/sync.c | 16 ++++++++++++++++ include/winternl.h | 1 + server/completion.c | 8 ++++++++ server/file.h | 2 ++ server/object.c | 5 +++++ server/protocol.def | 2 ++ 11 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index ddf1a120517..6d029bb6289 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -400,6 +400,7 @@ @ stdcall -syscall NtSetInformationVirtualMemory(long long ptr ptr ptr long) @ stdcall -syscall NtSetIntervalProfile(long long) @ stdcall -syscall NtSetIoCompletion(ptr long long long long) +@ stdcall -syscall NtSetIoCompletionEx(ptr ptr long long long long) @ stdcall -syscall NtSetLdtEntries(long int64 long int64) # @ stub NtSetLowEventPair # @ stub NtSetLowWaitHighEventPair @@ -1453,6 +1454,7 @@ @ stdcall -private -syscall ZwSetInformationVirtualMemory(long long ptr ptr ptr long) NtSetInformationVirtualMemory @ stdcall -private -syscall ZwSetIntervalProfile(long long) NtSetIntervalProfile @ stdcall -private -syscall ZwSetIoCompletion(ptr long long long long) NtSetIoCompletion +@ stdcall -private -syscall ZwSetIoCompletionEx(ptr ptr long long long long) NtSetIoCompletionEx @ stdcall -private -syscall ZwSetLdtEntries(long int64 long int64) NtSetLdtEntries # @ stub ZwSetLowEventPair # @ stub ZwSetLowWaitHighEventPair diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 438dfe8d439..f0687737f3f 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -443,6 +443,7 @@ DEFINE_SYSCALL(NtSetInformationToken, (HANDLE token, TOKEN_INFORMATION_CLASS cla DEFINE_SYSCALL(NtSetInformationVirtualMemory, (HANDLE process, VIRTUAL_MEMORY_INFORMATION_CLASS info_class, ULONG_PTR count, PMEMORY_RANGE_ENTRY addresses, PVOID ptr, ULONG size)) DEFINE_SYSCALL(NtSetIntervalProfile, (ULONG interval, KPROFILE_SOURCE source)) DEFINE_SYSCALL(NtSetIoCompletion, (HANDLE handle, ULONG_PTR key, ULONG_PTR value, NTSTATUS status, SIZE_T count)) +DEFINE_SYSCALL(NtSetIoCompletionEx, (HANDLE completion_handle, HANDLE completion_reserve_handle, ULONG_PTR key, ULONG_PTR value, NTSTATUS status, SIZE_T count)) DEFINE_SYSCALL(NtSetLdtEntries, (ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2)) DEFINE_SYSCALL(NtSetSecurityObject, (HANDLE handle, SECURITY_INFORMATION info, PSECURITY_DESCRIPTOR descr)) DEFINE_SYSCALL(NtSetSystemInformation, (SYSTEM_INFORMATION_CLASS class, void *info, ULONG length)) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 85847bc3111..95bd1c37cac 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -5945,7 +5945,6 @@ static void test_set_io_completion_ex(void)
if (!pNtSetIoCompletionEx || !pNtAllocateReserveObject) { - todo_wine win_skip("NtSetIoCompletionEx() or NtAllocateReserveObject() is unavailable.\n"); return; } diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 80f82c18730..3841a579ba2 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1986,12 +1986,41 @@ NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value req->cvalue = value; req->status = status; req->information = count; + req->has_reserve = FALSE; ret = wine_server_call( req ); } SERVER_END_REQ; return ret; }
+/*********************************************************************** + * NtSetIoCompletionEx (NTDLL.@) + * + * completion_reserve_handle is a handle allocated by NtAllocateReserveObject() for pre-allocating + * memory for completion objects to deal with low-memory situations. It's not in use for now. + */ +NTSTATUS WINAPI NtSetIoCompletionEx( HANDLE completion_handle, HANDLE completion_reserve_handle, + ULONG_PTR key, ULONG_PTR value, NTSTATUS status, SIZE_T count ) +{ + unsigned int ret; + + TRACE( "(%p, %p, %lx, %lx, %x, %lx)\n", completion_handle, completion_reserve_handle, + key, value, (int)status, count ); + + SERVER_START_REQ( add_completion ) + { + req->handle = wine_server_obj_handle( completion_handle ); + req->ckey = key; + req->cvalue = value; + req->status = status; + req->information = count; + req->reserve_handle = wine_server_obj_handle( completion_reserve_handle ); + req->has_reserve = TRUE; + ret = wine_server_call( req ); + } + SERVER_END_REQ; + return ret; +}
/*********************************************************************** * NtRemoveIoCompletion (NTDLL.@) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index eb85130ae1a..276e166c4a9 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1525,6 +1525,7 @@ @ stdcall -private ZwSetInformationToken(long long ptr long) NtSetInformationToken @ stdcall -private ZwSetIntervalProfile(long long) NtSetIntervalProfile @ stdcall -private ZwSetIoCompletion(ptr long long long long) NtSetIoCompletion +@ stdcall -private ZwSetIoCompletionEx(ptr ptr long long long long) NtSetIoCompletionEx @ stdcall -private ZwSetSecurityObject(long long ptr) NtSetSecurityObject @ stdcall -private ZwSetSystemInformation(long ptr long) NtSetSystemInformation @ stdcall -private ZwSetSystemTime(ptr ptr) NtSetSystemTime diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index a445da2d620..54dca19dc1a 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -1449,6 +1449,22 @@ NTSTATUS WINAPI wow64_NtSetIoCompletion( UINT *args ) }
+/********************************************************************** + * wow64_NtSetIoCompletionEx + */ +NTSTATUS WINAPI wow64_NtSetIoCompletionEx( UINT *args ) +{ + HANDLE completion_handle = get_handle( &args ); + HANDLE completion_reserve_handle = get_handle( &args ); + ULONG_PTR key = get_ulong( &args ); + ULONG_PTR value = get_ulong( &args ); + NTSTATUS status = get_ulong( &args ); + SIZE_T count = get_ulong( &args ); + + return NtSetIoCompletionEx( completion_handle, completion_reserve_handle, key, value, status, count ); +} + + /********************************************************************** * wow64_NtSetTimer */ diff --git a/include/winternl.h b/include/winternl.h index bc3ef12bc0d..edccef5ad18 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4675,6 +4675,7 @@ NTSYSAPI NTSTATUS WINAPI NtSetInformationToken(HANDLE,TOKEN_INFORMATION_CLASS,P NTSYSAPI NTSTATUS WINAPI NtSetInformationVirtualMemory(HANDLE,VIRTUAL_MEMORY_INFORMATION_CLASS,ULONG_PTR,PMEMORY_RANGE_ENTRY,PVOID,ULONG); NTSYSAPI NTSTATUS WINAPI NtSetIntervalProfile(ULONG,KPROFILE_SOURCE); NTSYSAPI NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,ULONG_PTR,NTSTATUS,SIZE_T); +NTSYSAPI NTSTATUS WINAPI NtSetIoCompletionEx(HANDLE,HANDLE,ULONG_PTR,ULONG_PTR,NTSTATUS,SIZE_T); NTSYSAPI NTSTATUS WINAPI NtSetLdtEntries(ULONG,LDT_ENTRY,ULONG,LDT_ENTRY); NTSYSAPI NTSTATUS WINAPI NtSetLowEventPair(HANDLE); NTSYSAPI NTSTATUS WINAPI NtSetLowWaitHighEventPair(HANDLE); diff --git a/server/completion.c b/server/completion.c index f9e68c523f1..47ae4092417 100644 --- a/server/completion.c +++ b/server/completion.c @@ -344,11 +344,19 @@ DECL_HANDLER(open_completion) DECL_HANDLER(add_completion) { struct completion* completion = get_completion_obj( current->process, req->handle, IO_COMPLETION_MODIFY_STATE ); + struct reserve* reserve = NULL;
if (!completion) return;
+ if (req->has_reserve && !(reserve = get_completion_reserve_obj( current->process, req->reserve_handle, 0 ))) + { + release_object( completion ); + return; + } + add_completion( completion, req->ckey, req->cvalue, req->status, req->information );
+ if (reserve) release_object( reserve ); release_object( completion ); }
diff --git a/server/file.h b/server/file.h index 3d7cdc460ff..eb4eff96575 100644 --- a/server/file.h +++ b/server/file.h @@ -29,6 +29,7 @@ struct fd; struct mapping; struct async_queue; struct completion; +struct reserve;
/* server-side representation of I/O status block */ struct iosb @@ -236,6 +237,7 @@ extern struct dir *get_dir_obj( struct process *process, obj_handle_t handle, un /* completion */
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 ); extern void cleanup_thread_completion( struct thread *thread ); diff --git a/server/object.c b/server/object.c index b1665fb5372..cd368ef724a 100644 --- a/server/object.c +++ b/server/object.c @@ -854,6 +854,11 @@ static struct reserve *create_reserve( struct object *root, const struct unicode return reserve; }
+struct reserve *get_completion_reserve_obj( struct process *process, obj_handle_t handle, unsigned int access ) +{ + return (struct reserve *)get_handle_obj( process, handle, access, &completion_reserve_ops ); +} + /* Allocate a reserve object for pre-allocating memory for object types */ DECL_HANDLER(allocate_reserve_object) { diff --git a/server/protocol.def b/server/protocol.def index 9ecb14cbac4..c0e3980c964 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3800,10 +3800,12 @@ typedef union /* add completion to completion port */ @REQ(add_completion) obj_handle_t handle; /* port handle */ + obj_handle_t reserve_handle; /* completion reserve 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 result */ + int has_reserve; /* whether completion reserve object handle is valid */ @END