All pastes #817644 Raw Edit

Mine

public text v1 · immutable
·published 2007-12-15 19:32 UTC
rendered paste body
From 530088678b26fda83f8fea0a388cca3afefb5ca1 Mon Sep 17 00:00:00 2001
From: Andrey Turkin <andrey.turkin@gmail.com>
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