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
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",
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; +}
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",