Use poll() on the client-side during server waits to implement
overlapped I/O.

diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index 3c6fd9d..b70c41b 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -50,6 +50,7 @@
 #endif
 #include <sys/ioctl.h>
 #include <unistd.h>
+#include <sys/poll.h>
 
 #include "windef.h"
 #ifdef HAVE_SYS_MODEM_H
@@ -2814,19 +2815,102 @@
 #endif
 }
 
-VOID COMM_WaitCommEventService(void **args)
+/***********************************************************************
+ *             COMM_WaitCommEventService      (INTERNAL)
+ *
+ *  This function is called while the client is waiting on the
+ *  server, so we can't make any server calls here.
+ */
+static void COMM_WaitCommEventService(async_private *ovp, int events)
 {
-    LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
-    LPDWORD buffer = (LPDWORD)args[1];
-    DWORD events = (DWORD)args[2];
+    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
 
-    TRACE("overlapped %p wait complete %p <- %lx\n",lpOverlapped,buffer,events);
-    if(buffer)
-        *buffer = events;
+    TRACE("overlapped %p wait complete %p <- %x\n",lpOverlapped,ovp->buffer,events);
+    if(events&POLLNVAL)
+    {
+        lpOverlapped->Internal = STATUS_HANDLES_CLOSED;
+        return;
+    }
+    if(ovp->buffer)
+    {
+        if(events&POLLIN)
+            *ovp->buffer = EV_RXCHAR;
+    }
  
     lpOverlapped->Internal = STATUS_SUCCESS;
-    SetEvent( lpOverlapped->hEvent);
-    CloseHandle(lpOverlapped->InternalHigh);
+}
+
+
+
+/***********************************************************************
+ *             COMM_WaitCommEvent         (INTERNAL)
+ *
+ *  This function must have an lpOverlapped.
+ */
+static BOOL COMM_WaitCommEvent(
+    HANDLE hFile,              /* [in] handle of comm port to wait for */
+    LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
+    LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
+{
+    int fd,ret;
+    async_private *ovp;
+
+    if(!lpOverlapped)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if(NtResetEvent(lpOverlapped->hEvent,NULL))
+        return FALSE;
+
+    lpOverlapped->Internal = STATUS_PENDING;
+    lpOverlapped->InternalHigh = 0;
+    lpOverlapped->Offset = 0;
+    lpOverlapped->OffsetHigh = 0;
+
+    /* start an ASYNCHRONOUS WaitCommEvent */
+    SERVER_START_REQ( create_async )
+    {
+        req->file_handle = hFile;
+        req->count = 0;
+        req->type = ASYNC_TYPE_WAIT;
+
+        ret=SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+
+    if (ret)
+        return FALSE;
+  
+    fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+    if(fd<0)
+	return FALSE;
+
+    ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+    if(!ovp)
+    {
+        close(fd);
+        return FALSE;
+    }
+    ovp->lpOverlapped = lpOverlapped;
+    ovp->timeout = 0;
+    ovp->tv.tv_sec = 0;
+    ovp->tv.tv_usec = 0;
+    ovp->event = POLLIN;
+    ovp->func = COMM_WaitCommEventService;
+    ovp->buffer = (char *)lpdwEvents;
+    ovp->fd = fd;
+  
+    ovp->next = NtCurrentTeb()->pending_list;
+    ovp->prev = NULL;
+    if(ovp->next)
+        ovp->next->prev=ovp;
+    NtCurrentTeb()->pending_list = ovp;
+  
+    SetLastError(ERROR_IO_PENDING);
+
+    return FALSE;
 }
 
 /***********************************************************************
@@ -2852,79 +2936,31 @@
     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
 {
     OVERLAPPED ov;
-    LPOVERLAPPED lpov;
     int ret;
 
     TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
 
+    if(lpOverlapped)
+        return COMM_WaitCommEvent(hFile, lpdwEvents, lpOverlapped);
+
     /* if there is no overlapped structure, create our own */
-    if(!lpOverlapped)
-    {
-        ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
-        lpov = &ov;
-    }
-    else
-        lpov = lpOverlapped;
+    ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
 
-    /* check that the overlapped structure has a valid event flag */
-    if ( (lpov->hEvent==0) || (lpov->hEvent == INVALID_HANDLE_VALUE) )
+    COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
+
+    if(GetLastError()!=STATUS_PENDING)
     {
-        ERR("Couldn't create Event flag for Overlapped structure\n");
-        SetLastError(ERROR_INVALID_PARAMETER);
+        CloseHandle(ov.hEvent);
         return FALSE;
     }
 
-    ResetEvent(lpov->hEvent);
+    /* wait for the overlapped to complete */
+    ret = GetOverlappedResult(hFile, &ov, NULL, TRUE);
+    CloseHandle(ov.hEvent);
 
-    lpov->Internal = STATUS_PENDING;
-    lpov->InternalHigh = 0;
-    lpov->Offset = 0;
-    lpov->OffsetHigh = 0;
-
-    /* start an ASYNCHRONOUS WaitCommEvent */
-    SERVER_START_REQ( create_async )
-    {
-        req->file_handle = hFile;
-        req->overlapped  = lpov;
-        req->buffer = lpdwEvents;
-        req->count = 0;
-        req->func = COMM_WaitCommEventService;
-        req->type = ASYNC_TYPE_WAIT;
-
-        ret=SERVER_CALL_ERR();
-
-        lpov->InternalHigh = req->ov_handle;
-    }
-    SERVER_END_REQ;
-
-    if(ret)
-    {
-        if(!lpOverlapped)
-            CloseHandle(lpov->hEvent);
-        TRACE("server call failed.\n");
-        return FALSE;
-    }
-
-    /* activate the overlapped operation */
-    lpov->Internal = STATUS_PENDING;
-
-    /* wait ourselves if the caller didn't give us an overlapped struct */
-    if(!lpOverlapped)
-    {
-        GetOverlappedResult(hFile, lpov, NULL, TRUE);
-        CloseHandle(lpov->hEvent);
-        lpov->hEvent=0;
-    }
-    else
-    {
-        /* caller wants overlapped I/O using GetOverlapped result */
-        SetLastError(ERROR_IO_PENDING);
-        return FALSE;
-    }
-
-    return TRUE;
+    return ret;
 }
-
+  
 /***********************************************************************
  *           GetCommProperties   (KERNEL32.286)
  *
diff --git a/files/file.c b/files/file.c
index 1259ccf..04e3bb7 100644
--- a/files/file.c
+++ b/files/file.c
@@ -27,6 +27,7 @@
 #include <sys/mman.h>
 #endif
 #include <sys/time.h>
+#include <sys/poll.h>
 #include <time.h>
 #include <unistd.h>
 #include <utime.h>
@@ -1196,60 +1197,43 @@
         *lpTransferred = lpOverlapped->InternalHigh;
 
     SetLastError(lpOverlapped->Internal);
- 
+
     return (r==WAIT_OBJECT_0);
 }
 
-/***********************************************************************
- *             FILE_AsyncResult           (INTERNAL)
- */
-static int FILE_AsyncResult(HANDLE hAsync, int result)
-{
-    int r;
-
-    SERVER_START_REQ( async_result )
-    {
-        req->ov_handle = hAsync;
-        req->result    = result;
-        r = SERVER_CALL_ERR();
-    }
-    SERVER_END_REQ;
-    return !r;
-}
 
 /***********************************************************************
  *             FILE_AsyncReadService      (INTERNAL)
+ *
+ *  This function is called while the client is waiting on the
+ *  server, so we can't make any server calls here.
  */
-static void FILE_AsyncReadService(void **args)
+static void FILE_AsyncReadService(async_private *ovp, int events)
 {
-    LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
-    LPDWORD buffer = (LPDWORD)args[1];
-    DWORD events = (DWORD)args[2];
-    int fd, result, r;
+    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+    int result, r;
 
-    TRACE("%p %p %08lx\n", lpOverlapped, buffer, events );
+    TRACE("%p %p %08x\n", lpOverlapped, ovp->buffer, events );
+
+    /* if POLLNVAL, then our fd was closed or we have the wrong fd */
+    if(events&POLLNVAL)
+    {
+        ERR("fd %d invalid for %p\n",ovp->fd,ovp);
+        r = STATUS_UNSUCCESSFUL;
+        goto async_end;
+    }
 
     /* if there are no events, it must be a timeout */
     if(events==0)
     {
         TRACE("read timed out\n");
-        /* r = STATUS_TIMEOUT; */
-        r = STATUS_SUCCESS;
-        goto async_end;
-    }
-
-    fd = FILE_GetUnixHandle(lpOverlapped->Offset, GENERIC_READ);
-    if(fd<0)
-    {
-        TRACE("FILE_GetUnixHandle(%ld) failed \n",lpOverlapped->Offset);
-        r = STATUS_UNSUCCESSFUL;
+        r = STATUS_TIMEOUT;
         goto async_end;
     }
 
     /* check to see if the data is ready (non-blocking) */
-    result = read(fd, &buffer[lpOverlapped->InternalHigh],
+    result = read(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh],
                   lpOverlapped->OffsetHigh - lpOverlapped->InternalHigh);
-    close(fd);
 
     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
     {
@@ -1276,50 +1260,91 @@
 
 async_end:
     lpOverlapped->Internal = r;
-    if ( (r!=STATUS_PENDING)
-        || (!FILE_AsyncResult( lpOverlapped->InternalHigh, r)))
-    {
-        /* close the handle to the async operation */
-        if(lpOverlapped->Offset)
-            CloseHandle(lpOverlapped->Offset);
-        lpOverlapped->Offset = 0;
+}
 
-        NtSetEvent( lpOverlapped->hEvent, NULL );
-        TRACE("set event flag\n");
+/* flogged from wineserver */
+/* add a timeout in milliseconds to an absolute time */
+static void add_timeout( struct timeval *when, int timeout )
+{
+    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;
     }
 }
 
 /***********************************************************************
  *             FILE_StartAsyncRead      (INTERNAL)
+ *
+ * Don't need thread safety, because the list of asyncs 
+ * will only be modified in this thread.
  */
 static BOOL FILE_StartAsyncRead( HANDLE hFile, LPOVERLAPPED overlapped, LPVOID buffer, DWORD count)
 {
-    int r;
+    async_private *ovp;
+    int fd, timeout, ret;
 
-    SERVER_START_REQ( create_async )
+    /* 
+     * Although the overlapped transfer will be done in this thread
+     * we still need to register the operation with the server, in
+     * case it is cancelled and to get a file handle and the timeout info.
+     */
+    SERVER_START_REQ(create_async)
     {
-        req->file_handle = hFile;
-        req->overlapped = overlapped;
-        req->buffer = buffer;
         req->count = count;
-        req->func = FILE_AsyncReadService;
         req->type = ASYNC_TYPE_READ;
-
-        r=SERVER_CALL_ERR();
-
-        overlapped->Offset = req->ov_handle;
+        req->file_handle = hFile;
+        ret = SERVER_CALL();
+        timeout = req->timeout;
     }
     SERVER_END_REQ;
-
-    if(!r)
+    if (ret)
     {
-        TRACE("ov=%ld IO is pending!!!\n",overlapped->Offset);
-        SetLastError(ERROR_IO_PENDING);
+        TRACE("server call failed\n");
+        return FALSE;
     }
 
-    return !r;
+    fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+    if(fd<0)
+    {
+        TRACE("Couldn't get FD\n");
+        return FALSE;
+    }
+
+    ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+    if(!ovp)
+    {
+        TRACE("HeapAlloc Failed\n");
+        close(fd);
+        return FALSE;
+    }
+    ovp->lpOverlapped = overlapped;
+    ovp->timeout = timeout;
+    gettimeofday(&ovp->tv,NULL);
+    add_timeout(&ovp->tv,timeout);
+    ovp->event = POLLIN;
+    ovp->func = FILE_AsyncReadService;
+    ovp->buffer = buffer;
+    ovp->fd = fd;
+
+    /* hook this overlap into the pending async operation list */
+    ovp->next = NtCurrentTeb()->pending_list;
+    ovp->prev = NULL;
+    if(ovp->next)
+        ovp->next->prev = ovp;
+    NtCurrentTeb()->pending_list = ovp;
+
+    SetLastError(ERROR_IO_PENDING);
+
+    return TRUE;
 }
 
+
 /***********************************************************************
  *              ReadFile                (KERNEL32.577)
  */
@@ -1341,20 +1366,18 @@
         if ( (overlapped->hEvent == 0) ||
            (overlapped->hEvent == INVALID_HANDLE_VALUE) )
         {
+            SetLastError(ERROR_INVALID_PARAMETER);
             return FALSE;
         }
 
         overlapped->Offset       = 0;
         overlapped->OffsetHigh   = bytesToRead;
-        overlapped->Internal     = 0;
+        overlapped->Internal = STATUS_PENDING;
         overlapped->InternalHigh = 0;
 
         NtResetEvent( overlapped->hEvent, NULL );
 
-        if(FILE_StartAsyncRead(hFile, overlapped, buffer, bytesToRead))
-        {
-            overlapped->Internal = STATUS_PENDING;
-        }
+        FILE_StartAsyncRead(hFile, overlapped, buffer, bytesToRead);
 
         /* always fail on return, either ERROR_IO_PENDING or other error */
         return FALSE;
@@ -1377,17 +1400,27 @@
     return TRUE;
 }
 
+
 /***********************************************************************
  *             FILE_AsyncWriteService      (INTERNAL)
+ *
+ *  This function is called while the client is waiting on the
+ *  server, so we can't make any server calls here.
  */
-static void FILE_AsyncWriteService(void **args)
+static void FILE_AsyncWriteService(struct async_private *ovp, int events)
 {
-    LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
-    LPDWORD buffer = (LPDWORD)args[1];
-    DWORD events = (DWORD)args[2];
-    int fd, result, r;
+    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+    int result, r;
 
-    TRACE("(%p %p %lx)\n",lpOverlapped,buffer,events);
+    TRACE("(%p %p %08x)\n",lpOverlapped,ovp->buffer,events);
+
+    /* if POLLNVAL, then our fd was closed or we have the wrong fd */
+    if(events&POLLNVAL)
+    {
+        ERR("fd %d invalid for %p\n",ovp->fd,ovp);
+        r = STATUS_UNSUCCESSFUL;
+        goto async_end;
+    }
 
     /* if there are no events, it must be a timeout */
     if(events==0)
@@ -1397,18 +1430,9 @@
         goto async_end;
     }
 
-    fd = FILE_GetUnixHandle(lpOverlapped->Offset, GENERIC_WRITE);
-    if(fd<0)
-    {
-        ERR("FILE_GetUnixHandle(%ld) failed \n",lpOverlapped->Offset);
-        r = STATUS_UNSUCCESSFUL;
-        goto async_end;
-    }
-
     /* write some data (non-blocking) */
-    result = write(fd, &buffer[lpOverlapped->InternalHigh],
+    result = write(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh],
                   lpOverlapped->OffsetHigh-lpOverlapped->InternalHigh);
-    close(fd);
 
     if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
     {
@@ -1425,6 +1449,8 @@
 
     lpOverlapped->InternalHigh += result;
 
+    TRACE("wrote %d more bytes %ld/%ld so far\n",result,lpOverlapped->InternalHigh,lpOverlapped->OffsetHigh);
+
     if(lpOverlapped->InternalHigh < lpOverlapped->OffsetHigh)
         r = STATUS_PENDING;
     else
@@ -1432,15 +1458,6 @@
 
 async_end:
     lpOverlapped->Internal = r;
-    if ( (r!=STATUS_PENDING)
-        || (!FILE_AsyncResult( lpOverlapped->Offset, r)))
-    {
-        /* close the handle to the async operation */
-        CloseHandle(lpOverlapped->Offset);
-        lpOverlapped->Offset = 0;
-
-        NtSetEvent( lpOverlapped->hEvent, NULL );
-    }
 }
 
 /***********************************************************************
@@ -1448,31 +1465,50 @@
  */
 static BOOL FILE_StartAsyncWrite(HANDLE hFile, LPOVERLAPPED overlapped, LPCVOID buffer,DWORD count)
 {
-    int r;
+    /* don't need thread safety, because the list will only be modified in this thread */
+    async_private *ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+    int timeout,ret;
 
-    SERVER_START_REQ( create_async )
+    SERVER_START_REQ(create_async)
     {
-        req->file_handle = hFile;
-        req->buffer = (LPVOID)buffer;
-        req->overlapped = overlapped;
-        req->count = 0;
-        req->func = FILE_AsyncWriteService;
+        req->count = count;
         req->type = ASYNC_TYPE_WRITE;
-
-        r = SERVER_CALL_ERR();
-
-        overlapped->Offset = req->ov_handle;
+        req->file_handle = hFile;
+        ret = SERVER_CALL();
+        timeout = req->timeout;
     }
     SERVER_END_REQ;
+    if (ret)
+        return FALSE;
 
-    if(!r)
+    /* need to register the overlapped with the server, get a file handle and the timeout info */
+    ovp->lpOverlapped = overlapped;
+    ovp->timeout = timeout;
+    gettimeofday(&ovp->tv,NULL);
+    add_timeout(&ovp->tv,timeout);
+    ovp->event = POLLOUT;
+    ovp->func = FILE_AsyncWriteService;
+    ovp->buffer = (LPVOID) buffer;
+    ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+    if(ovp->fd <0)
     {
-        SetLastError(ERROR_IO_PENDING);
+        HeapFree(GetProcessHeap(), 0, ovp);
+        return FALSE;
     }
 
-    return !r;
+    /* hook this overlap into the pending async operation list */
+    ovp->next = NtCurrentTeb()->pending_list;
+    ovp->prev = NULL;
+    if(ovp->next)
+        ovp->next->prev = ovp;
+    NtCurrentTeb()->pending_list = ovp;
+
+    SetLastError(ERROR_IO_PENDING);
+
+    return TRUE;
 }
 
+
 /***********************************************************************
  *             WriteFile               (KERNEL32.738)
  */
@@ -1492,19 +1528,19 @@
     {
         if ( (overlapped->hEvent == 0) ||
              (overlapped->hEvent == INVALID_HANDLE_VALUE) )
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
             return FALSE;
+        }
 
         overlapped->Offset       = 0;
         overlapped->OffsetHigh   = bytesToWrite;
-        overlapped->Internal     = 0;
+        overlapped->Internal = STATUS_PENDING;
         overlapped->InternalHigh = 0;
 
         NtResetEvent( overlapped->hEvent, NULL );
 
-        if (FILE_StartAsyncWrite(hFile, overlapped, buffer, bytesToWrite))
-        {
-            overlapped->Internal = STATUS_PENDING;
-        }
+        FILE_StartAsyncWrite(hFile, overlapped, buffer, bytesToWrite);
 
         /* always fail on return, either ERROR_IO_PENDING or other error */
         return FALSE;
@@ -1530,7 +1566,7 @@
     return TRUE;
 }
 
