[PATCH] Async IO on regular files

Martin Wilck Martin.Wilck at fujitsu-siemens.com
Wed Jan 2 09:21:37 CST 2002


This patch implements asynchronous I/O on regular file objects.
It is against the current (02/01/02) CVS version of wine.

I know that async IO on regular files is pretty pointless at the moment,
but it's better to have it working as expected, I guess ...

The patch was successfully tested with a simple test program that checks
the sequence of scheduled reqeuests and file positioning via the
lpOverlapped->Offset and OffsetHigh fields.

server/file.c:
	struct file:		add two async_queue fields (read/write) for async IO.
	create_file_for_fd(): 	Intialize async queues.
	destroy_file(): 	destroy async queues.
	file_poll_event(): 	invoke async requests for overlapped files.
	file_queue_async(): 	implement the queue_async() method.
	file_get_info(): 	return FD_TYPE_OVERLAPPED for overlapped files.

files/file.c:
	FILE_AsyncReadService():
		Use pread() for fd's that support seeking.
	FILE_AsyncWriteService():
		Use pwrite() for fd's that support seeking.

Regards
Martin

-- 
Martin Wilck                Phone: +49 5251 8 15113
Fujitsu Siemens Computers   Fax:   +49 5251 8 20409
Heinz-Nixdorf-Ring 1	    mailto:Martin.Wilck at Fujitsu-Siemens.com
D-33106 Paderborn           http://www.fujitsu-siemens.com/primergy




-------------- next part --------------
diff -uNr -X diffignore CVS/wine/files/file.c MW/wine/files/file.c
--- CVS/wine/files/file.c	Wed Jan  2 12:50:02 2002
+++ MW/wine/files/file.c	Wed Jan  2 15:51:53 2002
@@ -9,6 +9,9 @@
  *    Right now, they simply call the CopyFile method.
  */
 
+/* This is needed to avoid compile-time warnings about pread / pwrite */
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE 500
 #include "config.h"
 #include "wine/port.h"
 
@@ -1288,12 +1291,21 @@
 {
     LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
     int result, r;
+    int already = lpOverlapped->InternalHigh;
 
     TRACE("%p %p\n", lpOverlapped, ovp->buffer );
 
     /* check to see if the data is ready (non-blocking) */
-    result = read(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh],
-                  ovp->count - lpOverlapped->InternalHigh);
+
+    /* Check if this file object can lseek() */
+    /* FIXME: test this only once for each file object ?? */
+    if (lseek (ovp->fd, 0, SEEK_CUR) != (off_t) -1)
+	result = pread (ovp->fd, 
+			&ovp->buffer[already],
+			ovp->count - already,
+			(off_t) lpOverlapped->Offset  + ((off_t) lpOverlapped->OffsetHigh << 32) + already);
+    else
+	result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
 
     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
     {
@@ -1527,12 +1539,21 @@
 {
     LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
     int result, r;
+    int already = lpOverlapped->InternalHigh;
 
     TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
 
     /* write some data (non-blocking) */
-    result = write(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh],
-                  ovp->count-lpOverlapped->InternalHigh);
+
+    /* Check if this file object can lseek() */
+    /* FIXME: test this only once for each file object ?? */
+    if (lseek (ovp->fd, 0, SEEK_CUR) != (off_t) -1)
+	result = pwrite (ovp->fd, 
+			 &ovp->buffer[already],
+			 ovp->count - already,
+			 (off_t) lpOverlapped->Offset  + ((off_t) lpOverlapped->OffsetHigh << 32) + already);
+    else
+	result = write (ovp->fd, &ovp->buffer[already], ovp->count - already);
 
     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
     {
diff -uNr -X diffignore CVS/wine/server/file.c MW/wine/server/file.c
--- CVS/wine/server/file.c	Wed Jan  2 12:50:05 2002
+++ MW/wine/server/file.c	Wed Jan  2 15:08:58 2002
@@ -29,6 +29,7 @@
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
+#include "async.h"
 
 struct file
 {
@@ -39,6 +40,9 @@
     unsigned int        flags;      /* flags (FILE_FLAG_*) */
     unsigned int        sharing;    /* file sharing mode */
     int                 drive_type; /* type of drive the file is on */
+
+    struct async_queue  read_q;
+    struct async_queue  write_q;    
 };
 
 #define NAME_HASH_SIZE 37
@@ -47,10 +51,12 @@
 
 static void file_dump( struct object *obj, int verbose );
 static int file_get_poll_events( struct object *obj );
+static void file_poll_event( struct object *obj, int event );
 static int file_get_fd( struct object *obj );
 static int file_flush( struct object *obj );
 static int file_get_info( struct object *obj, struct get_file_info_reply *reply );
 static void file_destroy( struct object *obj );
+static struct async_queue * file_queue_async(struct object *obj, struct async* async, int type, int count);
 
 static const struct object_ops file_ops =
 {
@@ -61,11 +67,11 @@
     default_poll_signaled,        /* signaled */
     no_satisfied,                 /* satisfied */
     file_get_poll_events,         /* get_poll_events */
-    default_poll_event,           /* poll_event */
+    file_poll_event,              /* poll_event */
     file_get_fd,                  /* get_fd */
     file_flush,                   /* flush */
     file_get_info,                /* get_file_info */
-    NULL,                         /* queue_async */
+    file_queue_async,             /* queue_async */
     file_destroy                  /* destroy */
 };
 
@@ -116,6 +122,11 @@
         file->flags      = attrs;
         file->sharing    = sharing;
         file->drive_type = drive_type;
+	if (file->flags & FILE_FLAG_OVERLAPPED) 
+	{
+	    init_async_queue (&file->read_q);
+	    init_async_queue (&file->write_q);
+	}
     }
     return file;
 }
