I/O Completion Ports (1 of 2)

Robert Shearman R.J.Shearman at warwick.ac.uk
Sun Mar 23 19:11:01 CST 2003


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

-------------- next part --------------
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) */


More information about the wine-patches mailing list