-
+  
 /***********************************************************************
  *           WIN16_hread
  */
diff --git a/include/file.h b/include/file.h
index 811455e..2093d0e 100644
--- a/include/file.h
+++ b/include/file.h
@@ -8,6 +8,7 @@
 #define __WINE_FILE_H
 
 #include <time.h> /* time_t */
+#include <sys/time.h>
 #include "winbase.h"
 #include "wine/windef16.h"  /* HFILE16 */
 
@@ -30,6 +31,22 @@
     int flags;
 } DOS_DEVICE;
 
+/* overlapped private structure */
+struct async_private;
+typedef void (*async_handler)(struct async_private *ovp, int revents);
+typedef struct async_private
+{
+     LPOVERLAPPED  lpOverlapped;
+     int           fd;
+     int           timeout;
+     struct timeval tv;
+     int           event;
+     char         *buffer;
+     async_handler func;
+     struct async_private *next;
+     struct async_private *prev;
+} async_private;
+
 /* locale-independent case conversion */
 inline static char FILE_tolower( char c )
 {
diff --git a/include/server.h b/include/server.h
index 87904b1..2f48af9 100644
--- a/include/server.h
+++ b/include/server.h
@@ -1356,28 +1356,15 @@
 struct create_async_request
 {
     REQUEST_HEADER;                /* request header */
-    IN  handle_t     file_handle;  /* handle to comm port */
-    IN  void*        overlapped;
-    IN  void*        buffer;
+    IN  handle_t     file_handle;  /* handle to comm port, socket or file */
     IN  int          count;
-    IN  void*        func;
     IN  int          type;
-    OUT handle_t     ov_handle;
+    OUT int          timeout;
 };
 #define ASYNC_TYPE_READ  0x01
 #define ASYNC_TYPE_WRITE 0x02
 #define ASYNC_TYPE_WAIT  0x03
 
-/*
- * Used by service thread to tell the server that the current
- * operation has completed
- */
-struct async_result_request
-{
-    REQUEST_HEADER;                /* request header */
-    IN  handle_t     ov_handle;
-    IN  int          result;       /* NT status code */
-};
 
 /* Everything below this line is generated automatically by tools/make_requests */
 /* ### make_requests begin ### */
@@ -1492,7 +1479,6 @@
     REQ_get_serial_info,
     REQ_set_serial_info,
     REQ_create_async,
-    REQ_async_result,
     REQ_NB_REQUESTS
 };
 
