Module: wine Branch: master Commit: 343f2c1b307bbaffc00b93bceb01b8343730a83c URL: http://source.winehq.org/git/wine.git/?a=commit;h=343f2c1b307bbaffc00b93bceb...
Author: Andrey Turkin andrey.turkin@gmail.com Date: Thu Dec 20 00:27:44 2007 +0300
ntdll: Implement BindIoCompletionCallback.
---
dlls/kernel32/sync.c | 9 +++- dlls/kernel32/tests/sync.c | 4 -- dlls/ntdll/ntdll.spec | 2 +- dlls/ntdll/threadpool.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ include/winternl.h | 3 + 5 files changed, 104 insertions(+), 7 deletions(-)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index 1bb2c8a..975b914 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, (PRTL_OVERLAPPED_COMPLETION_ROUTINE)Function, Flags ); + if (status == STATUS_SUCCESS) return TRUE; + SetLastError( RtlNtStatusToDosError(status) ); return FALSE; }
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index e402fed..3ab86ea 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -326,10 +326,6 @@ static void test_iocp_callback(void)
retb = p_BindIoCompletionCallback(hFile, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded on a file that wasn't created with FILE_FLAG_OVERLAPPED\n"); - if(retb == FALSE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - todo_wine ok (0, "BindIoCompletionCallback returned ERROR_CALL_NOT_IMPLEMENTED\n"); - return; - } ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error is %d\n", GetLastError());
ret = CloseHandle(hFile); 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..147667b 100644 --- a/dlls/ntdll/threadpool.c +++ b/dlls/ntdll/threadpool.c @@ -54,6 +54,16 @@ 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; +static RTL_CRITICAL_SECTION threadpool_compl_cs; +static RTL_CRITICAL_SECTION_DEBUG critsect_compl_debug = +{ + 0, 0, &threadpool_compl_cs, + { &critsect_compl_debug.ProcessLocksList, &critsect_compl_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": threadpool_compl_cs") } +}; +static RTL_CRITICAL_SECTION threadpool_compl_cs = { &critsect_compl_debug, -1, 0, 0, 0, 0 }; + struct work_item { struct list entry; @@ -218,3 +228,86 @@ NTSTATUS WINAPI RtlQueueWorkItem(PRTL_WORK_ITEM_ROUTINE Function, PVOID Context,
return STATUS_SUCCESS; } + +/*********************************************************************** + * iocp_poller - get completion events and run callbacks + */ +static DWORD CALLBACK iocp_poller(LPVOID Arg) +{ + while( TRUE ) + { + PRTL_OVERLAPPED_COMPLETION_ROUTINE callback; + LPVOID overlapped; + IO_STATUS_BLOCK iosb; + NTSTATUS res = NtRemoveIoCompletion( compl_port, (PULONG_PTR)&callback, (PULONG_PTR)&overlapped, &iosb, NULL ); + if (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, PRTL_OVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) +{ + IO_STATUS_BLOCK iosb; + FILE_COMPLETION_INFORMATION info; + + if (Flags) FIXME("Unknown value Flags=0x%x\n", Flags); + + if (!compl_port) + { + NTSTATUS res = STATUS_SUCCESS; + + RtlEnterCriticalSection(&threadpool_compl_cs); + if (!compl_port) + { + HANDLE cport; + + res = NtCreateIoCompletion( &cport, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); + if (!res) + { + /* FIXME native can start additional threads in case of e.g. hung callback function. */ + res = RtlQueueWorkItem( iocp_poller, NULL, WT_EXECUTEDEFAULT ); + if (!res) + compl_port = cport; + else + NtClose( cport ); + } + } + RtlLeaveCriticalSection(&threadpool_compl_cs); + if (res) return res; + } + + info.CompletionPort = compl_port; + info.CompletionKey = (ULONG_PTR)Function; + + return NtSetInformationFile( FileHandle, &iosb, &info, sizeof(info), FileCompletionInformation ); +} diff --git a/include/winternl.h b/include/winternl.h index 7ba6e5b..79f3184 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1568,6 +1568,8 @@ typedef struct _KEY_MULTIPLE_VALUE_INFORMATION ULONG Type; } KEY_MULTIPLE_VALUE_INFORMATION, *PKEY_MULTIPLE_VALUE_INFORMATION;
+typedef VOID (CALLBACK *PRTL_OVERLAPPED_COMPLETION_ROUTINE)(DWORD,DWORD,LPVOID); + typedef VOID (*PTIMER_APC_ROUTINE) ( PVOID, ULONG, LONG );
typedef enum _EVENT_TYPE { @@ -2273,6 +2275,7 @@ NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,BOOL NTSYSAPI NTSTATUS WINAPI RtlSetEnvironmentVariable(PWSTR*,PUNICODE_STRING,PUNICODE_STRING); NTSYSAPI NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID,BOOLEAN); NTSYSAPI NTSTATUS WINAPI RtlSetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID,BOOLEAN); +NTSYSAPI NTSTATUS WINAPI RtlSetIoCompletionCallback(HANDLE,PRTL_OVERLAPPED_COMPLETION_ROUTINE,ULONG); NTSYSAPI void WINAPI RtlSetLastWin32Error(DWORD); NTSYSAPI void WINAPI RtlSetLastWin32ErrorAndNtStatusFromNtStatus(NTSTATUS); NTSYSAPI NTSTATUS WINAPI RtlSetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR,BOOLEAN,PACL,BOOLEAN);