This is the server / NTDLL code of my implementation of I/O completion ports. I have tried to make it patch against current CVS where possible, but I have a week old snapshot on my development machine at the moment :( There is one thing not implemented by this patch (the NumberOfConcurrentThreads parameter) which is pretty much optional anyway and is only a performance affecting thing. I will probably submit a patch to implement this if these two patches are accepted. ChangeLog: - Add server support for I/O completion ports License: - LGPL Rob
diff -r -u -x *.o wine/dlls/ntdll/Makefile.in newwine/dlls/ntdll/Makefile.in --- wine/dlls/ntdll/Makefile.in Fri Mar 21 15:37:41 2003 +++ newwine/dlls/ntdll/Makefile.in Fri Mar 21 15:39:46 2003 @@ -79,6 +79,7 @@ error.c \ file.c \ heap.c \ + iocompletion.c \ large_int.c \ loader.c \ misc.c \ diff -r -u -x *.o wine/dlls/ntdll/error.c newwine/dlls/ntdll/error.c --- wine/dlls/ntdll/error.c Fri Mar 21 15:37:41 2003 +++ newwine/dlls/ntdll/error.c Sat Mar 22 22:32:50 2003 @@ -69,8 +69,9 @@ /* conversion tables */ -static const DWORD table_00000103[31] = +static const DWORD table_00000102[32] = { + ERROR_TIMEOUT, /* 00000102 (STATUS_TIMEOUT) */ ERROR_IO_PENDING, /* 00000103 (STATUS_PENDING) */ ERROR_MR_MID_NOT_FOUND, /* 00000104 */ ERROR_MORE_DATA, /* 00000105 (STATUS_MORE_ENTRIES) */ @@ -1333,7 +1334,7 @@ static const struct error_table error_table[] = { - { 0x00000103, 0x00000122, table_00000103 }, + { 0x00000102, 0x00000122, table_00000102 }, { 0x40000002, 0x4000000e, table_40000002 }, { 0x40000370, 0x40000371, table_40000370 }, { 0x40020056, 0x40020057, table_40020056 }, diff -r -u -x *.o wine/dlls/ntdll/ntdll.spec newwine/dlls/ntdll/ntdll.spec --- wine/dlls/ntdll/ntdll.spec Fri Mar 21 15:37:41 2003 +++ newwine/dlls/ntdll/ntdll.spec Sat Mar 22 20:03:00 2003 @@ -77,7 +77,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(long long long long long long long) @ stdcall NtCreateMailslotFile(long long long long long long long long) @ stub NtCreateMutant @@ -189,7 +189,7 @@ @ stub NtReleaseMutant @ 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) @@ -217,7 +217,7 @@ @ stdcall NtSetInformationThread(long long long long) @ stub NtSetInformationToken @ stdcall NtSetIntervalProfile(long long) -@ stub NtSetIoCompletion +@ stdcall NtSetIoCompletion(ptr long ptr long long) @ stub NtSetLdtEntries @ stub NtSetLowEventPair @ stub NtSetLowWaitHighEventPair diff -r -u -x *.o wine/server/Makefile.in newwine/server/Makefile.in --- wine/server/Makefile.in Wed Feb 19 20:10:11 2003 +++ newwine/server/Makefile.in Fri Mar 21 14:10:26 2003 @@ -20,6 +20,7 @@ file.c \ handle.c \ hook.c \ + iocompletion.c \ main.c \ mapping.c \ mutex.c \ diff -r -u -x *.o wine/server/protocol.def newwine/server/protocol.def --- wine/server/protocol.def Fri Mar 21 14:40:52 2003 +++ newwine/server/protocol.def Fri Mar 21 16:00:56 2003 @@ -144,6 +144,17 @@ int signaled; /* wait result */ }; +/* structure sent by the server to send the + * io completion data to a waiting thread */ +struct io_completion_send_data_reply +{ + void *cookie; /* magic cookie that was passed in select_request */ + int signaled; /* wait result */ + unsigned int bytes_transferred; + void * completion_key; + void * overlapped; +}; + /* structure for process startup info */ typedef struct { diff -r -u -x *.o wine/server/thread.c newwine/server/thread.c --- wine/server/thread.c Fri Mar 21 14:09:22 2003 +++ newwine/server/thread.c Fri Mar 21 16:05:46 2003 @@ -41,6 +41,7 @@ #include "thread.h" #include "request.h" #include "user.h" +#include "iocompletion.h" /* thread queues */ @@ -1013,3 +1014,53 @@ release_object( thread ); } } + +/* adds a timeout for a thread waiting for data to be + * sent to an io completion port */ +void io_completion_sleep(void * cookie, int sec, int usec) +{ + select_on(0, cookie, NULL, SELECT_TIMEOUT, sec, usec); +} + + +/* send the wakeup signal and io completion data to a thread */ +static int io_completion_send_data( struct thread *thread, void *cookie, struct io_completion_data * data ) +{ + struct io_completion_send_data_reply reply; + int ret; + + reply.cookie = cookie; + reply.signaled = STATUS_SUCCESS; + reply.bytes_transferred = data->bytes_transferred; + reply.completion_key = data->completion_key; + reply.overlapped = data->overlapped; + if ((ret = write( get_unix_fd( thread->wait_fd ), &reply, sizeof(reply) )) == sizeof(reply)) + return 0; + if (ret >= 0) + fatal_protocol_error( thread, "partial wakeup write %d\n", ret ); + else if (errno == EPIPE) + kill_thread( thread, 0 ); /* normal death */ + else + fatal_protocol_perror( thread, "write" ); + return -1; +} + +/* attempt to wake up a thread */ +/* return >0 if OK, 0 if the wait condition is still not satisfied */ +int io_completion_send_data_wakeup( struct thread *thread, struct io_completion_data *data ) +{ + int count; + void *cookie; + + for (count = 0; thread->wait; count++) + { + cookie = thread->wait->cookie; + if (debug_level) fprintf( stderr, "%04x: *i/o completion wakeup* cookie=%p\n", + thread->id, cookie ); + end_wait( thread ); + if (io_completion_send_data( thread, cookie, data ) == -1) /* error */ + break; + } + return count; +} + --- /dev/null Mon Jun 24 01:53:01 2002 +++ wine/dlls/ntdll/iocompletion.c Sat Mar 22 21:24:27 2003 @@ -0,0 +1,297 @@ +/* + * 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 "winbase.h" +#include "winnt.h" +#include "winternl.h" + +#include "config.h" + +#include <assert.h> +#include <errno.h> +#include <signal.h> +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#ifdef HAVE_SYS_POLL_H +# include <sys/poll.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include "wine/server.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ntdll); + +/************************************************************************** + * 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); + + WARN("NumberOfConcurrentThreads ignored - performance issue only\n"); + + 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; +} + +inline static void reliable_write(void * data, size_t size) +{ + int ret; + if (size <= 0) + return; + for (;;) + { + ret = write( NtCurrentTeb()->wait_fd[1], data, size ); + if (ret == size) break; + if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret ); + if (errno == EINTR) continue; + server_protocol_perror("wakeup write"); + } +} + +/*********************************************************************** + * wait_data_or_wakeup_reply + * + * Wait for a reply on the waiting pipe of the current thread. + */ +static int wait_data_or_wakeup_reply( void *cookie, struct io_completion_send_data_reply * data_reply ) +{ + struct io_completion_send_data_reply reply; + for (;;) + { + int ret; + int retval; + ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) ); + if ((ret == sizeof(struct wake_up_reply)) || + (ret == sizeof(reply)) ) + { + if (!reply.cookie) break; /* thread got killed */ + if (reply.cookie == cookie) + { + if ((reply.signaled == STATUS_SUCCESS) && (ret == sizeof(reply))) + { + RtlCopyMemory(data_reply, &reply, sizeof(reply)); + return reply.signaled; + } + else + { + /* have to put the extra bit of data back in */ + reliable_write(((char *)&reply)+sizeof(struct wake_up_reply), + ret - sizeof(struct wake_up_reply)); + return reply.signaled; + } + } + /* we stole another reply, wait for the real one */ + retval = wait_data_or_wakeup_reply( cookie, data_reply ); + /* and now put the wrong one back in the pipe */ + reliable_write(&reply, sizeof(reply)); + return retval; + } + if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret ); + if (errno == EINTR) continue; + server_protocol_perror("wakeup read"); + } + /* the server closed the connection; time to die... */ + SYSDEPS_AbortThread(0); +} + +/*********************************************************************** + * get_timeout + */ +inline static void get_timeout( struct timeval *when, int timeout ) +{ + gettimeofday( when, 0 ); + if (timeout) + { + long sec = timeout / 1000; + if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000) + { + when->tv_usec -= 1000000; + when->tv_sec++; + } + when->tv_sec += sec; + } +} + +/************************************************************************** + * 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; + struct timeval tv; + int cookie; + + TRACE("(%p, %p, %p, %p, %p)\n", + CompletionPort, + CompletionKey, + lplpOverlapped, + CompletionStatus, + WaitTime); + + if (WaitTime == NULL) tv.tv_sec = tv.tv_usec = 0; /* INFINITE */ + else get_timeout( &tv, - WaitTime->QuadPart / 10000 ); + + SERVER_START_REQ( remove_io_completion ) + { + req->handle = CompletionPort; + req->sec = tv.tv_sec; + req->usec = tv.tv_usec; + req->cookie = &cookie; + 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) + { + struct io_completion_send_data_reply data; + ret = wait_data_or_wakeup_reply(&cookie, &data); + if (ret == STATUS_SUCCESS) + { + *CompletionKey = (ULONG_PTR)data.completion_key; + *lplpOverlapped = data.overlapped; + CompletionStatus = STATUS_SUCCESS; + CompletionStatus->Information = data.bytes_transferred; + } + } + + TRACE("returning %lx\n", ret); + return ret; +} --- /dev/null Mon Jun 24 01:53:01 2002 +++ wine/server/iocompletion.c Sat Mar 22 20:23:11 2003 @@ -0,0 +1,192 @@ +/* + * 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 "iocompletion.h" + +static void io_completion_dump( struct object *obj, int verbose ); +extern void io_completion_sleep(void * cookie, int sec, int usec); +extern int io_completion_send_data_wakeup( struct thread *thread, struct io_completion_data *data ); + +struct io_completion_wait_queue +{ + struct list entry; + struct thread * thread; +}; + +struct io_completion_port +{ + struct object obj; + unsigned int concurrent_threads; + unsigned int max_concurrent_threads; /* should we honour this? */ + struct io_completion_data * data_head; /* fifo queue for data */ + struct io_completion_data * data_tail; + + /* lifo queue for threads to 'minimize context switches'*/ + struct io_completion_wait_queue * wait_head; +}; + +static const struct object_ops io_completion_ops = +{ + sizeof(struct io_completion_port), /* size */ + io_completion_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + no_satisfied, /* satisfied */ + no_get_fd, /* get_fd */ + no_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 data_head=%p data_tail=%p wait_head=%p\n", + port->max_concurrent_threads, port->data_head, port->data_tail, port->wait_head ); +} + +static struct object * create_io_completion(unsigned int concurrent_threads) +{ + struct io_completion_port * port; + if (!(port = alloc_object( &io_completion_ops ))) + { + return NULL; + } + + port->data_head = NULL; + port->data_tail = NULL; + port->wait_head = NULL; + port->concurrent_threads = 0; + port->max_concurrent_threads = concurrent_threads; + + return &port->obj; +} + +DECL_HANDLER(create_io_completion) +{ + struct object * obj; + fprintf(stderr, "Point 1\n"); + + reply->handle = 0; + if ((obj = create_io_completion(req->concurrent_threads)) != NULL) + { + fprintf(stderr, "Point 2\n"); + reply->handle = alloc_handle(current->process, obj, req->access, FALSE /*inherit flag*/); + fprintf(stderr, "Point 3\n"); + 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 (port->data_head) /* there is waiting data */ + { + struct io_completion_data * data = port->data_head; + reply->bytes_transferred = data->bytes_transferred; + reply->completion_key = data->completion_key; + reply->overlapped = data->overlapped; + port->data_head = (struct io_completion_data *) + list_next( &data->entry, &data->entry ); + if (port->data_tail == data) /* i.e. we removed the last one */ + port->data_tail = port->data_head; /* port->data_head should be NULL */ + free( data ); + } + else /* there is no waiting data */ + { + struct io_completion_wait_queue * waiting_thread; + if ( (waiting_thread = mem_alloc( sizeof(*waiting_thread) )) != NULL ) + { + list_init(&waiting_thread->entry); + waiting_thread->thread = current; + io_completion_sleep(req->cookie, req->sec, req->usec); + reply->bytes_transferred = 0; + reply->completion_key = NULL; + reply->overlapped = NULL; + set_error( STATUS_PENDING ); + } + } + 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; + + if (port->wait_head == NULL) /* there is no waiting thread */ + { + if (port->data_head == NULL) /* need to update head as well */ + port->data_head = data; + else /* need to update existing data to reflect new data added */ + list_add_tail(&port->data_tail->entry, &data->entry); + + port->data_tail = data; + } + else /* there is a waiting thread */ + { + struct io_completion_wait_queue * head = port->wait_head; + struct thread * waiting_thread = head->thread; + port->wait_head = (struct io_completion_wait_queue *) + list_next( &head->entry, &head->entry ); + io_completion_send_data_wakeup( waiting_thread, data ); + free( data ); + free( head ); + } + } + release_object( &port->obj ); +} --- /dev/null Mon Jun 24 01:53:01 2002 +++ wine/server/iocompletion.h Fri Mar 21 14:51:05 2003 @@ -0,0 +1,29 @@ +/* + * 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 "list.h" + +struct io_completion_data +{ + struct list entry; + unsigned int bytes_transferred; + void * completion_key; + void * overlapped; +}; --- wine/include/wine/server_protocol.h Sun Mar 23 22:15:31 2003 +++ newwine/include/wine/server_protocol.h Sun Mar 23 22:14:45 2003 @@ -128,6 +128,17 @@ int signaled; }; +/* structure sent by the server to send the + * io completion data to a waiting thread */ +struct io_completion_send_data_reply +{ + void *cookie; + int signaled; + unsigned int bytes_transferred; + void * completion_key; + void * overlapped; +}; + typedef struct { @@ -3012,6 +3023,47 @@ /* VARARG(module,unicode_str); */ }; +struct create_io_completion_request +{ + struct request_header __header; + unsigned int access; + unsigned int concurrent_threads; +}; +struct create_io_completion_reply +{ + struct reply_header __header; + user_handle_t handle; +}; + +struct set_io_completion_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int bytes_transferred; + void* completion_key; + void* overlapped; +}; +struct set_io_completion_reply +{ + struct reply_header __header; +}; + +struct remove_io_completion_request +{ + struct request_header __header; + user_handle_t handle; + void* cookie; + int sec; + int usec; +}; +struct remove_io_completion_reply +{ + struct reply_header __header; + unsigned int bytes_transferred; + void* completion_key; + void* overlapped; +}; + enum request { @@ -3189,6 +3241,9 @@ REQ_start_hook_chain, REQ_finish_hook_chain, REQ_get_next_hook, + REQ_create_io_completion, + REQ_set_io_completion, + REQ_remove_io_completion, REQ_NB_REQUESTS }; @@ -3370,6 +3425,9 @@ struct start_hook_chain_request start_hook_chain_request; struct finish_hook_chain_request finish_hook_chain_request; struct get_next_hook_request get_next_hook_request; + struct create_io_completion_request create_io_completion_request; + struct set_io_completion_request set_io_completion_request; + struct remove_io_completion_request remove_io_completion_request; }; union generic_reply { @@ -3549,8 +3607,11 @@ struct start_hook_chain_reply start_hook_chain_reply; struct finish_hook_chain_reply finish_hook_chain_reply; struct get_next_hook_reply get_next_hook_reply; + struct create_io_completion_reply create_io_completion_reply; + struct set_io_completion_reply set_io_completion_reply; + struct remove_io_completion_reply remove_io_completion_reply; }; -#define SERVER_PROTOCOL_VERSION 102 +#define SERVER_PROTOCOL_VERSION 103 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ --- wine/include/winternl.h Sun Mar 23 22:46:44 2003 +++ newwine/include/winternl.h Sun Mar 23 22:46:28 2003 @@ -1234,6 +1234,22 @@ NTSTATUS WINAPI LdrUnloadDll(HMODULE); NTSTATUS WINAPI LdrUnlockLoaderLock(ULONG,ULONG); +/************************************************************************* + * I/O completion functions and structures. + * + * Those 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); + #ifdef __cplusplus } /* extern "C" */ #endif /* defined(__cplusplus) */