@@ -1608,10 +1594,9 @@
     struct get_serial_info_request get_serial_info;
     struct set_serial_info_request set_serial_info;
     struct create_async_request create_async;
-    struct async_result_request async_result;
 };
 
-#define SERVER_PROTOCOL_VERSION 43
+#define SERVER_PROTOCOL_VERSION 44
 
 /* ### make_requests end ### */
 /* Everything above this line is generated automatically by tools/make_requests */
diff --git a/include/thread.h b/include/thread.h
index f26239c..264c2fb 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -100,10 +100,11 @@
     int          wait_fd[2];     /* --3 214 fd for sleeping server requests */
     void        *debug_info;     /* --3 21c Info for debugstr functions */
     void        *pthread_data;   /* --3 220 Data for pthread emulation */
+    struct async_private *pending_list;   /* --3 224 list of pending async operations */
     /* here is plenty space for wine specific fields (don't forget to change pad6!!) */
 
     /* the following are nt specific fields */
-    DWORD        pad6[629];                  /* --n 224 */
+    DWORD        pad6[628];                  /* --n 228 */
     UNICODE_STRING StaticUnicodeString;      /* -2- bf8 used by advapi32 */
     USHORT       StaticUnicodeBuffer[261];   /* -2- c00 used by advapi32 */
     DWORD        pad7;                       /* --n e0c */
