Use poll() on the client-side during server waits to implement
overlapped I/O.
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
*/