@@ -253,6 +264,27 @@
     return events;
 }
 
+static void file_poll_event( struct object *obj, int event )
+{
+    struct file *file = (struct file *)obj;
+    assert( obj->ops == &file_ops );
+    if ( file->flags & FILE_FLAG_OVERLAPPED ) 
+    {
+	if( IS_READY(file->read_q) && (POLLIN & event) )
+	{
+	    async_notify(file->read_q.head, STATUS_ALERTED);
+	    return;
+	}
+	if( IS_READY(file->write_q) && (POLLIN & event) )
+	{
+	    async_notify(file->write_q.head, STATUS_ALERTED);
+	    return;
+	}
+    }
+    default_poll_event( obj, event );
+}
+
+
 static int file_get_fd( struct object *obj )
 {
     struct file *file = (struct file *)obj;
@@ -308,9 +340,45 @@
         reply->index_low   = st.st_ino;
         reply->serial      = 0; /* FIXME */
     }
+
+    if (file->flags & FILE_FLAG_OVERLAPPED)
+	return FD_TYPE_OVERLAPPED;
+
     return FD_TYPE_DEFAULT;
 }
 
+static struct async_queue *file_queue_async(struct object *obj, struct async *async, int type, int count)
+{
+    struct file *file = (struct file *)obj;
+    struct async_queue *q;
+
+    assert( obj->ops == &file_ops );
+
+    if ( !(file->flags & FILE_FLAG_OVERLAPPED) ) 
+    {
+	set_error ( STATUS_INVALID_HANDLE );
+	return NULL;
+    }
+	
+    switch(type)
+    {
+    case ASYNC_TYPE_READ:
+        q = &file->read_q;
+        break;
+    case ASYNC_TYPE_WRITE:
+        q = &file->write_q;
+        break;
+    default:
+        set_error( STATUS_INVALID_PARAMETER );
+        return NULL;
+    }
+
+    if(async && !async->q)
+	async_insert(q, async);
+    
+    return q;
+}
+
 static void file_destroy( struct object *obj )
 {
     struct file *file = (struct file *)obj;
@@ -325,6 +393,11 @@
         *pptr = (*pptr)->next;
         if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name );
         free( file->name );
+    }
+    if (file->flags & FILE_FLAG_OVERLAPPED)
+    {
+	destroy_async_queue (&file->read_q);
+	destroy_async_queue (&file->write_q);
     }
 }
 


More information about the wine-devel mailing list