diff --git a/scheduler/synchro.c b/scheduler/synchro.c
index 45159ee..0add600 100644
--- a/scheduler/synchro.c
+++ b/scheduler/synchro.c
@@ -8,6 +8,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <sys/time.h>
+#include <sys/poll.h>
 #include <unistd.h>
 #include <string.h>
 
@@ -35,6 +36,125 @@
     }
 }
 
+#define MAX_NUMBER_OF_FDS 20
+
+static inline int time_before( struct timeval *t1, struct timeval *t2 )
+{
+    return ((t1->tv_sec < t2->tv_sec) ||
+            ((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec)));
+}
+
+static void finish_async(async_private *ovp)
+{
+    /* remove it from the active list */
+    if(ovp->prev)
+        ovp->prev->next = ovp->next;
+    else
+        NtCurrentTeb()->pending_list = ovp->next;
+
+    if(ovp->next)
+        ovp->next->prev = ovp->prev;
+
+    ovp->next=NULL;
+    ovp->prev=NULL;
+
+    close(ovp->fd);
+    NtSetEvent(ovp->lpOverlapped->hEvent,NULL);
+    HeapFree(GetProcessHeap(), 0, ovp);
+}
+
+/***********************************************************************
+ *           check_async_list
+ *
+ *  Create a list of fds for poll to check while waiting on the server
+ *  FIXME: this loop is too large, cut into smaller functions
+ *         perhaps we could share/steal some of the code in server/select.c?
+ */
+static void check_async_list(void)
+{
+    /* FIXME: should really malloc these two arrays */
+    struct pollfd fds[MAX_NUMBER_OF_FDS];
+    async_private *user[MAX_NUMBER_OF_FDS], *tmp;
+    int i, n, r, timeout;
+    async_private *ovp, *timeout_user;
+    struct timeval now;
+
+    while(1)
+    {
+        /* the first fd belongs to the server connection */
+        fds[0].events=POLLIN;
+        fds[0].revents=0;
+        fds[0].fd = NtCurrentTeb()->wait_fd[0];
+
+        ovp = NtCurrentTeb()->pending_list;
+        timeout = -1;
+        timeout_user = NULL;
+        gettimeofday(&now,NULL);
+        for(n=1; ovp && (n<MAX_NUMBER_OF_FDS); ovp = tmp)
+        {
+            tmp = ovp->next;
+
+            if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
+            {
+                ovp->lpOverlapped->Internal=STATUS_UNSUCCESSFUL;
+                finish_async(ovp);
+                continue;
+            }
+
+            if(ovp->timeout && time_before(&ovp->tv,&now))
+            {
+                ovp->lpOverlapped->Internal=STATUS_TIMEOUT;
+                finish_async(ovp);
+                continue;
+            }
+
+            fds[n].fd=ovp->fd;
+            fds[n].events=ovp->event;
+            fds[n].revents=0;
+            user[n] = ovp;
+
+            if(ovp->timeout && ( (!timeout_user) || time_before(&ovp->tv,&timeout_user->tv)))
+            {
+                timeout = (ovp->tv.tv_sec - now.tv_sec) * 1000
+                        + (ovp->tv.tv_usec - now.tv_usec) / 1000;
+                timeout_user = ovp;
+            }
+
+            n++;
+        }
+
+        /* if there aren't any active asyncs return */
+        if(n==1)
+            return;
+
+        r = poll(fds, n, timeout);
+
+        /* if there were any errors, return immediately */
+        if( (r<0) || (fds[0].revents==POLLNVAL) )
+            return;
+
+        if( r==0 )
+        {
+            timeout_user->lpOverlapped->Internal = STATUS_TIMEOUT;
+            finish_async(timeout_user);
+            continue;
+        }
+
+        /* search for async operations that are ready */
+        for( i=1; i<n; i++)
+        {
+            if (fds[i].revents)
+                user[i]->func(user[i],fds[i].revents);
+
+            if(user[i]->lpOverlapped->Internal!=STATUS_PENDING)
+                finish_async(user[i]);
+        }
+
+        if(fds[0].revents == POLLIN)
+            return;
+    }
+}
+
 
 /***********************************************************************
  *              wait_reply
@@ -47,7 +167,9 @@
     struct wake_up_reply reply;
     for (;;)
     {
-        int ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
+        int ret;
+        if (NtCurrentTeb()->pending_list) check_async_list();
+        ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
         if (ret == sizeof(reply))
         {
             if (!reply.cookie) break;  /* thread got killed */
