Andrey Turkin : ntdll: Implement BindIoCompletionCallback.
Alexandre Julliard
julliard at winehq.org
Fri Dec 21 07:28:32 CST 2007
Module: wine
Branch: master
Commit: 343f2c1b307bbaffc00b93bceb01b8343730a83c
URL: http://source.winehq.org/git/wine.git/?a=commit;h=343f2c1b307bbaffc00b93bceb01b8343730a83c
Author: Andrey Turkin <andrey.turkin at 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);
More information about the wine-cvs
mailing list