I/O Completion Ports Implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

This has been hanging around in my tree for a while. This is useful for RPC 
and for eventually implementing QueueUserWorkItem.

Changelog:
Implement I/O completion ports

? wine/server/iocompletion.c
Index: wine/server/Makefile.in
===================================================================
RCS file: /home/wine/wine/server/Makefile.in,v
retrieving revision 1.47
diff -u -r1.47 Makefile.in
--- wine/server/Makefile.in	24 Jul 2003 00:07:00 -0000	1.47
+++ wine/server/Makefile.in	6 Nov 2003 14:00:40 -0000
@@ -21,6 +21,7 @@
 	file.c \
 	handle.c \
 	hook.c \
+	iocompletion.c \
 	main.c \
 	mapping.c \
 	mutex.c \
Index: wine/server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.87
diff -u -r1.87 protocol.def
--- wine/server/protocol.def	14 Oct 2003 01:30:42 -0000	1.87
+++ wine/server/protocol.def	6 Nov 2003 14:00:43 -0000
@@ -2123,6 +2123,43 @@
 @END
 
 
+/* Create an I/O completion port */
+@REQ(create_io_completion)
+    unsigned int   access;             /* access desired by client */
+    unsigned int   concurrent_threads; /* the number of concurrent threads processing a request */
+@REPLY
+    user_handle_t  handle;             /* handle to the i/o completion port */
+@END
+
+/* Post data to an I/O completion port */
+@REQ(set_io_completion)
+    user_handle_t  handle;            /* handle to the i/o completion port */
+    unsigned int   bytes_transferred; /* number of bytes transferred */
+    void*          completion_key;    /* user data to send to waiting client */
+    void*          overlapped;        /* overlapped structure to send to client */
+@END
+
+/* Get or wait for data posted to an I/O completion port */
+@REQ(remove_io_completion)
+    user_handle_t  handle;       /* handle to the i/o completion port */
+    void*          cookie;       /* magic cookie to return to client */
+    abs_time_t     timeout;      /* absolute timeout */
+@REPLY
+    unsigned int   bytes_transferred; /* number of bytes transferred */
+    void*          completion_key;    /* user data to send to waiting client */
+    void*          overlapped;        /* overlapped structure to send to client */
+@END
+
+/* Get data posted to an I/O completion port after waiting for it */
+@REQ(remove_io_completion_assigned)
+    user_handle_t  handle;       /* handle to the i/o completion port */
+@REPLY
+    unsigned int   bytes_transferred; /* number of bytes transferred */
+    void*          completion_key;    /* user data to send to waiting client */
+    void*          overlapped;        /* overlapped structure to send to client */
+@END
+
+
 /* Set/get clipboard information */
 @REQ(set_clipboard_info)
     unsigned int   flags;       /* flags for fields to set (see below) */
Index: wine/server/request.h
===================================================================
RCS file: /home/wine/wine/server/request.h,v
retrieving revision 1.89
diff -u -r1.89 request.h
--- wine/server/request.h	7 Oct 2003 03:40:23 -0000	1.89
+++ wine/server/request.h	6 Nov 2003 14:00:43 -0000
@@ -279,6 +279,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(set_clipboard_info);
 DECL_HANDLER(open_token);
 DECL_HANDLER(set_global_windows);
@@ -464,6 +468,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_set_clipboard_info,
     (req_handler)req_open_token,
     (req_handler)req_set_global_windows,
Index: wine/server/thread.c
===================================================================
RCS file: /home/wine/wine/server/thread.c,v
retrieving revision 1.103
diff -u -r1.103 thread.c
--- wine/server/thread.c	27 Oct 2003 22:10:22 -0000	1.103
+++ wine/server/thread.c	6 Nov 2003 14:00:45 -0000
@@ -521,7 +521,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 )
 {
     int ret, i;
Index: wine/server/trace.c
===================================================================
RCS file: /home/wine/wine/server/trace.c,v
retrieving revision 1.185
diff -u -r1.185 trace.c
--- wine/server/trace.c	14 Oct 2003 01:30:42 -0000	1.185
+++ wine/server/trace.c	6 Nov 2003 14:00:48 -0000
@@ -2498,6 +2498,52 @@
     dump_varargs_unicode_str( cur_size );
 }
 