@@ -105,7 +227,6 @@
         case APC_NONE:
             return;  /* no more APCs */
         case APC_ASYNC:
-            proc( &args[0] );
             break;
         case APC_USER:
             proc( args[0] );
diff --git a/server/async.c b/server/async.c
index 2d37b83..bcb5714 100644
--- a/server/async.c
+++ b/server/async.c
@@ -4,280 +4,31 @@
  * Copyright (C) 1998 Alexandre Julliard
  * Copyright (C) 2000 Mike McCormack
  *
- * TODO:
- *  Fix up WaitCommEvent operations. Currently only EV_RXCHAR is supported.
- *    This may require modifications to the linux kernel to enable select
- *    to wait on Modem Status Register deltas. (delta DCD, CTS, DSR or RING)
- *
  */
 
 #include "config.h"
 
 #include <assert.h>
-#include <fcntl.h>
-#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <errno.h>
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <time.h>
 #include <unistd.h>
-#include <utime.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-
-#include "winerror.h"
-#include "winbase.h"
 
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
 
-struct async 
-{
-    struct object           obj;
-    void                   *client_overlapped;
-    int                     type;
-    int                     result;
-    int                     count;
-    int                     eventmask;
-    struct async           *next;
-    struct timeval          tv;
-    struct timeout_user    *timeout;
-    struct wait_queue_entry wait;
-    void                   *buffer;
-    void                   *func;
-    struct thread          *thread;
-    struct object          *file;
-};
-
-static void async_dump( struct object *obj, int verbose );
-static void async_destroy( struct object *obj );
-static int async_get_poll_events( struct object *obj );
-static int async_get_fd( struct object *obj );
-static int async_get_info( struct object *obj, struct get_file_info_request *req );
-static void async_poll_event( struct object *obj, int event );
-static void overlapped_timeout (void *private);
-
-static const struct object_ops async_ops =
-{
-    sizeof(struct async),         /* size */
-    async_dump,                   /* dump */
-    default_poll_add_queue,       /* add_queue */
-    default_poll_remove_queue,    /* remove_queue */
-    default_poll_signaled,        /* signaled */
-    no_satisfied,                 /* satisfied */
-    async_get_poll_events,        /* get_poll_events */
-    async_poll_event,             /* poll_event */
-    async_get_fd,                 /* get_fd */
-    no_flush,                     /* flush */
-    async_get_info,               /* get_file_info */
-    async_destroy                 /* destroy */
-};
-
-static void async_dump( struct object *obj, int verbose )
-{
-    struct async *ov = (struct async *)obj;
-
-    assert( obj->ops == &async_ops );
-
-    fprintf( stderr, "async: overlapped %p %s\n", 
-                 ov->client_overlapped, ov->timeout?"with timeout":"");
-}
-
-/* same as file_destroy, but don't delete comm ports */
-static void async_destroy( struct object *obj )
-{
-    struct async *ov = (struct async *)obj;
-    assert( obj->ops == &async_ops );
-
-    if(ov->timeout)
-    {
-        remove_timeout_user(ov->timeout);
-        ov->timeout = NULL;
-    }
-}
-
-struct async *get_async_obj( struct process *process, handle_t handle, unsigned int access )
-{
-    return (struct async *)get_handle_obj( process, handle, access, &async_ops );
-}
-
-static int async_get_poll_events( struct object *obj )
-{
-    struct async *ov = (struct async *)obj;
-    assert( obj->ops == &async_ops );
-
-    /* FIXME: this should be a function pointer */
-    return serial_async_get_poll_events(ov);
-}
-
-static int async_get_fd( struct object *obj )
-{
-    struct async *async = (struct async *)obj;
-    assert( obj->ops == &async_ops );
-    return async->obj.fd;
-}
-
-static int async_get_info( struct object *obj, struct get_file_info_request *req ) {
-    assert( obj->ops == &async_ops );
-    req->type        = FILE_TYPE_CHAR;
-    req->attr        = 0;
-    req->access_time = 0;
-    req->write_time  = 0;
-    req->size_high   = 0;
-    req->size_low    = 0;
-    req->links       = 0;
-    req->index_high  = 0;
-    req->index_low   = 0;
-    req->serial      = 0;
-    return 1;
-}
-
-/* data access functions */
-int async_type(struct async *ov)
-{
-    return ov->type;
-}
-
-int async_count(struct async *ov)
-{
-    return ov->count;
-}
-
-int async_get_eventmask(struct async *ov)
-{
-    return ov->eventmask;
-}
-
-int async_set_eventmask(struct async *ov, int eventmask)
-{
-    return ov->eventmask = eventmask;
-}
 
 DECL_HANDLER(create_async)
 {
     struct object *obj;
-    struct async *ov = NULL;
-    int fd;
 
-    req->ov_handle = 0;
     if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) )
         return;
 
