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