From 530088678b26fda83f8fea0a388cca3afefb5ca1 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 15 Dec 2007 23:29:52 +0300 Subject: [PATCH] implement BindIoCompletionCallback --- dlls/kernel32/sync.c | 9 ++++- dlls/ntdll/ntdll.spec | 2 +- dlls/ntdll/threadpool.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index 08385f1..fcc3011 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -1912,8 +1912,13 @@ BOOL WINAPI PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD dwNumberOfB */ BOOL WINAPI BindIoCompletionCallback( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) { - FIXME("%p, %p, %d, stub!\n", FileHandle, Function, Flags); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + NTSTATUS status; + + TRACE("(%p, %p, %d)\n", FileHandle, Function, Flags); + + status = RtlSetIoCompletionCallback( FileHandle, Function, Flags ); + if (status == STATUS_SUCCESS) return TRUE; + SetLastError( RtlNtStatusToDosError(status) ); return FALSE; } diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index fc1a6c8..1a7db96 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -822,7 +822,7 @@ @ stdcall RtlSetGroupSecurityDescriptor(ptr ptr long) # @ stub RtlSetHeapInformation @ stub RtlSetInformationAcl -# @ stub RtlSetIoCompletionCallback +@ stdcall RtlSetIoCompletionCallback(long ptr long) @ stdcall RtlSetLastWin32Error(long) @ stdcall RtlSetLastWin32ErrorAndNtStatusFromNtStatus(long) # @ stub RtlSetMemoryStreamSize diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c index 72ea0cf..940f4f5 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -54,6 +54,8 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_debug = }; static RTL_CRITICAL_SECTION threadpool_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; +static HANDLE compl_port = NULL; + struct work_item { struct list entry; @@ -218,3 +220,85 @@ NTSTATUS WINAPI RtlQueueWorkItem(PRTL_WORK_ITEM_ROUTINE Function, PVOID Context, return STATUS_SUCCESS; } + +/*********************************************************************** + * iocp_poller - get completion events and run callbacks + */ +DWORD CALLBACK iocp_poller(LPVOID Arg) +{ + while( TRUE ) + { + LPOVERLAPPED_COMPLETION_ROUTINE callback; + LPOVERLAPPED overlapped; + IO_STATUS_BLOCK iosb; + NTSTATUS res = NtRemoveIoCompletion( compl_port, (PULONG_PTR)&callback, (PULONG_PTR)&overlapped, &iosb, NULL ); + if (FAILED(res)) + { + ERR("NtRemoveIoCompletion failed: 0x%x\n", res); + } + else + { + DWORD transferred = 0; + DWORD err = 0; + + if (iosb.u.Status == STATUS_SUCCESS) + transferred = iosb.Information; + else + err = RtlNtStatusToDosError(iosb.u.Status); + + callback( err, transferred, overlapped ); + } + } +} + +/*********************************************************************** + * RtlSetIoCompletionCallback (NTDLL.@) + * + * Binds a handle to a thread pool's completion port, and possibly + * starts a non-I/O thread to monitor this port and call functions back. + * + * PARAMS + * FileHandle [I] Handle to bind to a completion port. + * Function [I] Callback function to call on I/O completions. + * Flags [I] Not used. + * + * RETURNS + * Success: STATUS_SUCCESS. + * Failure: Any NTSTATUS code. + * + */ +NTSTATUS WINAPI RtlSetIoCompletionCallback(HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) +{ + IO_STATUS_BLOCK iosb; + FILE_COMPLETION_INFORMATION info; + NTSTATUS res; + + if (Flags) FIXME("Unknown value Flags=0x%x\n", Flags); + + if (!compl_port) + { + HANDLE cport; + + res = NtCreateIoCompletion( &cport, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); + if (FAILED(res)) return res; + if (interlocked_cmpxchg_ptr( (PVOID *)&compl_port, (PVOID)cport, 0 )) + NtClose( cport ); + else + { + /* FIXME native can start additional threads in case of e.g. hung callback function. */ + res = RtlQueueWorkItem( iocp_poller, NULL, WT_EXECUTEDEFAULT ); + if (FAILED(res)) + { + compl_port = NULL; + NtClose (cport ); + return res; + } + } + } + + info.CompletionPort = compl_port; + info.CompletionKey = (ULONG_PTR)Function; + + return NtSetInformationFile(FileHandle, &iosb, &info, sizeof(info), FileCompletionInformation ); +} + -- 1.5.3.7