-    fd = dup(obj->fd);
-    if(fd<0)
-    {
-        release_object(obj);
-        set_error(STATUS_UNSUCCESSFUL);
-        return;
-    }
-
-    if(0>fcntl(fd, F_SETFL, O_NONBLOCK))
-    {
-        release_object(obj);
-        set_error(STATUS_UNSUCCESSFUL);
-        return;
-    }
-
-    ov = alloc_object (&async_ops, fd);
-    if(!ov)
-    {
-        release_object(obj);
-        set_error(STATUS_UNSUCCESSFUL);
-        return;
-    }
-
-    ov->client_overlapped = req->overlapped;
-    ov->next    = NULL;
-    ov->timeout = NULL;
-    ov->type    = req->type;
-    ov->thread  = current;
-    ov->func    = req->func;
-    ov->file    = obj;
-    ov->buffer  = req->buffer;
-    ov->count   = req->count;
-    ov->tv.tv_sec = 0;
-    ov->tv.tv_usec = 0;
+    /* FIXME: check if this object is allowed to do overlapped I/O */
 
     /* FIXME: this should be a function pointer */
-    serial_async_setup(obj,ov);
+    req->timeout = get_serial_async_timeout(obj,req->type,req->count);
 
-    if( ov->tv.tv_sec || ov->tv.tv_usec )
-    {
-        ov->timeout = add_timeout_user(&ov->tv, overlapped_timeout, ov);
-    }
-
-    ov->obj.ops->add_queue(&ov->obj,&ov->wait);
-
-    req->ov_handle = alloc_handle( current->process, ov, GENERIC_READ|GENERIC_WRITE, 0 );
-
-    release_object(ov);
     release_object(obj);
 }
