Andrey Turkin : server: Allow async i/ o operations to send completion messages.

Alexandre Julliard julliard at winehq.org
Thu Nov 15 07:45:05 CST 2007


Module: wine
Branch: master
Commit: c702a91a3ca605637577281f78a1dc61dd067e06
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=c702a91a3ca605637577281f78a1dc61dd067e06

Author: Andrey Turkin <andrey.turkin at gmail.com>
Date:   Sat Nov 10 01:11:48 2007 +0300

server: Allow async i/o operations to send completion messages.

---

 dlls/ntdll/directory.c         |    1 +
 dlls/ntdll/file.c              |   26 ++++++++++++++++++++++----
 dlls/ws2_32/socket.c           |    3 +++
 include/wine/server_protocol.h |    3 ++-
 server/async.c                 |    6 ++++++
 server/completion.c            |    2 +-
 server/fd.c                    |    7 +++++++
 server/file.h                  |    4 +++-
 server/protocol.def            |    1 +
 9 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index 9288d31..6891949 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -2356,6 +2356,7 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event,
         req->async.arg      = info;
         req->async.apc      = read_changes_user_apc;
         req->async.event    = Event;
+        req->async.cvalue   = 0;
         status = wine_server_call( req );
     }
     SERVER_END_REQ;
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 7b64b67..a3a4af1 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -650,6 +650,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
                 req->async.arg      = fileio;
                 req->async.apc      = fileio_apc;
                 req->async.event    = hEvent;
+                req->async.cvalue   = 0;
                 status = wine_server_call( req );
             }
             SERVER_END_REQ;
@@ -879,6 +880,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
                 req->async.arg      = fileio;
                 req->async.apc      = fileio_apc;
                 req->async.event    = hEvent;
+                req->async.cvalue   = 0;
                 status = wine_server_call( req );
             }
             SERVER_END_REQ;
@@ -1005,6 +1007,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
         req->async.arg      = async;
         req->async.apc      = (apc || event) ? ioctl_apc : NULL;
         req->async.event    = event;
+        req->async.cvalue   = 0;
         wine_server_add_data( req, in_buffer, in_size );
         wine_server_set_reply( req, out_buffer, out_size );
         if (!(status = wine_server_call( req )))
@@ -1061,7 +1064,7 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
                                       PVOID out_buffer, ULONG out_size)
 {
     ULONG device = (code >> 16);
-    NTSTATUS status;
+    NTSTATUS status = STATUS_NOT_SUPPORTED;
 
     TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
           handle, event, apc, apc_context, io, code,
@@ -1085,11 +1088,12 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
         status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
                                       in_buffer, in_size, out_buffer, out_size);
         break;
-    default:
+    }
+
+    if (status == STATUS_NOT_SUPPORTED)
         status = server_ioctl_file( handle, event, apc, apc_context, io, code,
                                     in_buffer, in_size, out_buffer, out_size );
-        break;
-    }
+
     if (status != STATUS_PENDING) io->u.Status = status;
     return status;
 }
@@ -1807,6 +1811,16 @@ static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, co
 }
 #endif
 
+static inline int is_device_placeholder( int fd )
+{
+    static const char wine_placeholder[] = "Wine device placeholder";
+    char buffer[sizeof(wine_placeholder)-1];
+
+    if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
+        return 0;
+    return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
+}
+
 /******************************************************************************
  *              get_device_info
  *
@@ -1847,6 +1861,10 @@ static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
     {
         info->DeviceType = FILE_DEVICE_NAMED_PIPE;
     }
+    else if (is_device_placeholder( fd ))
+    {
+        info->DeviceType = FILE_DEVICE_DISK;
+    }
     else  /* regular file or directory */
     {
 #if defined(linux) && defined(HAVE_FSTATFS)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index f4111cd..5d51311 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -1324,6 +1324,7 @@ static int WS2_register_async_shutdown( SOCKET s, int type )
         req->async.iosb     = &wsa->local_iosb;
         req->async.arg      = wsa;
         req->async.apc      = ws2_async_apc;
+        req->async.cvalue   = 0;
         status = wine_server_call( req );
     }
     SERVER_END_REQ;
@@ -2688,6 +2689,7 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                 req->async.arg      = wsa;
                 req->async.apc      = ws2_async_apc;
                 req->async.event    = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
