IoCompletion port
Christian Heimes
lists at cheimes.de
Thu Dec 14 12:57:47 CST 2006
Hello!
I have a program that needs IoCompletion port to run. The program
crashes at startup because WINE head has only stubs for the functions. I
found a patch created by Robert Shearman which adds IoCompletion to
WINE. The patch is very old (2004?) and doesn't apply against the
current development version of wine.
I merged the patch manually into the source tree but my knowdledge of
WINE is limited (zero *g*). My patched source tree doesn't compile:
make[2]: Betrete Verzeichnis '/home/heimes/dev/misc/wine-io/dlls/winecrt0'
gcc -c -I. -I. -I../../include -I../../include -D__WINESRC__
-D_REENTRANT -fPIC -Wall -pipe -fno-strict-aliasing
-Wdeclaration-after-statement -Wwrite-strings -Wpointer-arith
-fno-stack-protector -o drv_entry.o drv_entry.c
In file included from drv_entry.c:23:
../../include/winternl.h:2377: error: expected declaration specifiers or
‘...’ before ‘LPOVERLAPPED’
../../include/winternl.h:2378: error: expected declaration specifiers or
‘...’ before ‘LPOVERLAPPED’
make[2]: *** [drv_entry.o] Fehler 1
I'm attaching my patch to this posting in the hope somebody with more
wisdom stands up. The patch has two ports (iofiles and new_iocompletion)
because git diff didn't include the new files although I did a git add.
bug report: http://bugs.winehq.org/show_bug.cgi?id=6155
iocompletion: original patch by Robert Shearman
iofiles + new_iocompletion: patches against GIT head
Thank you very much!
Christian
-------------- next part --------------
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/iocompletion.c wine/dlls/kernel/iocompletion.c
--- wine.orig/dlls/kernel/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/kernel/iocompletion.c 2005-05-04 14:08:38.000000000 -0400
@@ -0,0 +1,173 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "ntstatus.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(iocompletion);
+
+HANDLE WINAPI CreateIoCompletionPort(
+ HANDLE FileHandle,
+ HANDLE ExistingCompletionPort,
+ ULONG_PTR CompletionKey,
+ DWORD NumberOfConcurrentThreads)
+{
+ HANDLE CompletionPort;
+ NTSTATUS Status;
+
+ TRACE("(%p, %p, %lx, %ld)\n",
+ FileHandle,
+ ExistingCompletionPort,
+ CompletionKey,
+ NumberOfConcurrentThreads);
+
+ if (((FileHandle == INVALID_HANDLE_VALUE) && (ExistingCompletionPort != NULL)) ||
+ (ExistingCompletionPort == INVALID_HANDLE_VALUE))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+ if (ExistingCompletionPort == NULL)
+ {
+ Status = NtCreateIoCompletion(
+ &CompletionPort,
+ GENERIC_ALL, 0,
+ NumberOfConcurrentThreads);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ else
+ CompletionPort = ExistingCompletionPort;
+
+ if (FileHandle != INVALID_HANDLE_VALUE)
+ {
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_COMPLETION_INFORMATION CompletionInfo;
+ CompletionInfo.CompletionKey = CompletionKey;
+ CompletionInfo.CompletionPort = CompletionPort;
+
+ Status = NtSetInformationFile(
+ FileHandle,
+ &IoStatusBlock,
+ (PVOID)&CompletionInfo,
+ sizeof(FILE_COMPLETION_INFORMATION),
+ FileCompletionInformation);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ return CompletionPort;
+}
+
+BOOL WINAPI GetQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ LPDWORD lpNumberOfBytesTransferred,
+ PULONG_PTR lpCompletionKey,
+ LPOVERLAPPED * lplpOverlapped,
+ DWORD dwMilliseconds)
+{
+ IO_STATUS_BLOCK CompletionBlock;
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %p, %p, %p, %ld)\n",
+ CompletionPort,
+ lpNumberOfBytesTransferred,
+ lpCompletionKey,
+ lplpOverlapped,
+ dwMilliseconds);
+
+ if (dwMilliseconds == INFINITE)
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ NULL);
+ else
+ {
+ LARGE_INTEGER WaitTime;
+ /* multiplying two LONGLONGs with at least one LONGLONG having its
+ * higher long part not zero makes the multiplying a bit harder,
+ * therefore we do an easy multiply and negate afterwards rather than
+ * making it a hard multiply by doing "* -10000"
+ */
+ WaitTime.QuadPart = (LONGLONG)dwMilliseconds * (LONGLONG)10000;
+ WaitTime.QuadPart = -WaitTime.QuadPart;
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ &WaitTime);
+ }
+ if (Status == STATUS_SUCCESS)
+ {
+ *lpNumberOfBytesTransferred = CompletionBlock.Information;
+ return TRUE;
+ }
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
+
+BOOL WINAPI PostQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ DWORD dwNumberOfBytesTransferred,
+ ULONG_PTR dwCompletionKey,
+ LPOVERLAPPED lpOverlapped)
+{
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %ld, %lx, %p)\n",
+ CompletionPort,
+ dwNumberOfBytesTransferred,
+ dwCompletionKey,
+ lpOverlapped);
+
+ Status = NtSetIoCompletion(
+ CompletionPort,
+ dwCompletionKey,
+ lpOverlapped, 0,
+ dwNumberOfBytesTransferred);
+
+ if (Status == STATUS_SUCCESS)
+ return TRUE;
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/kernel32.spec wine/dlls/kernel/kernel32.spec
--- wine.orig/dlls/kernel/kernel32.spec 2005-04-27 07:08:47.000000000 -0400
+++ wine/dlls/kernel/kernel32.spec 2005-05-04 13:58:00.000000000 -0400
@@ -657,7 +657,7 @@
@ stdcall PeekConsoleInputA(ptr ptr long ptr)
@ stdcall PeekConsoleInputW(ptr ptr long ptr)
@ stdcall PeekNamedPipe(long ptr long ptr ptr ptr)
-@ stub PostQueuedCompletionStatus
+@ stdcall PostQueuedCompletionStatus(ptr long long ptr)
@ stdcall PrepareTape(ptr long long)
@ stub PrivMoveFileIdentityW
@ stdcall Process32First (ptr ptr)
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/Makefile.in wine/dlls/kernel/Makefile.in
--- wine.orig/dlls/kernel/Makefile.in 2005-04-20 11:43:36.000000000 -0400
+++ wine/dlls/kernel/Makefile.in 2005-05-04 14:19:47.000000000 -0400
@@ -33,6 +33,7 @@
file.c \
file16.c \
format_msg.c \
+ iocompletion.c \
global16.c \
heap.c \
instr.c \
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel/sync.c wine/dlls/kernel/sync.c
--- wine.orig/dlls/kernel/sync.c 2005-04-24 13:36:34.000000000 -0400
+++ wine/dlls/kernel/sync.c 2005-05-04 19:33:16.000000000 -0400
@@ -1743,31 +1743,6 @@
/******************************************************************************
- * CreateIoCompletionPort (KERNEL32.@)
- */
-HANDLE WINAPI CreateIoCompletionPort(HANDLE hFileHandle, HANDLE hExistingCompletionPort,
- ULONG_PTR CompletionKey, DWORD dwNumberOfConcurrentThreads)
-{
- FIXME("(%p, %p, %08lx, %08lx): stub.\n",
- hFileHandle, hExistingCompletionPort, CompletionKey, dwNumberOfConcurrentThreads);
- return NULL;
-}
-
-
-/******************************************************************************
- * GetQueuedCompletionStatus (KERNEL32.@)
- */
-BOOL WINAPI GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred,
- PULONG_PTR pCompletionKey, LPOVERLAPPED *lpOverlapped,
- DWORD dwMilliseconds )
-{
- FIXME("(%p,%p,%p,%p,%ld), stub!\n",
- CompletionPort,lpNumberOfBytesTransferred,pCompletionKey,lpOverlapped,dwMilliseconds);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-/******************************************************************************
* CreateJobObjectW (KERNEL32.@)
*/
HANDLE WINAPI CreateJobObjectW( LPSECURITY_ATTRIBUTES attr, LPCWSTR name )
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/iocompletion.c wine/dlls/ntdll/iocompletion.c
--- wine.orig/dlls/ntdll/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/ntdll/iocompletion.c 2005-05-04 20:05:27.000000000 -0400
@@ -0,0 +1,216 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+
+#include "ntdll_misc.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+
+extern int NTDLL_wait_reply( void *cookie );
+
+/**************************************************************************
+ * NtCreateIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [O]: the handle created
+ * DesiredAccess [I}: the access desired (e.g. GENERIC_ALL)
+ * Reserved [I}: unknown
+ * NumberOfConcurrentThreads [I]: the desired number of concurrent
+ * threads
+ * Returns:
+ * Status
+ * Notes:
+ * It is effectively a FIFO queue for data and
+ * a LIFO queue for threads to "minimize context switches".
+ * The aim is to keep a small number of threads constantly
+ * active.
+ * See:
+ * MSDN for CreateIoCompletionPort spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtCreateIoCompletion (
+ OUT PHANDLE CompletionPort,
+ IN ACCESS_MASK DesiredAccess,
+ IN ULONG_PTR Reserved,
+ IN ULONG NumberOfConcurrentThreads
+ )
+ {
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %lx, %ld)\n",
+ CompletionPort,
+ DesiredAccess,
+ Reserved,
+ NumberOfConcurrentThreads);
+
+ if (Reserved != 0)
+ {
+ FIXME("Reserved != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (DesiredAccess && GENERIC_ALL)
+ DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
+
+ SERVER_START_REQ( create_io_completion )
+ {
+ req->access = DesiredAccess;
+ req->concurrent_threads = NumberOfConcurrentThreads;
+ ret = wine_server_call( req );
+ *CompletionPort = reply->handle;
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtSetIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [I]: port to send data to
+ * CompletionKey [I}: user key to identify this set of data
+ * lpOverlapped [I}: OVERLAPPED structure to send to port
+ * NumberOfBytesTransferred [I}: unknown - seems to be set to zero always
+ * NumberOfBytesToTransfer [I]: Bytes to transfer in this packet of data
+ * Returns:
+ * Status
+ * See:
+ * MSDN for PostQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtSetIoCompletion(
+ IN HANDLE CompletionPort,
+ IN ULONG_PTR CompletionKey,
+ IN LPOVERLAPPED lpOverlapped,
+ IN ULONG NumberOfBytesTransferred, /* normally set to 0 */
+ IN ULONG NumberOfBytesToTransfer /* will become number of bytes transferred in the io operation */
+ )
+{
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %p, %ld, %ld)\n",
+ CompletionPort,
+ CompletionKey,
+ lpOverlapped,
+ NumberOfBytesTransferred,
+ NumberOfBytesToTransfer);
+
+ if (NumberOfBytesTransferred != 0)
+ {
+ FIXME("NumberOfBytesTransferred != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ SERVER_START_REQ( set_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->completion_key = (void *)CompletionKey;
+ req->overlapped = lpOverlapped;
+ req->bytes_transferred = NumberOfBytesToTransfer;
+ ret = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtRemoveIoCompletion (NTDLL.@)
+ *
+ * See: MSDN for GetQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtRemoveIoCompletion (
+ IN HANDLE CompletionPort,
+ OUT PULONG_PTR CompletionKey,
+ OUT LPOVERLAPPED * lplpOverlapped,
+ OUT PIO_STATUS_BLOCK CompletionStatus,
+ IN PLARGE_INTEGER WaitTime
+ )
+{
+ NTSTATUS ret;
+ int cookie;
+
+ TRACE("(%p, %p, %p, %p, %p)\n",
+ CompletionPort,
+ CompletionKey,
+ lplpOverlapped,
+ CompletionStatus,
+ WaitTime);
+
+ for (;;)
+ {
+ SERVER_START_REQ( remove_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->cookie = &cookie;
+ NTDLL_get_server_timeout( &req->timeout, WaitTime );
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ if (ret == STATUS_PENDING)
+ ret = NTDLL_wait_reply( &cookie );
+ if (ret == STATUS_ABANDONED)
+ {
+ SERVER_START_REQ( remove_io_completion_assigned )
+ {
+ req->handle = CompletionPort;
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ }
+ break;
+ }
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/Makefile.in wine/dlls/ntdll/Makefile.in
--- wine.orig/dlls/ntdll/Makefile.in 2004-12-07 09:47:13.000000000 -0500
+++ wine/dlls/ntdll/Makefile.in 2005-05-04 14:25:17.000000000 -0400
@@ -18,6 +18,7 @@
file.c \
handletable.c \
heap.c \
+ iocompletion.c \
large_int.c \
loader.c \
loadorder.c \
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/ntdll.spec wine/dlls/ntdll/ntdll.spec
--- wine.orig/dlls/ntdll/ntdll.spec 2005-04-22 17:17:16.000000000 -0400
+++ wine/dlls/ntdll/ntdll.spec 2005-05-04 14:24:47.000000000 -0400
@@ -86,7 +86,7 @@
@ stdcall NtCreateEvent(long long long long long)
@ stub NtCreateEventPair
@ stdcall NtCreateFile(ptr long ptr ptr long long long ptr long long ptr)
-@ stub NtCreateIoCompletion
+@ stdcall NtCreateIoCompletion(ptr long long long)
@ stdcall NtCreateKey(ptr long ptr long ptr long long)
@ stdcall NtCreateMailslotFile(long long long long long long long long)
@ stdcall NtCreateMutant(ptr long ptr long)
@@ -205,7 +205,7 @@
@ stdcall NtReleaseMutant(long ptr)
@ stub NtReleaseProcessMutant
@ stdcall NtReleaseSemaphore(long long ptr)
-@ stub NtRemoveIoCompletion
+@ stdcall NtRemoveIoCompletion(ptr ptr ptr ptr ptr)
@ stdcall NtReplaceKey(ptr long ptr)
@ stub NtReplyPort
@ stdcall NtReplyWaitReceivePort(ptr ptr ptr ptr)
@@ -234,7 +234,7 @@
@ stdcall NtSetInformationThread(long long ptr long)
@ stdcall NtSetInformationToken(long long ptr long)
@ stdcall NtSetIntervalProfile(long long)
-@ stub NtSetIoCompletion
+@ stdcall NtSetIoCompletion(ptr long ptr long long)
@ stub NtSetLdtEntries
@ stub NtSetLowEventPair
@ stub NtSetLowWaitHighEventPair
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/sync.c wine/dlls/ntdll/sync.c
--- wine.orig/dlls/ntdll/sync.c 2005-04-24 13:35:53.000000000 -0400
+++ wine/dlls/ntdll/sync.c 2005-05-04 14:27:33.000000000 -0400
@@ -611,7 +611,7 @@
*
* Wait for a reply on the waiting pipe of the current thread.
*/
-static int wait_reply( void *cookie )
+int NTDLL_wait_reply( void *cookie )
{
int signaled;
struct wake_up_reply reply;
@@ -624,7 +624,7 @@
if (!reply.cookie) break; /* thread got killed */
if (reply.cookie == cookie) return reply.signaled;
/* we stole another reply, wait for the real one */
- signaled = wait_reply( cookie );
+ signaled = NTDLL_wait_reply( cookie );
/* and now put the wrong one back in the pipe */
for (;;)
{
@@ -719,7 +719,7 @@
ret = wine_server_call( req );
}
SERVER_END_REQ;
- if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
+ if (ret == STATUS_PENDING) ret = NTDLL_wait_reply( &cookie );
if (ret != STATUS_USER_APC) break;
call_apcs( (flags & SELECT_ALERTABLE) != 0 );
if (flags & SELECT_ALERTABLE) break;
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/include/winbase.h wine/include/winbase.h
--- wine.orig/include/winbase.h 2005-04-25 12:23:32.000000000 -0400
+++ wine/include/winbase.h 2005-05-04 13:58:00.000000000 -0400
@@ -1602,6 +1602,7 @@
HANDLE WINAPI OpenWaitableTimerW(DWORD,BOOL,LPCWSTR);
#define OpenWaitableTimer WINELIB_NAME_AW(OpenWaitableTimer)
BOOL WINAPI PeekNamedPipe(HANDLE,PVOID,DWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI PostQueuedCompletionStatus(HANDLE,DWORD,ULONG_PTR,LPOVERLAPPED);
DWORD WINAPI PrepareTape(HANDLE,DWORD,BOOL);
BOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR,LPCSTR,HANDLE,PPRIVILEGE_SET,BOOL);
BOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR,LPCWSTR,HANDLE,PPRIVILEGE_SET,BOOL);
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/include/winternl.h wine/include/winternl.h
--- wine.orig/include/winternl.h 2005-04-27 04:14:18.000000000 -0400
+++ wine/include/winternl.h 2005-05-04 19:24:46.000000000 -0400
@@ -1467,7 +1467,6 @@
NTSTATUS WINAPI NtClose(HANDLE);
NTSTATUS WINAPI NtCreateEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *,BOOLEAN,BOOLEAN);
NTSTATUS WINAPI NtCreateFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
-NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,ULONG);
NTSTATUS WINAPI NtCreateKey(PHKEY,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,const UNICODE_STRING*,ULONG,PULONG);
NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG,ULONG,PLARGE_INTEGER);
NTSTATUS WINAPI NtCreateMutant(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*,BOOLEAN);
@@ -1543,7 +1542,6 @@
NTSTATUS WINAPI NtReadVirtualMemory(HANDLE,const void*,void*,SIZE_T,SIZE_T*);
NTSTATUS WINAPI NtReleaseMutant(HANDLE,PLONG);
NTSTATUS WINAPI NtReleaseSemaphore(HANDLE,ULONG,PULONG);
-NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG,PULONG,PIO_STATUS_BLOCK,PLARGE_INTEGER);
NTSTATUS WINAPI NtReplaceKey(POBJECT_ATTRIBUTES,HKEY,POBJECT_ATTRIBUTES);
NTSTATUS WINAPI NtResetEvent(HANDLE,PULONG);
NTSTATUS WINAPI NtRestoreKey(HKEY,HANDLE,ULONG);
@@ -1554,12 +1552,10 @@
NTSTATUS WINAPI NtSetDefaultUILanguage(LANGID);
NTSTATUS WINAPI NtSetEaFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG);
NTSTATUS WINAPI NtSetEvent(HANDLE,PULONG);
-NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
NTSTATUS WINAPI NtSetInformationKey(HKEY,const int,PVOID,ULONG);
NTSTATUS WINAPI NtSetInformationObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG);
NTSTATUS WINAPI NtSetInformationThread(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
NTSTATUS WINAPI NtSetInformationToken(HANDLE,TOKEN_INFORMATION_CLASS,PVOID,ULONG);
-NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG,ULONG,NTSTATUS,ULONG);
NTSTATUS WINAPI NtSetSecurityObject(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
NTSTATUS WINAPI NtSetSystemTime(const LARGE_INTEGER*,LARGE_INTEGER*);
NTSTATUS WINAPI NtSetTimer(HANDLE, const LARGE_INTEGER*, PTIMERAPCROUTINE, PVOID, BOOLEAN, ULONG, BOOLEAN*);
@@ -1968,6 +1964,23 @@
NTSTATUS WINAPI LdrUnloadDll(HMODULE);
NTSTATUS WINAPI LdrUnlockLoaderLock(ULONG,ULONG);
+/*************************************************************************
+ * I/O completion functions and structures.
+ *
+ * These are not part of standard Winternl.h
+ */
+typedef struct _FILE_COMPLETION_INFORMATION {
+ HANDLE CompletionPort;
+ ULONG_PTR CompletionKey;
+} FILE_COMPLETION_INFORMATION;
+typedef FILE_COMPLETION_INFORMATION *PFILE_COMPLETION_INFORMATION;
+
+NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,ULONG_PTR,ULONG);
+NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,LPOVERLAPPED,ULONG,ULONG);
+NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG_PTR,LPOVERLAPPED*,PIO_STATUS_BLOCK,PLARGE_INTEGER);
+NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
+
+
/* list manipulation macros */
#define InitializeListHead(le) (void)((le)->Flink = (le)->Blink = (le))
#define InsertHeadList(le,e) do { PLIST_ENTRY f = (le)->Flink; (e)->Flink = f; (e)->Blink = (le); f->Blink = (e); (le)->Flink = (e); } while (0)
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/iocompletion.c wine/server/iocompletion.c
--- wine.orig/server/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/server/iocompletion.c 2005-05-04 14:13:16.000000000 -0400
@@ -0,0 +1,282 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdio.h>
+
+#include "windef.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+#include "wine/list.h"
+
+static void io_completion_dump( struct object *obj, int verbose );
+static void io_completion_destroy( struct object *obj );
+static int io_completion_signaled( struct object * obj, struct thread * thread );
+static int io_completion_satisfied( struct object * obj, struct thread * thread );
+
+extern void select_on( int count, void *cookie, const obj_handle_t *handles,
+ int flags, const abs_time_t *timeout );
+
+struct io_completion_data
+{
+ struct list entry;
+ unsigned int bytes_transferred;
+ void * completion_key;
+ void * overlapped;
+};
+
+struct io_completion_assigned_data
+{
+ struct list entry;
+ struct thread * thread;
+ struct io_completion_data * data;
+};
+
+struct io_completion_port
+{
+ struct object obj;
+ unsigned int concurrent_threads;
+ unsigned int max_concurrent_threads; /* FIXME: should we honour this? */
+ struct list data; /* fifo queue for io_completion_data */
+
+ struct list assigned_data; /* io_completion_assigned_data */
+
+ /* Used to determine whether we have initiated the select()
+ * through GetQueuedCompletionStatus or whether the client
+ * has done WaitForSingleObject */
+ int satisfied;
+};
+
+static const struct object_ops io_completion_ops =
+{
+ sizeof(struct io_completion_port), /* size */
+ io_completion_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ io_completion_signaled, /* signaled */
+ io_completion_satisfied, /* satisfied */
+ no_get_fd, /* get_fd */
+ io_completion_destroy /* destroy */
+};
+
+static void io_completion_dump( struct object *obj, int verbose )
+{
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ fprintf( stderr, "I/O completion port max_threads=%d\n",
+ port->max_concurrent_threads);
+}
+
+static void io_completion_destroy( struct object *obj )
+{
+ struct list * current;
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+
+ /* free data queue */
+ for (current = list_head(&port->data);
+ !list_empty(&port->data); current = list_head(&port->data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_data, entry) );
+ }
+
+ /* free assigned data queue */
+ for (current = list_head(&port->assigned_data);
+ !list_empty(&port->assigned_data); current = list_head(&port->assigned_data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry)->data );
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry) );
+ }
+}
+
+static int io_completion_signaled( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return !list_empty(&port->data);
+}
+
+static int io_completion_satisfied( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return port->satisfied;
+}
+
+static struct object * create_io_completion(unsigned int concurrent_threads)
+{
+ struct io_completion_port * port;
+ if (!(port = alloc_object( &io_completion_ops )))
+ {
+ return NULL;
+ }
+
+ list_init(&port->data);
+ list_init(&port->assigned_data);
+ port->concurrent_threads = 0;
+ port->max_concurrent_threads = concurrent_threads;
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+
+ return &port->obj;
+}
+
+static void assign_data(struct io_completion_port * port, struct thread * thread)
+{
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ struct io_completion_assigned_data * assigned_data;
+ if ((assigned_data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&assigned_data->entry);
+ assigned_data->data = data;
+ assigned_data->thread = thread;
+
+ list_add_head( &port->assigned_data, &assigned_data->entry );
+
+ list_remove( &data->entry );
+ }
+}
+
+DECL_HANDLER(create_io_completion)
+{
+ struct object * obj;
+
+ reply->handle = 0;
+ if ((obj = create_io_completion(req->concurrent_threads)) != NULL)
+ {
+ reply->handle = alloc_handle(current->process, obj, req->access | SYNCHRONIZE, FALSE /*inherit flag*/);
+ release_object( obj );
+ }
+}
+
+DECL_HANDLER(remove_io_completion)
+{
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_READ,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ if (!list_empty(&port->data)) /* there is waiting data */
+ {
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ reply->bytes_transferred = data->bytes_transferred;
+ reply->completion_key = data->completion_key;
+ reply->overlapped = data->overlapped;
+ /* remove the data from the completion port */
+ list_remove( &data->entry );
+ free( data );
+ }
+ else /* there is no waiting data */
+ {
+ port->satisfied = 0; /* don't abandon wait on the port */
+ select_on(1, req->cookie, &req->handle, SELECT_TIMEOUT, &req->timeout);
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(set_io_completion)
+{
+ struct io_completion_data * data;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ return;
+
+ if ((data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&data->entry);
+ data->bytes_transferred = req->bytes_transferred;
+ data->completion_key = req->completion_key;
+ data->overlapped = req->overlapped;
+
+ list_add_tail(&port->data, &data->entry);
+
+ if (port->obj.tail != NULL) /* there is a waiting thread */
+ {
+ struct wait_queue_entry * waiting = port->obj.tail;
+ assign_data( port, waiting->thread );
+ wake_thread( waiting->thread );
+ }
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(remove_io_completion_assigned)
+{
+ struct io_completion_assigned_data * assigned_data;
+ struct list * cursor;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ LIST_FOR_EACH(cursor, &port->assigned_data)
+ {
+ assigned_data = LIST_ENTRY(cursor, struct io_completion_assigned_data, entry);
+ if (assigned_data->thread == current)
+ {
+ reply->bytes_transferred = assigned_data->data->bytes_transferred;
+ reply->completion_key = assigned_data->data->completion_key;
+ reply->overlapped = assigned_data->data->overlapped;
+ list_remove( &assigned_data->entry );
+ free( assigned_data->data );
+ free( assigned_data );
+ return;
+ }
+ }
+
+ set_error(STATUS_INVALID_PARAMETER);
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+}
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/Makefile.in wine/server/Makefile.in
--- wine.orig/server/Makefile.in 2005-03-30 14:02:15.000000000 -0500
+++ wine/server/Makefile.in 2005-05-04 14:38:33.000000000 -0400
@@ -21,6 +21,7 @@
file.c \
handle.c \
hook.c \
+ iocompletion.c \
mailslot.c \
main.c \
mapping.c \
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/request.h wine/server/request.h
--- wine.orig/server/request.h 2005-04-28 08:04:14.000000000 -0400
+++ wine/server/request.h 2005-05-04 14:40:31.000000000 -0400
@@ -280,6 +280,10 @@
DECL_HANDLER(start_hook_chain);
DECL_HANDLER(finish_hook_chain);
DECL_HANDLER(get_next_hook);
+DECL_HANDLER(create_io_completion);
+DECL_HANDLER(set_io_completion);
+DECL_HANDLER(remove_io_completion);
+DECL_HANDLER(remove_io_completion_assigned);
DECL_HANDLER(create_class);
DECL_HANDLER(destroy_class);
DECL_HANDLER(set_class_info);
@@ -476,6 +480,10 @@
(req_handler)req_start_hook_chain,
(req_handler)req_finish_hook_chain,
(req_handler)req_get_next_hook,
+ (req_handler)req_create_io_completion,
+ (req_handler)req_set_io_completion,
+ (req_handler)req_remove_io_completion,
+ (req_handler)req_remove_io_completion_assigned,
(req_handler)req_create_class,
(req_handler)req_destroy_class,
(req_handler)req_set_class_info,
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/thread.c wine/server/thread.c
--- wine.orig/server/thread.c 2005-04-24 13:35:52.000000000 -0400
+++ wine/server/thread.c 2005-05-04 14:41:21.000000000 -0400
@@ -533,7 +533,7 @@
}
/* select on a list of handles */
-static void select_on( int count, void *cookie, const obj_handle_t *handles,
+void select_on( int count, void *cookie, const obj_handle_t *handles,
int flags, const abs_time_t *timeout, obj_handle_t signal_obj )
{
int ret, i;
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/trace.c wine/server/trace.c
--- wine.orig/server/trace.c 2005-04-28 08:04:14.000000000 -0400
+++ wine/server/trace.c 2005-05-04 14:32:57.000000000 -0400
@@ -2602,6 +2602,33 @@
fprintf( stderr, " client_ptr=%p", req->client_ptr );
}
+static void dump_remove_io_completion_request( const struct remove_io_completion_request *req )
+{
+ fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " cookie=%p,", req->cookie );
+ fprintf( stderr, " timeout=" );
+ dump_abs_time( &req->timeout );
+}
+
+static void dump_remove_io_completion_reply( const struct remove_io_completion_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
+static void dump_remove_io_completion_assigned_request( const struct remove_io_completion_assigned_request *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_remove_io_completion_assigned_reply( const struct remove_io_completion_assigned_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
static void dump_set_class_info_request( const struct set_class_info_request *req )
{
fprintf( stderr, " window=%p,", req->window );
@@ -2949,6 +2976,10 @@
(dump_func)dump_start_hook_chain_request,
(dump_func)dump_finish_hook_chain_request,
(dump_func)dump_get_next_hook_request,
+ (dump_func)dump_create_io_completion_request,
+ (dump_func)dump_set_io_completion_request,
+ (dump_func)dump_remove_io_completion_request,
+ (dump_func)dump_remove_io_completion_assigned_request,
(dump_func)dump_create_class_request,
(dump_func)dump_destroy_class_request,
(dump_func)dump_set_class_info_request,
@@ -3142,6 +3173,10 @@
(dump_func)dump_start_hook_chain_reply,
(dump_func)0,
(dump_func)dump_get_next_hook_reply,
+ (dump_func)dump_create_io_completion_reply,
+ (dump_func)0,
+ (dump_func)dump_remove_io_completion_reply,
+ (dump_func)dump_remove_io_completion_assigned_reply,
(dump_func)0,
(dump_func)dump_destroy_class_reply,
(dump_func)dump_set_class_info_reply,
@@ -3335,6 +3370,10 @@
"start_hook_chain",
"finish_hook_chain",
"get_next_hook",
+ "create_io_completion",
+ "set_io_completion",
+ "remove_io_completion",
+ "remove_io_completion_assigned",
"create_class",
"destroy_class",
"set_class_info",
-------------- next part --------------
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/kernel32/iocompletion.c wine/dlls/kernel32/iocompletion.c
--- wine.orig/dlls/kernel32/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/kernel32/iocompletion.c 2005-05-04 14:08:38.000000000 -0400
@@ -0,0 +1,173 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "ntstatus.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(iocompletion);
+
+HANDLE WINAPI CreateIoCompletionPort(
+ HANDLE FileHandle,
+ HANDLE ExistingCompletionPort,
+ ULONG_PTR CompletionKey,
+ DWORD NumberOfConcurrentThreads)
+{
+ HANDLE CompletionPort;
+ NTSTATUS Status;
+
+ TRACE("(%p, %p, %lx, %ld)\n",
+ FileHandle,
+ ExistingCompletionPort,
+ CompletionKey,
+ NumberOfConcurrentThreads);
+
+ if (((FileHandle == INVALID_HANDLE_VALUE) && (ExistingCompletionPort != NULL)) ||
+ (ExistingCompletionPort == INVALID_HANDLE_VALUE))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+ if (ExistingCompletionPort == NULL)
+ {
+ Status = NtCreateIoCompletion(
+ &CompletionPort,
+ GENERIC_ALL, 0,
+ NumberOfConcurrentThreads);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ else
+ CompletionPort = ExistingCompletionPort;
+
+ if (FileHandle != INVALID_HANDLE_VALUE)
+ {
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_COMPLETION_INFORMATION CompletionInfo;
+ CompletionInfo.CompletionKey = CompletionKey;
+ CompletionInfo.CompletionPort = CompletionPort;
+
+ Status = NtSetInformationFile(
+ FileHandle,
+ &IoStatusBlock,
+ (PVOID)&CompletionInfo,
+ sizeof(FILE_COMPLETION_INFORMATION),
+ FileCompletionInformation);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ return CompletionPort;
+}
+
+BOOL WINAPI GetQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ LPDWORD lpNumberOfBytesTransferred,
+ PULONG_PTR lpCompletionKey,
+ LPOVERLAPPED * lplpOverlapped,
+ DWORD dwMilliseconds)
+{
+ IO_STATUS_BLOCK CompletionBlock;
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %p, %p, %p, %ld)\n",
+ CompletionPort,
+ lpNumberOfBytesTransferred,
+ lpCompletionKey,
+ lplpOverlapped,
+ dwMilliseconds);
+
+ if (dwMilliseconds == INFINITE)
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ NULL);
+ else
+ {
+ LARGE_INTEGER WaitTime;
+ /* multiplying two LONGLONGs with at least one LONGLONG having its
+ * higher long part not zero makes the multiplying a bit harder,
+ * therefore we do an easy multiply and negate afterwards rather than
+ * making it a hard multiply by doing "* -10000"
+ */
+ WaitTime.QuadPart = (LONGLONG)dwMilliseconds * (LONGLONG)10000;
+ WaitTime.QuadPart = -WaitTime.QuadPart;
+ Status = NtRemoveIoCompletion(
+ CompletionPort,
+ lpCompletionKey,
+ lplpOverlapped,
+ &CompletionBlock,
+ &WaitTime);
+ }
+ if (Status == STATUS_SUCCESS)
+ {
+ *lpNumberOfBytesTransferred = CompletionBlock.Information;
+ return TRUE;
+ }
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
+
+BOOL WINAPI PostQueuedCompletionStatus(
+ HANDLE CompletionPort,
+ DWORD dwNumberOfBytesTransferred,
+ ULONG_PTR dwCompletionKey,
+ LPOVERLAPPED lpOverlapped)
+{
+ NTSTATUS Status;
+
+ TRACE("(CompletionPort %p, %ld, %lx, %p)\n",
+ CompletionPort,
+ dwNumberOfBytesTransferred,
+ dwCompletionKey,
+ lpOverlapped);
+
+ Status = NtSetIoCompletion(
+ CompletionPort,
+ dwCompletionKey,
+ lpOverlapped, 0,
+ dwNumberOfBytesTransferred);
+
+ if (Status == STATUS_SUCCESS)
+ return TRUE;
+ else
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+}
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/dlls/ntdll/iocompletion.c wine/dlls/ntdll/iocompletion.c
--- wine.orig/dlls/ntdll/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/dlls/ntdll/iocompletion.c 2005-05-04 20:05:27.000000000 -0400
@@ -0,0 +1,216 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include <stdarg.h>
+
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winternl.h"
+
+#include "ntdll_misc.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+
+extern int NTDLL_wait_reply( void *cookie );
+
+/**************************************************************************
+ * NtCreateIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [O]: the handle created
+ * DesiredAccess [I}: the access desired (e.g. GENERIC_ALL)
+ * Reserved [I}: unknown
+ * NumberOfConcurrentThreads [I]: the desired number of concurrent
+ * threads
+ * Returns:
+ * Status
+ * Notes:
+ * It is effectively a FIFO queue for data and
+ * a LIFO queue for threads to "minimize context switches".
+ * The aim is to keep a small number of threads constantly
+ * active.
+ * See:
+ * MSDN for CreateIoCompletionPort spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtCreateIoCompletion (
+ OUT PHANDLE CompletionPort,
+ IN ACCESS_MASK DesiredAccess,
+ IN ULONG_PTR Reserved,
+ IN ULONG NumberOfConcurrentThreads
+ )
+ {
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %lx, %ld)\n",
+ CompletionPort,
+ DesiredAccess,
+ Reserved,
+ NumberOfConcurrentThreads);
+
+ if (Reserved != 0)
+ {
+ FIXME("Reserved != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (DesiredAccess && GENERIC_ALL)
+ DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
+
+ SERVER_START_REQ( create_io_completion )
+ {
+ req->access = DesiredAccess;
+ req->concurrent_threads = NumberOfConcurrentThreads;
+ ret = wine_server_call( req );
+ *CompletionPort = reply->handle;
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtSetIoCompletion (NTDLL.@)
+ *
+ * Params:
+ * CompletionPort [I]: port to send data to
+ * CompletionKey [I}: user key to identify this set of data
+ * lpOverlapped [I}: OVERLAPPED structure to send to port
+ * NumberOfBytesTransferred [I}: unknown - seems to be set to zero always
+ * NumberOfBytesToTransfer [I]: Bytes to transfer in this packet of data
+ * Returns:
+ * Status
+ * See:
+ * MSDN for PostQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtSetIoCompletion(
+ IN HANDLE CompletionPort,
+ IN ULONG_PTR CompletionKey,
+ IN LPOVERLAPPED lpOverlapped,
+ IN ULONG NumberOfBytesTransferred, /* normally set to 0 */
+ IN ULONG NumberOfBytesToTransfer /* will become number of bytes transferred in the io operation */
+ )
+{
+ NTSTATUS ret;
+
+ TRACE("(%p, %lx, %p, %ld, %ld)\n",
+ CompletionPort,
+ CompletionKey,
+ lpOverlapped,
+ NumberOfBytesTransferred,
+ NumberOfBytesToTransfer);
+
+ if (NumberOfBytesTransferred != 0)
+ {
+ FIXME("NumberOfBytesTransferred != 0 not supported\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ SERVER_START_REQ( set_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->completion_key = (void *)CompletionKey;
+ req->overlapped = lpOverlapped;
+ req->bytes_transferred = NumberOfBytesToTransfer;
+ ret = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
+/**************************************************************************
+ * NtRemoveIoCompletion (NTDLL.@)
+ *
+ * See: MSDN for GetQueuedCompletionStatus spec and
+ * the article "Inside I/O Completion Ports"
+ * (http://www.sysinternals.com/ntw2k/info/comport.shtml)
+ */
+NTSTATUS WINAPI NtRemoveIoCompletion (
+ IN HANDLE CompletionPort,
+ OUT PULONG_PTR CompletionKey,
+ OUT LPOVERLAPPED * lplpOverlapped,
+ OUT PIO_STATUS_BLOCK CompletionStatus,
+ IN PLARGE_INTEGER WaitTime
+ )
+{
+ NTSTATUS ret;
+ int cookie;
+
+ TRACE("(%p, %p, %p, %p, %p)\n",
+ CompletionPort,
+ CompletionKey,
+ lplpOverlapped,
+ CompletionStatus,
+ WaitTime);
+
+ for (;;)
+ {
+ SERVER_START_REQ( remove_io_completion )
+ {
+ req->handle = CompletionPort;
+ req->cookie = &cookie;
+ NTDLL_get_server_timeout( &req->timeout, WaitTime );
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ if (ret == STATUS_PENDING)
+ ret = NTDLL_wait_reply( &cookie );
+ if (ret == STATUS_ABANDONED)
+ {
+ SERVER_START_REQ( remove_io_completion_assigned )
+ {
+ req->handle = CompletionPort;
+ ret = wine_server_call( req );
+ if (ret == STATUS_SUCCESS)
+ {
+ *CompletionKey = (ULONG_PTR)reply->completion_key;
+ *lplpOverlapped = reply->overlapped;
+ CompletionStatus->u.Status = STATUS_SUCCESS;
+ CompletionStatus->Information = reply->bytes_transferred;
+ }
+ }
+ SERVER_END_REQ;
+ }
+ break;
+ }
+
+ TRACE("returning %lx\n", ret);
+ return ret;
+}
+
diff -Naur -u --exclude-from=autogen.list --exclude-from=excludes.list wine.orig/server/iocompletion.c wine/server/iocompletion.c
--- wine.orig/server/iocompletion.c 1969-12-31 19:00:00.000000000 -0500
+++ wine/server/iocompletion.c 2005-05-04 14:13:16.000000000 -0400
@@ -0,0 +1,282 @@
+/*
+ * I/O Completion Ports
+ *
+ * Copyright (C) 2003 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdio.h>
+
+#include "windef.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+#include "wine/list.h"
+
+static void io_completion_dump( struct object *obj, int verbose );
+static void io_completion_destroy( struct object *obj );
+static int io_completion_signaled( struct object * obj, struct thread * thread );
+static int io_completion_satisfied( struct object * obj, struct thread * thread );
+
+extern void select_on( int count, void *cookie, const obj_handle_t *handles,
+ int flags, const abs_time_t *timeout );
+
+struct io_completion_data
+{
+ struct list entry;
+ unsigned int bytes_transferred;
+ void * completion_key;
+ void * overlapped;
+};
+
+struct io_completion_assigned_data
+{
+ struct list entry;
+ struct thread * thread;
+ struct io_completion_data * data;
+};
+
+struct io_completion_port
+{
+ struct object obj;
+ unsigned int concurrent_threads;
+ unsigned int max_concurrent_threads; /* FIXME: should we honour this? */
+ struct list data; /* fifo queue for io_completion_data */
+
+ struct list assigned_data; /* io_completion_assigned_data */
+
+ /* Used to determine whether we have initiated the select()
+ * through GetQueuedCompletionStatus or whether the client
+ * has done WaitForSingleObject */
+ int satisfied;
+};
+
+static const struct object_ops io_completion_ops =
+{
+ sizeof(struct io_completion_port), /* size */
+ io_completion_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ io_completion_signaled, /* signaled */
+ io_completion_satisfied, /* satisfied */
+ no_get_fd, /* get_fd */
+ io_completion_destroy /* destroy */
+};
+
+static void io_completion_dump( struct object *obj, int verbose )
+{
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ fprintf( stderr, "I/O completion port max_threads=%d\n",
+ port->max_concurrent_threads);
+}
+
+static void io_completion_destroy( struct object *obj )
+{
+ struct list * current;
+ struct io_completion_port *port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+
+ /* free data queue */
+ for (current = list_head(&port->data);
+ !list_empty(&port->data); current = list_head(&port->data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_data, entry) );
+ }
+
+ /* free assigned data queue */
+ for (current = list_head(&port->assigned_data);
+ !list_empty(&port->assigned_data); current = list_head(&port->assigned_data))
+ {
+ list_remove(current);
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry)->data );
+ free( LIST_ENTRY(current, struct io_completion_assigned_data, entry) );
+ }
+}
+
+static int io_completion_signaled( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return !list_empty(&port->data);
+}
+
+static int io_completion_satisfied( struct object * obj, struct thread * thread )
+{
+ struct io_completion_port * port = (struct io_completion_port *)obj;
+ assert( obj->ops == &io_completion_ops );
+ return port->satisfied;
+}
+
+static struct object * create_io_completion(unsigned int concurrent_threads)
+{
+ struct io_completion_port * port;
+ if (!(port = alloc_object( &io_completion_ops )))
+ {
+ return NULL;
+ }
+
+ list_init(&port->data);
+ list_init(&port->assigned_data);
+ port->concurrent_threads = 0;
+ port->max_concurrent_threads = concurrent_threads;
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+
+ return &port->obj;
+}
+
+static void assign_data(struct io_completion_port * port, struct thread * thread)
+{
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ struct io_completion_assigned_data * assigned_data;
+ if ((assigned_data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&assigned_data->entry);
+ assigned_data->data = data;
+ assigned_data->thread = thread;
+
+ list_add_head( &port->assigned_data, &assigned_data->entry );
+
+ list_remove( &data->entry );
+ }
+}
+
+DECL_HANDLER(create_io_completion)
+{
+ struct object * obj;
+
+ reply->handle = 0;
+ if ((obj = create_io_completion(req->concurrent_threads)) != NULL)
+ {
+ reply->handle = alloc_handle(current->process, obj, req->access | SYNCHRONIZE, FALSE /*inherit flag*/);
+ release_object( obj );
+ }
+}
+
+DECL_HANDLER(remove_io_completion)
+{
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_READ,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ if (!list_empty(&port->data)) /* there is waiting data */
+ {
+ struct io_completion_data * data =
+ LIST_ENTRY(list_head(&port->data), struct io_completion_data, entry);
+ reply->bytes_transferred = data->bytes_transferred;
+ reply->completion_key = data->completion_key;
+ reply->overlapped = data->overlapped;
+ /* remove the data from the completion port */
+ list_remove( &data->entry );
+ free( data );
+ }
+ else /* there is no waiting data */
+ {
+ port->satisfied = 0; /* don't abandon wait on the port */
+ select_on(1, req->cookie, &req->handle, SELECT_TIMEOUT, &req->timeout);
+ port->satisfied = 1; /* abandon any waits on the port immediately */
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(set_io_completion)
+{
+ struct io_completion_data * data;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ return;
+
+ if ((data = mem_alloc(sizeof(*data))) != NULL)
+ {
+ list_init(&data->entry);
+ data->bytes_transferred = req->bytes_transferred;
+ data->completion_key = req->completion_key;
+ data->overlapped = req->overlapped;
+
+ list_add_tail(&port->data, &data->entry);
+
+ if (port->obj.tail != NULL) /* there is a waiting thread */
+ {
+ struct wait_queue_entry * waiting = port->obj.tail;
+ assign_data( port, waiting->thread );
+ wake_thread( waiting->thread );
+ }
+ }
+ release_object( &port->obj );
+}
+
+DECL_HANDLER(remove_io_completion_assigned)
+{
+ struct io_completion_assigned_data * assigned_data;
+ struct list * cursor;
+ struct io_completion_port * port = (struct io_completion_port *)get_handle_obj(
+ current->process,
+ req->handle,
+ GENERIC_WRITE,
+ &io_completion_ops);
+
+ if (!port)
+ {
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+ return;
+ }
+
+ LIST_FOR_EACH(cursor, &port->assigned_data)
+ {
+ assigned_data = LIST_ENTRY(cursor, struct io_completion_assigned_data, entry);
+ if (assigned_data->thread == current)
+ {
+ reply->bytes_transferred = assigned_data->data->bytes_transferred;
+ reply->completion_key = assigned_data->data->completion_key;
+ reply->overlapped = assigned_data->data->overlapped;
+ list_remove( &assigned_data->entry );
+ free( assigned_data->data );
+ free( assigned_data );
+ return;
+ }
+ }
+
+ set_error(STATUS_INVALID_PARAMETER);
+ reply->bytes_transferred = 0;
+ reply->completion_key = NULL;
+ reply->overlapped = NULL;
+}
-------------- next part --------------
diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in
index c725509..be5da9e 100644
--- a/dlls/kernel32/Makefile.in
+++ b/dlls/kernel32/Makefile.in
@@ -35,6 +35,7 @@ C_SRCS = \
file.c \
file16.c \
format_msg.c \
+ iocompletion.c \
global16.c \
heap.c \
instr.c \
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 7502bb8..76ee2dc 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -828,6 +828,7 @@ # @ stub NumaVirtualQueryNode
@ stdcall PeekConsoleInputA(ptr ptr long ptr)
@ stdcall PeekConsoleInputW(ptr ptr long ptr)
@ stdcall PeekNamedPipe(long ptr long ptr ptr ptr)
+# PATCH: @ stdcall PostQueuedCompletionStatus(ptr long long ptr)
@ stdcall PostQueuedCompletionStatus(long long ptr ptr)
@ stdcall PrepareTape(ptr long long)
@ stub PrivCopyFileExW
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index eaa0f70..c517744 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -1766,41 +1766,6 @@ BOOL WINAPI SetMailslotInfo( HANDLE hMai
return TRUE;
}
-
-/******************************************************************************
- * CreateIoCompletionPort (KERNEL32.@)
- */
-HANDLE WINAPI CreateIoCompletionPort(HANDLE hFileHandle, HANDLE hExistingCompletionPort,
- ULONG_PTR CompletionKey, DWORD dwNumberOfConcurrentThreads)
-{
- FIXME("(%p, %p, %08lx, %08x): stub.\n",
- hFileHandle, hExistingCompletionPort, CompletionKey, dwNumberOfConcurrentThreads);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return NULL;
-}
-
-
-/******************************************************************************
- * GetQueuedCompletionStatus (KERNEL32.@)
- */
-BOOL WINAPI GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred,
- PULONG_PTR pCompletionKey, LPOVERLAPPED *lpOverlapped,
- DWORD dwMilliseconds )
-{
- FIXME("(%p,%p,%p,%p,%d), stub!\n",
- CompletionPort,lpNumberOfBytesTransferred,pCompletionKey,lpOverlapped,dwMilliseconds);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
-BOOL WINAPI PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD dwNumberOfBytes,
- ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped)
-{
- FIXME("%p %d %08lx %p\n", CompletionPort, dwNumberOfBytes, dwCompletionKey, lpOverlapped );
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
-
/******************************************************************************
* CreateJobObjectW (KERNEL32.@)
*/
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 37b18f1..7496930 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -21,6 +21,7 @@ C_SRCS = \
file.c \
handletable.c \
heap.c \
+ iocompletion.c \
large_int.c \
loader.c \
loadorder.c \
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 803ed53..baf5ff8 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -124,6 +124,7 @@ # @ stub NtCreateDebugObject
@ stdcall NtCreateEvent(long long long long long)
@ stub NtCreateEventPair
@ stdcall NtCreateFile(ptr long ptr ptr long long long ptr long long ptr)
+# PATCH: @ stdcall NtCreateIoCompletion(ptr long long long)
@ stdcall NtCreateIoCompletion(ptr long ptr long)
# @ stub NtCreateJobObject
# @ stub NtCreateJobSet
@@ -328,6 +329,7 @@ # @ stub NtSetInformationJobObject
@ stdcall NtSetInformationThread(long long ptr long)
@ stdcall NtSetInformationToken(long long ptr long)
@ stdcall NtSetIntervalProfile(long long)
+# PATCH: @ stdcall NtSetIoCompletion(ptr long ptr long long)
@ stdcall NtSetIoCompletion(ptr long ptr long long)
@ stub NtSetLdtEntries
@ stub NtSetLowEventPair
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 852bfde..bc0470b 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -618,7 +618,7 @@ NTSTATUS WINAPI NtSetTimerResolution(IN
*
* Wait for a reply on the waiting pipe of the current thread.
*/
-static int wait_reply( void *cookie )
+int NTDLL_wait_reply( void *cookie )
{
int signaled;
struct wake_up_reply reply;
@@ -631,7 +631,7 @@ static int wait_reply( void *cookie )
if (!reply.cookie) break; /* thread got killed */
if (reply.cookie == cookie) return reply.signaled;
/* we stole another reply, wait for the real one */
- signaled = wait_reply( cookie );
+ signaled = NTDLL_wait_reply( cookie );
/* and now put the wrong one back in the pipe */
for (;;)
{
@@ -726,7 +726,7 @@ NTSTATUS NTDLL_wait_for_multiple_objects
ret = wine_server_call( req );
}
SERVER_END_REQ;
- if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
+ if (ret == STATUS_PENDING) ret = NTDLL_wait_reply( &cookie );
if (ret != STATUS_USER_APC) break;
call_apcs( (flags & SELECT_ALERTABLE) != 0 );
if (flags & SELECT_ALERTABLE) break;
diff --git a/include/winternl.h b/include/winternl.h
index 19b2ac9..d27d4f2 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1763,7 +1763,6 @@ NTSTATUS WINAPI NtCreateDirectoryObject
NTSTATUS WINAPI NtCreateEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *,BOOLEAN,BOOLEAN);
NTSTATUS WINAPI NtCreateEventPair(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES);
NTSTATUS WINAPI NtCreateFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
-NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,ULONG);
NTSTATUS WINAPI NtCreateKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,const UNICODE_STRING*,ULONG,PULONG);
NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG,ULONG,PLARGE_INTEGER);
NTSTATUS WINAPI NtCreateMutant(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*,BOOLEAN);
@@ -1882,7 +1881,6 @@ NTSTATUS WINAPI NtReadVirtualMemory(HAN
NTSTATUS WINAPI NtRegisterThreadTerminatePort(HANDLE);
NTSTATUS WINAPI NtReleaseMutant(HANDLE,PLONG);
NTSTATUS WINAPI NtReleaseSemaphore(HANDLE,ULONG,PULONG);
-NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG_PTR,PIO_STATUS_BLOCK,PULONG,PLARGE_INTEGER);
NTSTATUS WINAPI NtReplaceKey(POBJECT_ATTRIBUTES,HANDLE,POBJECT_ATTRIBUTES);
NTSTATUS WINAPI NtReplyPort(HANDLE,PLPC_MESSAGE);
NTSTATUS WINAPI NtReplyWaitReceivePort(HANDLE,PULONG,PLPC_MESSAGE,PLPC_MESSAGE);
@@ -1904,14 +1902,12 @@ NTSTATUS WINAPI NtSetEvent(HANDLE,PULON
NTSTATUS WINAPI NtSetHighEventPair(HANDLE);
NTSTATUS WINAPI NtSetHighWaitLowEventPair(HANDLE);
NTSTATUS WINAPI NtSetHighWaitLowThread(VOID);
-NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
NTSTATUS WINAPI NtSetInformationKey(HANDLE,const int,PVOID,ULONG);
NTSTATUS WINAPI NtSetInformationObject(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG);
NTSTATUS WINAPI NtSetInformationProcess(HANDLE,PROCESS_INFORMATION_CLASS,PVOID,ULONG);
NTSTATUS WINAPI NtSetInformationThread(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
NTSTATUS WINAPI NtSetInformationToken(HANDLE,TOKEN_INFORMATION_CLASS,PVOID,ULONG);
NTSTATUS WINAPI NtSetIntervalProfile(ULONG,KPROFILE_SOURCE);
-NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,PIO_STATUS_BLOCK,ULONG,ULONG);
NTSTATUS WINAPI NtSetLdtEntries(ULONG,LDT_ENTRY,ULONG,LDT_ENTRY);
NTSTATUS WINAPI NtSetLowEventPair(HANDLE);
NTSTATUS WINAPI NtSetLowWaitHighEventPair(HANDLE);
@@ -2367,11 +2363,21 @@ NTSTATUS WINAPI LdrQueryProcessModuleInf
NTSTATUS WINAPI LdrUnloadDll(HMODULE);
NTSTATUS WINAPI LdrUnlockLoaderLock(ULONG,ULONG);
+/*************************************************************************
+ * I/O completion functions and structures.
+ *
+ * These are not part of standard Winternl.h
+ */
typedef struct _FILE_COMPLETION_INFORMATION {
HANDLE CompletionPort;
ULONG_PTR CompletionKey;
} FILE_COMPLETION_INFORMATION;
typedef FILE_COMPLETION_INFORMATION *PFILE_COMPLETION_INFORMATION;
+NTSTATUS WINAPI NtCreateIoCompletion(PHANDLE,ACCESS_MASK,ULONG_PTR,ULONG);
+NTSTATUS WINAPI NtSetIoCompletion(HANDLE,ULONG_PTR,LPOVERLAPPED,ULONG,ULONG);
+NTSTATUS WINAPI NtRemoveIoCompletion(HANDLE,PULONG_PTR,LPOVERLAPPED*,PIO_STATUS_BLOCK,PLARGE_INTEGER);
+NTSTATUS WINAPI NtSetInformationFile(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
+
/* list manipulation macros */
#define InitializeListHead(le) (void)((le)->Flink = (le)->Blink = (le))
diff --git a/server/Makefile.in b/server/Makefile.in
index f62bd1d..2c0daa4 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -24,6 +24,7 @@ C_SRCS = \
file.c \
handle.c \
hook.c \
+ iocompletion.c \
mailslot.c \
main.c \
mapping.c \
diff --git a/server/request.h b/server/request.h
index 8cfeccd..c6b6a8b 100644
--- a/server/request.h
+++ b/server/request.h
@@ -302,6 +302,10 @@ DECL_HANDLER(remove_hook);
DECL_HANDLER(start_hook_chain);
DECL_HANDLER(finish_hook_chain);
DECL_HANDLER(get_hook_info);
+DECL_HANDLER(create_io_completion);
+DECL_HANDLER(set_io_completion);
+DECL_HANDLER(remove_io_completion);
+DECL_HANDLER(remove_io_completion_assigned);
DECL_HANDLER(create_class);
DECL_HANDLER(destroy_class);
DECL_HANDLER(set_class_info);
@@ -521,6 +525,10 @@ static const req_handler req_handlers[RE
(req_handler)req_start_hook_chain,
(req_handler)req_finish_hook_chain,
(req_handler)req_get_hook_info,
+ (req_handler)req_create_io_completion,
+ (req_handler)req_set_io_completion,
+ (req_handler)req_remove_io_completion,
+ (req_handler)req_remove_io_completion_assigned,
(req_handler)req_create_class,
(req_handler)req_destroy_class,
(req_handler)req_set_class_info,
diff --git a/server/thread.c b/server/thread.c
index 05cf3cd..8581b0b 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -548,7 +548,7 @@ static int signal_object( obj_handle_t h
}
/* select on a list of handles */
-static void select_on( int count, void *cookie, const obj_handle_t *handles,
+void select_on( int count, void *cookie, const obj_handle_t *handles,
int flags, const abs_time_t *timeout, obj_handle_t signal_obj )
{
int ret, i;
diff --git a/server/trace.c b/server/trace.c
index b128ad5..1dd2f1b 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2975,6 +2975,33 @@ static void dump_destroy_class_reply( co
fprintf( stderr, " client_ptr=%p", req->client_ptr );
}
+static void dump_remove_io_completion_request( const struct remove_io_completion_request *req )
+{
+ fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " cookie=%p,", req->cookie );
+ fprintf( stderr, " timeout=" );
+ dump_abs_time( &req->timeout );
+}
+
+static void dump_remove_io_completion_reply( const struct remove_io_completion_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
+static void dump_remove_io_completion_assigned_request( const struct remove_io_completion_assigned_request *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_remove_io_completion_assigned_reply( const struct remove_io_completion_assigned_reply *req )
+{
+ fprintf( stderr, " bytes_transferred=%08x,", req->bytes_transferred );
+ fprintf( stderr, " completion_key=%p,", req->completion_key );
+ fprintf( stderr, " overlapped=%p", req->overlapped );
+}
+
static void dump_set_class_info_request( const struct set_class_info_request *req )
{
fprintf( stderr, " window=%p,", req->window );
@@ -3456,6 +3483,10 @@ static const dump_func req_dumpers[REQ_N
(dump_func)dump_start_hook_chain_request,
(dump_func)dump_finish_hook_chain_request,
(dump_func)dump_get_hook_info_request,
+ (dump_func)dump_create_io_completion_request,
+ (dump_func)dump_set_io_completion_request,
+ (dump_func)dump_remove_io_completion_request,
+ (dump_func)dump_remove_io_completion_assigned_request,
(dump_func)dump_create_class_request,
(dump_func)dump_destroy_class_request,
(dump_func)dump_set_class_info_request,
@@ -3672,6 +3703,10 @@ static const dump_func reply_dumpers[REQ
(dump_func)dump_start_hook_chain_reply,
(dump_func)0,
(dump_func)dump_get_hook_info_reply,
+ (dump_func)dump_create_io_completion_reply,
+ (dump_func)0,
+ (dump_func)dump_remove_io_completion_reply,
+ (dump_func)dump_remove_io_completion_assigned_reply,
(dump_func)0,
(dump_func)dump_destroy_class_reply,
(dump_func)dump_set_class_info_reply,
@@ -3888,6 +3923,10 @@ static const char * const req_names[REQ_
"start_hook_chain",
"finish_hook_chain",
"get_hook_info",
+ "create_io_completion",
+ "set_io_completion",
+ "remove_io_completion",
+ "remove_io_completion_assigned",
"create_class",
"destroy_class",
"set_class_info",
More information about the wine-devel
mailing list