-
-/* handler for async poll() events */
-static void async_poll_event( struct object *obj, int event )
-{
-    struct async *ov = (struct async *) obj;
-
-    /* queue an APC in the client thread to do our dirty work */
-    ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
-    if(ov->timeout)
-    {
-        remove_timeout_user(ov->timeout);
-        ov->timeout = NULL;
-    }
-
-    /* FIXME: this should be a function pointer */
-    event = serial_async_poll_event(obj,event);
-
-    thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
-                     ov->client_overlapped, ov->buffer, event);
-}
-
-/* handler for async i/o timeouts */
-static void overlapped_timeout (void *private)
-{
-    struct async *ov = (struct async *) private;
-
-    ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
-    ov->timeout = NULL;
-
-    thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
-                     ov->client_overlapped,ov->buffer, 0);
-}
-
-void async_add_timeout(struct async *ov, int timeout)
-{
-    if(timeout)
-    {
-        gettimeofday(&ov->tv,0);
-        add_timeout(&ov->tv,timeout);
-    }
-}
-
-DECL_HANDLER(async_result)
-{
-    struct async *ov;
-
-    if ((ov = get_async_obj( current->process, req->ov_handle, 0 )))
-    {
-        ov->result = req->result;
-        if(ov->result == STATUS_PENDING)
-        {
-            ov->obj.ops->add_queue(&ov->obj,&ov->wait);
-            if( (ov->tv.tv_sec || ov->tv.tv_usec) && !ov->timeout)
-            {
-                ov->timeout = add_timeout_user(&ov->tv, overlapped_timeout, ov);
-            }
-        }
-        release_object( ov );
-    }
-}
-
diff --git a/server/object.h b/server/object.h
index 089ab5b..2b3a02a 100644
--- a/server/object.h
+++ b/server/object.h
@@ -153,19 +153,9 @@
 extern struct file *create_temp_file( int access );
 extern void file_set_error(void);
 
-/* async functions */
-
-void async_add_timeout(struct async *ov, int timeout);
-int async_count(struct async *ov);
-int async_type(struct async *ov);
-int async_get_eventmask(struct async *ov);
-int async_set_eventmask(struct async *ov, int eventmask);
-
 /* serial functions */
 
-int serial_async_setup(struct object *obj, struct async *ov);
-int serial_async_get_poll_events( struct async *ov );
-int serial_async_poll_event(struct object *obj, int event);
+int get_serial_async_timeout(struct object *obj, int type, int count);
 
 /* console functions */
 
diff --git a/server/request.h b/server/request.h
index a24d04b..43ac0ae 100644
--- a/server/request.h
+++ b/server/request.h
@@ -176,7 +176,6 @@
 DECL_HANDLER(get_serial_info);
 DECL_HANDLER(set_serial_info);
 DECL_HANDLER(create_async);
-DECL_HANDLER(async_result);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -291,7 +290,6 @@
     (req_handler)req_get_serial_info,
     (req_handler)req_set_serial_info,
     (req_handler)req_create_async,
-    (req_handler)req_async_result,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/serial.c b/server/serial.c
index 953be97..738bcbc 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -173,76 +173,25 @@
     return 1;
 }
 
-/* these functions are for interaction with asynchronous i/o objects */
-int serial_async_setup(struct object *obj, struct async *ov)
+/* these function calculates the timeout for an async operation
+   on a serial port */
+int get_serial_async_timeout(struct object *obj, int type, int count)
 {
     struct serial *serial = (struct serial *)obj;
-    int timeout;
 
     if(obj->ops != &serial_ops)
         return 0;
 
-    switch(async_type(ov))
+    switch(type)
     {
     case ASYNC_TYPE_READ:
-        timeout = serial->readconst + serial->readmult*async_count(ov);
-        async_add_timeout(ov, timeout);
-        async_set_eventmask(ov,EV_RXCHAR);
-        break;
+        return serial->readconst + serial->readmult*count;
     case ASYNC_TYPE_WRITE:
-        timeout = serial->writeconst + serial->writemult*async_count(ov);
-        async_add_timeout(ov, timeout);
-        async_set_eventmask(ov,EV_TXEMPTY);
-        break;
-    case ASYNC_TYPE_WAIT:
-        async_set_eventmask(ov,serial->eventmask);
-        break;
+        return serial->writeconst + serial->writemult*count;
     }
-
-    return 1;
+    return 0;
 }
 
-int serial_async_get_poll_events( struct async *ov )
-{
-    int events=0,mask;
-
-    switch(async_type(ov))
-    {
-    case ASYNC_TYPE_READ:
-        events |= POLLIN;
-        break;
-    case ASYNC_TYPE_WRITE:
-        events |= POLLOUT;
-        break;
-    case ASYNC_TYPE_WAIT:
-    /* 
-     * FIXME: here is the spot to implement other WaitCommEvent flags
-     */
-        mask = async_get_eventmask(ov);
-        if(mask&EV_RXCHAR)
-            events |= POLLIN;
-        /* if(mask&EV_TXEMPTY)
-            events |= POLLOUT; */
-        break;
-    }
-    return events;
-}
-
-/* receive a select event, and output a windows event */
-int serial_async_poll_event(struct object *obj, int event)
-{
-    int r=0;
-
-    /* 
-     * FIXME: here is the spot to implement other WaitCommEvent flags
-     */
-    if(event & POLLIN)
-        r |= EV_RXCHAR;
-    if(event & POLLOUT)
-        r |= EV_TXEMPTY;
-
-    return r;
-}
 
 /* create a serial */
 DECL_HANDLER(create_serial)
diff --git a/server/trace.c b/server/trace.c
index 367c258..f1648cc 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1477,22 +1477,13 @@
 static void dump_create_async_request( const struct create_async_request *req )
 {
     fprintf( stderr, " file_handle=%d,", req->file_handle );
-    fprintf( stderr, " overlapped=%p,", req->overlapped );
-    fprintf( stderr, " buffer=%p,", req->buffer );
     fprintf( stderr, " count=%d,", req->count );
-    fprintf( stderr, " func=%p,", req->func );
     fprintf( stderr, " type=%d", req->type );
 }
 
 static void dump_create_async_reply( const struct create_async_request *req )
 {
-    fprintf( stderr, " ov_handle=%d", req->ov_handle );
-}
-
-static void dump_async_result_request( const struct async_result_request *req )
-{
-    fprintf( stderr, " ov_handle=%d,", req->ov_handle );
-    fprintf( stderr, " result=%d", req->result );
+    fprintf( stderr, " timeout=%d", req->timeout );
 }
 
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
@@ -1604,7 +1595,6 @@
     (dump_func)dump_get_serial_info_request,
     (dump_func)dump_set_serial_info_request,
     (dump_func)dump_create_async_request,
-    (dump_func)dump_async_result_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -1716,7 +1706,6 @@
     (dump_func)dump_get_serial_info_reply,
     (dump_func)0,
     (dump_func)dump_create_async_reply,
-    (dump_func)0,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -1828,7 +1817,6 @@
     "get_serial_info",
     "set_serial_info",
     "create_async",
-    "async_result",
 };
 
 /* ### make_requests end ### */