+static void dump_create_io_completion_request( const struct create_io_completion_request *req )
+{
+    fprintf( stderr, " access=%08x,", req->access );
+    fprintf( stderr, " concurrent_threads=%08x", req->concurrent_threads );
+}
+
+static void dump_create_io_completion_reply( const struct create_io_completion_reply *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_set_io_completion_request( const struct set_io_completion_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    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_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_clipboard_info_request( const struct set_clipboard_info_request *req )
 {
     fprintf( stderr, " flags=%08x,", req->flags );
@@ -2721,6 +2767,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_set_clipboard_info_request,
     (dump_func)dump_open_token_request,
     (dump_func)dump_set_global_windows_request,
@@ -2903,6 +2953,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)dump_set_clipboard_info_reply,
     (dump_func)dump_open_token_reply,
     (dump_func)dump_set_global_windows_reply,
@@ -3085,6 +3139,10 @@
     "start_hook_chain",
     "finish_hook_chain",
     "get_next_hook",
+    "create_io_completion",
+    "set_io_completion",
+    "remove_io_completion",
+    "remove_io_completion_assigned",
     "set_clipboard_info",
     "open_token",
     "set_global_windows",
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ wine/server/iocompletion.c	Thu Nov  6 13:24:08 2003
@@ -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;
+}
Index: wine/include/winbase.h
===================================================================
RCS file: /home/wine/wine/include/winbase.h,v
retrieving revision 1.199
diff -u -r1.199 winbase.h
--- wine/include/winbase.h	4 Nov 2003 04:52:54 -0000	1.199
+++ wine/include/winbase.h	6 Nov 2003 14:06:41 -0000
@@ -1149,6 +1149,7 @@
 HANDLE      WINAPI CreateFileMappingA(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,DWORD,DWORD,LPCSTR);
 HANDLE      WINAPI CreateFileMappingW(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,DWORD,DWORD,LPCWSTR);
 #define     CreateFileMapping WINELIB_NAME_AW(CreateFileMapping)
+HANDLE      WINAPI CreateIoCompletionPort(HANDLE,HANDLE,ULONG_PTR,DWORD);
 HANDLE      WINAPI CreateMailslotA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
 HANDLE      WINAPI CreateMailslotW(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
 #define     CreateMailslot WINELIB_NAME_AW(CreateMailslot)
@@ -1290,6 +1291,7 @@
 BOOL        WINAPI GetProcessAffinityMask(HANDLE,PDWORD,PDWORD);
 BOOL        WINAPI GetProcessTimes(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME,LPFILETIME);
 DWORD       WINAPI GetProcessVersion(DWORD);
+BOOL        WINAPI GetQueuedCompletionStatus(HANDLE,LPDWORD,PULONG_PTR,LPOVERLAPPED*,DWORD);
 BOOL        WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR_CONTROL,LPDWORD);
 BOOL        WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,LPBOOL,PACL *,LPBOOL);
 BOOL        WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR,PSID *,LPBOOL);
@@ -1391,6 +1393,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 PulseEvent(HANDLE);
 BOOL        WINAPI PurgeComm(HANDLE,DWORD);
Index: wine/include/winternl.h
===================================================================
RCS file: /home/wine/wine/include/winternl.h,v
retrieving revision 1.63
diff -u -r1.63 winternl.h
--- wine/include/winternl.h	31 Oct 2003 00:16:20 -0000	1.63
+++ wine/include/winternl.h	6 Nov 2003 14:06:44 -0000
@@ -1367,7 +1367,7 @@
 /*************************************************************************
  * Loader functions and structures.
  *
- * Those are not part of standard Winternl.h
+ * These are not part of standard Winternl.h
  */
 typedef struct _LDR_MODULE
 {
@@ -1428,6 +1428,23 @@
 NTSTATUS WINAPI LdrQueryProcessModuleInformation(SYSTEM_MODULE_INFORMATION*, ULONG, ULONG*);
 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))
Index: wine/include/wine/server_protocol.h
===================================================================
RCS file: /home/wine/wine/include/wine/server_protocol.h,v
retrieving revision 1.88
diff -u -r1.88 server_protocol.h
--- wine/include/wine/server_protocol.h	14 Oct 2003 01:30:42 -0000	1.88
+++ wine/include/wine/server_protocol.h	6 Nov 2003 14:06:47 -0000
@@ -3046,6 +3046,64 @@
 
 
 