+                req->async.cvalue   = 0;
                 err = wine_server_call( req );
             }
             SERVER_END_REQ;
@@ -4201,6 +4203,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                     req->async.arg      = wsa;
                     req->async.apc      = ws2_async_apc;
                     req->async.event    = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
+                    req->async.cvalue   = 0;
                     err = wine_server_call( req );
                 }
                 SERVER_END_REQ;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 913f2a1..410b802 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -163,6 +163,7 @@ typedef struct
     void           *arg;
     void           *apc;
     obj_handle_t    event;
+    unsigned long   cvalue;
 } async_data_t;
 
 
@@ -4885,6 +4886,6 @@ union generic_reply
     struct set_completion_info_reply set_completion_info_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 328
+#define SERVER_PROTOCOL_VERSION 329
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/async.c b/server/async.c
index 3a99f80..98d6075 100644
--- a/server/async.c
+++ b/server/async.c
@@ -144,6 +144,10 @@ void async_terminate( struct async *async, unsigned int status )
         return;
     }
 
+    /* send error completion event */
+    if (status != STATUS_ALERTED && async->data.cvalue && async->queue && async->queue->fd)
+        fd_add_completion( async->queue->fd, async->data.cvalue, status, 0 );
+
     memset( &data, 0, sizeof(data) );
     data.type            = APC_ASYNC_IO;
     data.async_io.func   = async->data.callback;
@@ -251,6 +255,8 @@ void async_set_result( struct object *obj, unsigned int status )
         if (async->timeout) remove_timeout_user( async->timeout );
         async->timeout = NULL;
         async->status = status;
+        if (async->data.cvalue && async->queue && async->queue->fd)
+            fd_add_completion( async->queue->fd, async->data.cvalue, status, 0 ); /* TODO pass Information field */
         if (async->data.apc)
         {
             apc_call_t data;
diff --git a/server/completion.c b/server/completion.c
index bff2ada..96aaacc 100644
--- a/server/completion.c
+++ b/server/completion.c
@@ -132,7 +132,7 @@ struct completion *get_completion_obj( struct process *process, obj_handle_t han
     return (struct completion *) get_handle_obj( process, handle, access, &completion_ops );
 }
 
-static void add_completion( struct completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information )
+void add_completion( struct completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information )
 {
     struct comp_msg *msg = mem_alloc( sizeof( *msg ) );
 
diff --git a/server/fd.c b/server/fd.c
index dc292cb..cb3aea8 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1919,6 +1919,13 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
     return fd;
 }
 
+/* add a completion result to a completion queue attached to the fd */
+void fd_add_completion( struct fd *fd, unsigned long cvalue, unsigned int status, unsigned long information )
+{
+    if (fd->completion)
+        add_completion( fd->completion, fd->comp_key, cvalue, status, information );
+}
+
 /* flush a file buffers */
 DECL_HANDLER(flush_file)
 {
diff --git a/server/file.h b/server/file.h
index d6295d9..dbf0930 100644
--- a/server/file.h
+++ b/server/file.h
@@ -122,7 +122,8 @@ extern struct object *create_dir_obj( struct fd *fd );
 
 /* completion */
 
-struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access );
+extern struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access );
+extern void add_completion( struct completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information );
 
 /* serial port functions */
 
@@ -139,6 +140,7 @@ extern void async_set_result( struct object *obj, unsigned int status );
 extern int async_waiting( struct async_queue *queue );
 extern void async_terminate( struct async *async, unsigned int status );
 extern void async_wake_up( struct async_queue *queue, unsigned int status );
+extern void fd_add_completion( struct fd *fd, unsigned long cvalue, unsigned int status, unsigned long information );
 
 /* access rights that require Unix read permission */
 #define FILE_UNIX_READ_ACCESS (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
diff --git a/server/protocol.def b/server/protocol.def
index 90e943b..93e4887 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -179,6 +179,7 @@ typedef struct
     void           *arg;           /* opaque user data to pass to callback */
     void           *apc;           /* user apc to call */
     obj_handle_t    event;         /* event to signal when done */
+    unsigned long   cvalue;        /* completion value to use for completion events */
 } async_data_t;
 
 /* structures for extra message data */




More information about the wine-cvs mailing list