+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;
+    abs_time_t     timeout;
+};
+struct remove_io_completion_reply
+{
+    struct reply_header __header;
+    unsigned int   bytes_transferred;
+    void*          completion_key;
+    void*          overlapped;
+};
+
+
+struct remove_io_completion_assigned_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+};
+struct remove_io_completion_assigned_reply
+{
+    struct reply_header __header;
+    unsigned int   bytes_transferred;
+    void*          completion_key;
+    void*          overlapped;
+};
+
+
+
 struct set_clipboard_info_request
 {
     struct request_header __header;
@@ -3292,6 +3350,10 @@
     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_remove_io_completion_assigned,
     REQ_set_clipboard_info,
     REQ_open_token,
     REQ_set_global_windows,
@@ -3478,6 +3540,10 @@
     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;
+    struct remove_io_completion_assigned_request remove_io_completion_assigned_request;
     struct set_clipboard_info_request set_clipboard_info_request;
     struct open_token_request open_token_request;
     struct set_global_windows_request set_global_windows_request;
@@ -3662,11 +3728,15 @@
     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;
+    struct remove_io_completion_assigned_reply remove_io_completion_assigned_reply;
     struct set_clipboard_info_reply set_clipboard_info_reply;
     struct open_token_reply open_token_reply;
     struct set_global_windows_reply set_global_windows_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 126
+#define SERVER_PROTOCOL_VERSION 127
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
? wine/dlls/kernel/iocompletion.c
Index: wine/dlls/kernel/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/kernel/Makefile.in,v
retrieving revision 1.98
diff -u -r1.98 Makefile.in
--- wine/dlls/kernel/Makefile.in	6 Nov 2003 01:09:58 -0000	1.98
+++ wine/dlls/kernel/Makefile.in	6 Nov 2003 14:08:31 -0000
@@ -44,6 +44,7 @@
 	file.c \
 	file16.c \
 	format_msg.c \
+	iocompletion.c \
 	global16.c \
 	heap.c \
 	instr.c \
Index: wine/dlls/kernel/kernel32.spec
===================================================================
RCS file: /home/wine/wine/dlls/kernel/kernel32.spec,v
retrieving revision 1.116
diff -u -r1.116 kernel32.spec
--- wine/dlls/kernel/kernel32.spec	3 Nov 2003 22:12:15 -0000	1.116
+++ wine/dlls/kernel/kernel32.spec	6 Nov 2003 14:08:33 -0000
@@ -645,7 +645,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)
Index: wine/dlls/kernel/sync.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/sync.c,v
retrieving revision 1.44
diff -u -r1.44 sync.c
--- wine/dlls/kernel/sync.c	3 Nov 2003 22:12:15 -0000	1.44
+++ wine/dlls/kernel/sync.c	6 Nov 2003 14:08:34 -0000
@@ -1529,31 +1529,6 @@
 
 
 /******************************************************************************
- *		CreateIoCompletionPort (KERNEL32.@)
- */
-HANDLE WINAPI CreateIoCompletionPort(HANDLE hFileHandle, HANDLE hExistingCompletionPort,
-                                     DWORD dwCompletionKey, DWORD dwNumberOfConcurrentThreads)
-{
-    FIXME("(%p, %p, %08lx, %08lx): stub.\n",
-          hFileHandle, hExistingCompletionPort, dwCompletionKey, dwNumberOfConcurrentThreads);
-    return NULL;
-}
-
-
-/******************************************************************************
- *		GetQueuedCompletionStatus (KERNEL32.@)
- */
-BOOL WINAPI GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred,
-                                       LPDWORD lpCompletionKey, LPOVERLAPPED *lpOverlapped,
-                                       DWORD dwMilliseconds )
-{
-    FIXME("(%p,%p,%p,%p,%ld), stub!\n",
-          CompletionPort,lpNumberOfBytesTransferred,lpCompletionKey,lpOverlapped,dwMilliseconds);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-
-/******************************************************************************
  *		CreateJobObjectW (KERNEL32.@)
  */
 HANDLE WINAPI CreateJobObjectW( LPSECURITY_ATTRIBUTES attr, LPCWSTR name )
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ wine/dlls/kernel/iocompletion.c	Thu Nov  6 14:31:21 2003
@@ -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;
+    }
+}
Index: wine/dlls/ntdll/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/Makefile.in,v
retrieving revision 1.92
diff -u -r1.92 Makefile.in
--- wine/dlls/ntdll/Makefile.in	5 Nov 2003 23:31:11 -0000	1.92
+++ wine/dlls/ntdll/Makefile.in	6 Nov 2003 14:25:00 -0000
@@ -15,6 +15,7 @@
 	exception.c \
 	file.c \
 	heap.c \
+	iocompletion.c \
 	large_int.c \
 	loader.c \
 	loadorder.c \
Index: wine/dlls/ntdll/sync.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/sync.c,v
retrieving revision 1.33
diff -u -r1.33 sync.c
--- wine/dlls/ntdll/sync.c	6 Nov 2003 00:08:05 -0000	1.33
+++ wine/dlls/ntdll/sync.c	6 Nov 2003 14:25:01 -0000
@@ -462,11 +462,11 @@
 
 
 /***********************************************************************
- *              wait_reply
+ *              NTDLL_wait_reply
  *
  * 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;
@@ -479,7 +479,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 (;;)
             {
@@ -575,7 +575,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;
Index: wine/dlls/ntdll/ntdll.spec
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/ntdll.spec,v
retrieving revision 1.137
diff -u -r1.137 ntdll.spec
--- wine/dlls/ntdll/ntdll.spec	5 Nov 2003 23:31:11 -0000	1.137
+++ wine/dlls/ntdll/ntdll.spec	6 Nov 2003 14:25:03 -0000
@@ -79,7 +79,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
@@ -192,7 +192,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)
@@ -220,7 +220,7 @@
 @ stdcall NtSetInformationThread(long long ptr long)
 @ stub NtSetInformationToken
 @ stdcall NtSetIntervalProfile(long long)
-@ stub NtSetIoCompletion
+@ stdcall NtSetIoCompletion(ptr long ptr long long)
 @ stub NtSetLdtEntries
 @ stub NtSetLowEventPair
 @ stub NtSetLowWaitHighEventPair
--- /dev/null	Mon Jun 24 01:53:01 2002
+++ wine/dlls/ntdll/iocompletion.c	Thu Nov  6 13:24:58 2003
@@ -0,0 +1,215 @@
+/*
+ * 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 "config.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;
+}

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux