Unfortunately this patch has become big, because i came across so many
problems today and I just needed to go forward.
I am sorry for this, but it has become very late tonight, and I want
people to see this stuff to stop me before it's too late
(if I'm on the wrong track).
It compiles without warnings, but I have not tested it - may crash wine
right away, I don't know.
* Full separation of async handling and file io-specific stuff.
* Do not rely on LPOVERLAPPED for status data in generic code, it may be
NULL. File IO code may rely on it, here it is required to be non-NULL.
* Use GetOverlappedResult() to check for immediate completion (UNTESTED!)
Please give me comments telling me which parts you don't like, so that I
can adjust for further development.
Mike, can you tell me about those apps that were causing trouble in the
past ? Where can I obtain them? Do they need special hardware (modem,
mouse) for test runs ?
--
Martin Wilck Phone: +49 5251 8 15113
Fujitsu Siemens Computers Fax: +49 5251 8 20409
Heinz-Nixdorf-Ring 1 mailto:Martin.Wilck@Fujitsu-Siemens.com
D-33106 Paderborn
http://www.fujitsu-siemens.com/primergy
ChangeLog:
server/protocol.def:
cancel_async(): Define new reqest type.
server/async.c:
cancel_async(): Implement new reqest type.
include/file.h:
struct async_ops: 4 methods for async_private: get_status, set_status, get_count, call_completion.
struct async_private: contains only those elements which are absolutely necessary for queueing and server interaction
struct async_fileio: contains all other fields.
scheduler/synchro.c:
register_async(): replacement for FILE_StartAsync(). Uses STATUS_USER_APC as (pseudo-) indicator
to queue a new request. Hooks new requests in NtCurrentTeb()->pending_list (formerly done
in calling functions). Not used by CancelIo() anymore. Finishes requests that are not in
PENDING state after scheduling.
finish_async(): Assume status is already set correctly. Queue call_completion unconditionally
(No completion_func check needed)
check_async(): Use register_async() for rescheduling.
files/file.c:
GetOverlappedResult(): Return ERROR_IO_INCOMPLETE if IO still pending (MSDN docs)
FILE_StartAsync(): -> scheduler/synchro.c: register_async
CancelIo(): Use new cancel_async server request (I felt former StartAsync() was too overloaded).
Skip requests with wrong handle.
fileio_call_completion_func(): Now called unconditionally, check if completion_func is non-NULL.
FILE_AsyncReadService(): type adjustments according to new API
FILE_AsyncWriteService(): dito
FILE_ReadFileEx(): use new async API. Call GetOverlappedResult() to check for immediate completion.
FILE_WriteFileEx(): dito. Now exactly equivalent to FILE_ReadFileEx()
kernel/comm.c:
COMM_WaitCommEventService(): Use new async API.
diff -ruX diffignore CVS/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c
--- CVS/wine/dlls/kernel/comm.c Tue Jan 8 18:53:41 2002
+++ MW/wine/dlls/kernel/comm.c Wed Jan 9 21:20:37 2002
@@ -1514,12 +1514,13 @@
*/
static void COMM_WaitCommEventService(async_private *ovp)
{
- LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+ async_fileio *fileio = (async_fileio*) ovp;
+ LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
TRACE("overlapped %p\n",lpOverlapped);
/* FIXME: detect other events */
- *ovp->buffer = EV_RXCHAR;
+ *fileio->buffer = EV_RXCHAR;
lpOverlapped->Internal = STATUS_SUCCESS;
}
@@ -1536,7 +1537,7 @@
LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
{
int fd,ret;
- async_private *ovp;
+ async_fileio *ovp;
if(!lpOverlapped)
{
@@ -1547,52 +1548,35 @@
if(NtResetEvent(lpOverlapped->hEvent,NULL))
return FALSE;
- lpOverlapped->Internal = STATUS_PENDING;
- lpOverlapped->InternalHigh = 0;
- lpOverlapped->Offset = 0;
- lpOverlapped->OffsetHigh = 0;
-
fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
if(fd<0)
return FALSE;
- ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+ ovp = (async_fileio *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp)
{
close(fd);
return FALSE;
}
+
+ ovp->async.ops = &fileio_async_ops;
+ ovp->async.handle = hFile;
+ ovp->async.fd = fd;
+ ovp->async.type = ASYNC_TYPE_WAIT;
+ ovp->async.func = COMM_WaitCommEventService;
+
ovp->lpOverlapped = lpOverlapped;
- ovp->func = COMM_WaitCommEventService;
ovp->buffer = (char *)lpdwEvents;
- ovp->fd = fd;
ovp->count = 0;
ovp->completion_func = 0;
- ovp->type = ASYNC_TYPE_WAIT;
- ovp->handle = hFile;
-
- ovp->next = NtCurrentTeb()->pending_list;
- ovp->prev = NULL;
- if(ovp->next)
- ovp->next->prev=ovp;
- NtCurrentTeb()->pending_list = ovp;
- /* start an ASYNCHRONOUS WaitCommEvent */
- SERVER_START_REQ( register_async )
- {
- req->handle = hFile;
- req->overlapped = lpOverlapped;
- req->type = ASYNC_TYPE_WAIT;
- req->count = 0;
- req->func = check_async_list;
- req->status = STATUS_PENDING;
-
- ret=wine_server_call_err(req);
- }
- SERVER_END_REQ;
+ lpOverlapped->Internal = STATUS_USER_APC;
+ lpOverlapped->InternalHigh = 0;
+ lpOverlapped->Offset = 0;
+ lpOverlapped->OffsetHigh = 0;
- if (!ret)
- SetLastError(ERROR_IO_PENDING);
+ if (register_async (&ovp->async))
+ SetLastError(ERROR_IO_PENDING);
return FALSE;
}
diff -ruX diffignore CVS/wine/files/file.c MW/wine/files/file.c
--- CVS/wine/files/file.c Tue Jan 8 18:57:47 2002
+++ MW/wine/files/file.c Wed Jan 9 20:55:09 2002
@@ -60,6 +60,20 @@
static HANDLE dos_handles[DOS_TABLE_SIZE];
+/* Async operations struct (see file.h) */
+
+static DWORD fileio_get_async_status (async_private *ovp);
+static DWORD fileio_get_async_count (async_private *ovp);
+static void fileio_set_async_status (async_private *ovp, DWORD status);
+static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
+
+async_ops fileio_async_ops =
+{
+ fileio_get_async_status, /* get_status */
+ fileio_set_async_status, /* set_status */
+ fileio_get_async_count, /* get_count */
+ fileio_call_completion_func /* call_completion */
+};
/***********************************************************************
* FILE_ConvertOFMode
@@ -1244,35 +1258,13 @@
if(lpTransferred)
*lpTransferred = lpOverlapped->InternalHigh;
- SetLastError(lpOverlapped->Internal);
+ /* This is what the function should return accirding to MSDN specs */
+ if ( lpOverlapped->Internal == STATUS_PENDING )
+ SetLastError (ERROR_IO_INCOMPLETE);
return (r==WAIT_OBJECT_0);
}
-
-/***********************************************************************
- * FILE_StartAsync (INTERNAL)
- *
- * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
- * lpOverlapped==NULL means all overlappeds match
- */
-BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status)
-{
- BOOL ret;
- SERVER_START_REQ(register_async)
- {
- req->handle = hFile;
- req->overlapped = lpOverlapped;
- req->type = type;
- req->count = count;
- req->func = check_async_list;
- req->status = status;
- ret = wine_server_call( req );
- }
- SERVER_END_REQ;
- return !ret;
-}
-
/***********************************************************************
* CancelIo (KERNEL32.@)
*/
@@ -1282,21 +1274,60 @@
TRACE("handle = %x\n",handle);
- ovp = NtCurrentTeb()->pending_list;
- while(ovp)
+
+ for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
{
t = ovp->next;
- if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED))
+ if (ovp->handle != handle) continue;
+
+ SERVER_START_REQ ( cancel_async )
{
- TRACE("overlapped = %p\n",ovp->lpOverlapped);
- finish_async(ovp, STATUS_CANCELLED);
+ req->handle = handle;
+ req->type = ovp->type;
+ req->overlapped = ovp;
+ wine_server_call ( req );
+ if (reply->cancelled)
+ {
+ TRACE ("cancelling request: %p\n", ovp);
+ ovp->ops->set_status ( ovp, STATUS_CANCELLED );
+ finish_async (ovp);
+ }
}
- ovp = t;
+ SERVER_END_REQ;
}
WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
return TRUE;
}
+static DWORD fileio_get_async_status (async_private *ovp)
+{
+ return ((async_fileio*) ovp)->lpOverlapped->Internal;
+}
+
+static void fileio_set_async_status (async_private *ovp, DWORD status)
+{
+ ((async_fileio*) ovp)->lpOverlapped->Internal = status;
+}
+
+static DWORD fileio_get_async_count (async_private *ovp)
+{
+ async_fileio *fileio = (async_fileio*) ovp;
+ DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
+ return (ret < 0 ? 0 : ret);
+}
+
+static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
+{
+ async_fileio *ovp = (async_fileio*) data;
+ TRACE ("data: %p\n", ovp);
+
+ if (ovp->completion_func)
+ ovp->completion_func(ovp->lpOverlapped->Internal,
+ ovp->lpOverlapped->InternalHigh,
+ ovp->lpOverlapped);
+ HeapFree(GetProcessHeap(), 0, ovp);
+}
+
/***********************************************************************
* FILE_AsyncReadService (INTERNAL)
*
@@ -1305,18 +1336,19 @@
*/
static void FILE_AsyncReadService(async_private *ovp)
{
- LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+ async_fileio *fileio = (async_fileio*) ovp;
+ LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
int result, r;
int already = lpOverlapped->InternalHigh;
- TRACE("%p %p\n", lpOverlapped, ovp->buffer );
+ TRACE("%p %p\n", lpOverlapped, fileio->buffer );
/* check to see if the data is ready (non-blocking) */
- result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already,
+ result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE))
- result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
+ result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
{
@@ -1334,9 +1366,9 @@
}
lpOverlapped->InternalHigh += result;
- TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
+ TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
- if(lpOverlapped->InternalHigh < ovp->count)
+ if(lpOverlapped->InternalHigh < fileio->count)
r = STATUS_PENDING;
else
r = STATUS_SUCCESS;
@@ -1352,7 +1384,7 @@
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
- async_private *ovp;
+ async_fileio *ovp;
int fd;
TRACE("file %d to buf %p num %ld %p func %p\n",
@@ -1369,10 +1401,11 @@
if(fd<0)
{
TRACE("Couldn't get FD\n");
+ SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
- ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+ ovp = (async_fileio *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp)
{
TRACE("HeapAlloc Failed\n");
@@ -1380,30 +1413,23 @@
close(fd);
return FALSE;
}
+
+ ovp->async.ops = &fileio_async_ops;
+ ovp->async.handle = hFile;
+ ovp->async.fd = fd;
+ ovp->async.type = ASYNC_TYPE_READ;
+ ovp->async.func = FILE_AsyncReadService;
+
ovp->lpOverlapped = overlapped;
- ovp->count = bytesToRead;
ovp->completion_func = lpCompletionRoutine;
- ovp->func = FILE_AsyncReadService;
ovp->buffer = buffer;
- ovp->fd = fd;
- ovp->type = ASYNC_TYPE_READ;
- ovp->handle = hFile;
-
- /* 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;
+ ovp->count = bytesToRead;
- if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) )
- {
- /* FIXME: remove async_private and release memory */
- ERR("FILE_StartAsync failed\n");
- return FALSE;
- }
+ /* Tell register_async that this is a new request */
+ overlapped->Internal = STATUS_USER_APC;
- return TRUE;
+ /* The request is hooked into the pending list by register_async() */
+ return register_async (&ovp->async);
}
/***********************************************************************
@@ -1413,7 +1439,6 @@
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
- overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0;
return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine);
}
@@ -1470,41 +1495,21 @@
return FALSE;
}
- /* see if we can read some data already (this shouldn't block) */
- result = pread( unix_handle, buffer, bytesToRead, OVERLAPPED_OFFSET(overlapped) );
- if ((result < 0) && (errno == ESPIPE))
- result = read( unix_handle, buffer, bytesToRead );
close(unix_handle);
-
- if(result<0)
- {
- if( (errno!=EAGAIN) && (errno!=EINTR) &&
- ((errno != EFAULT) || IsBadWritePtr( buffer, bytesToRead )) )
- {
- FILE_SetDosError();
- return FALSE;
- }
- else
- result = 0;
- }
+ overlapped->InternalHigh = 0;
- /* if we read enough to keep the app happy, then return now */
- if(result>=bytesToRead)
- {
- *bytesRead = result;
- return TRUE;
- }
+ if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, FILE_OverlappedComplete))
+ return FALSE;
- /* at last resort, do an overlapped read */
- overlapped->Internal = STATUS_PENDING;
- overlapped->InternalHigh = result;
- if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, FILE_OverlappedComplete))
+ if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
+ {
+ if ( GetLastError() == ERROR_IO_INCOMPLETE )
+ SetLastError ( ERROR_IO_PENDING );
return FALSE;
+ }
- /* fail on return, with ERROR_IO_PENDING */
- SetLastError(ERROR_IO_PENDING);
- return FALSE;
+ return TRUE;
}
else if ( FD_TYPE (type) == FD_TYPE_CONSOLE )
@@ -1554,18 +1559,19 @@
*/
static void FILE_AsyncWriteService(struct async_private *ovp)
{
- LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+ async_fileio *fileio = (async_fileio *) ovp;
+ LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
int result, r;
int already = lpOverlapped->InternalHigh;
- TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
+ TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
/* write some data (non-blocking) */
- result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already,
+ result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE))
- result = write(ovp->fd, &ovp->buffer[already], ovp->count - already);
+ result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
{
@@ -1582,9 +1588,9 @@
lpOverlapped->InternalHigh += result;
- TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
+ TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
- if(lpOverlapped->InternalHigh < ovp->count)
+ if(lpOverlapped->InternalHigh < fileio->count)
r = STATUS_PENDING;
else
r = STATUS_SUCCESS;
@@ -1600,7 +1606,8 @@
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
- async_private *ovp;
+ async_fileio *ovp;
+ int fd;
TRACE("file %d to buf %p num %ld %p func %p stub\n",
hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
@@ -1611,45 +1618,39 @@
return FALSE;
}
- overlapped->Internal = STATUS_PENDING;
- overlapped->InternalHigh = 0;
-
- if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
+ fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+ if(fd<0)
{
- TRACE("FILE_StartAsync failed\n");
+ TRACE("Couldn't get FD\n");
+ SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
- ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+ ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp)
{
TRACE("HeapAlloc Failed\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ close(fd);
return FALSE;
}
+
+ ovp->async.ops = &fileio_async_ops;
+ ovp->async.handle = hFile;
+ ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+ ovp->async.type = ASYNC_TYPE_WRITE;
+ ovp->async.func = FILE_AsyncWriteService;
+
ovp->lpOverlapped = overlapped;
- ovp->func = FILE_AsyncWriteService;
ovp->buffer = (LPVOID) buffer;
- ovp->count = bytesToWrite;
ovp->completion_func = lpCompletionRoutine;
- ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
- ovp->type = ASYNC_TYPE_WRITE;
- ovp->handle = hFile;
-
- if(ovp->fd <0)
- {
- HeapFree(GetProcessHeap(), 0, ovp);
- return FALSE;
- }
+ ovp->count = bytesToWrite;
- /* 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;
+ /* Tell register_async that this is a new request */
+ overlapped->Internal = STATUS_USER_APC;
- return TRUE;
+ /* The request is hooked into the pending list by register_async() */
+ return register_async (&ovp->async);
}
/***********************************************************************
@@ -1659,7 +1660,6 @@
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
- overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0;
return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
@@ -1693,44 +1693,20 @@
return FALSE;
}
- /* see if we can write some data already (this shouldn't block) */
-
- result = pwrite( unix_handle, buffer, bytesToWrite, OVERLAPPED_OFFSET (overlapped) );
- if ((result < 0) && (errno == ESPIPE))
- result = write( unix_handle, buffer, bytesToWrite );
-
close(unix_handle);
-
- if(result<0)
- {
- if( (errno!=EAGAIN) && (errno!=EINTR) &&
- ((errno != EFAULT) || IsBadReadPtr( buffer, bytesToWrite )) )
- {
- FILE_SetDosError();
- return FALSE;
- }
- else
- result = 0;
- }
-
- /* if we wrote enough to keep the app happy, then return now */
- if(result>=bytesToWrite)
- {
- *bytesWritten = result;
- return TRUE;
- }
-
- /* at last resort, do an overlapped read */
- overlapped->Internal = STATUS_PENDING;
- overlapped->InternalHigh = result;
+ overlapped->InternalHigh = 0;
- if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, FILE_OverlappedComplete))
+ if (!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, FILE_OverlappedComplete))
return FALSE;
+
+ if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
+ {
+ if ( GetLastError() == ERROR_IO_INCOMPLETE )
+ SetLastError ( ERROR_IO_PENDING );
+ return FALSE;
+ }
- /* fail on return, with ERROR_IO_PENDING */
- SetLastError(ERROR_IO_PENDING);
- return FALSE;
-
+ return TRUE;
}
else if ( FD_TYPE (type) == FD_TYPE_CONSOLE )
diff -ruX diffignore CVS/wine/include/file.h MW/wine/include/file.h
--- CVS/wine/include/file.h Wed Jan 9 21:27:50 2002
+++ MW/wine/include/file.h Wed Jan 9 20:25:05 2002
@@ -33,23 +33,46 @@
/* overlapped private structure */
struct async_private;
-typedef void (*async_handler)(struct async_private *ovp);
+
+typedef void (*async_handler) (struct async_private *ovp);
+typedef void CALLBACK (*async_call_completion_func) (ULONG_PTR data);
+typedef DWORD (*async_get_status) (struct async_private *ovp);
+typedef DWORD (*async_get_count) (struct async_private *ovp);
+typedef void (*async_set_status) (struct async_private *ovp, DWORD status);
+
+typedef struct async_ops
+{
+ async_get_status get_status;
+ async_set_status set_status;
+ async_get_count get_count;
+ async_call_completion_func call_completion;
+} async_ops;
+
+extern async_ops fileio_async_ops;
+
typedef struct async_private
{
- LPOVERLAPPED lpOverlapped;
- HANDLE handle;
- int fd;
- char *buffer;
- async_handler func;
- int count;
- int type;
- LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
- struct async_private *next;
- struct async_private *prev;
+ async_ops *ops;
+ HANDLE handle;
+ int fd;
+ int type;
+ async_handler func;
+ struct async_private *next;
+ struct async_private *prev;
} async_private;
-extern void WINAPI check_async_list(LPOVERLAPPED ov, DWORD status);
-extern void finish_async(struct async_private *ovp, DWORD status);
+typedef struct async_fileio
+{
+ async_private async;
+ LPOVERLAPPED lpOverlapped;
+ LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
+ char *buffer;
+ int count;
+} async_fileio;
+
+extern BOOL register_async (async_private *ovp);
+extern void WINAPI check_async_list(async_private *ovp, DWORD status);
+extern void finish_async(async_private *ovp);
/* locale-independent case conversion */
inline static char FILE_tolower( char c )
@@ -83,7 +106,6 @@
DWORD attributes, HANDLE template, BOOL fail_read_only,
UINT drive_type );
extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa );
-extern BOOL FILE_StartAsync(HANDLE handle, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status);
extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG);
diff -ruX diffignore CVS/wine/scheduler/synchro.c MW/wine/scheduler/synchro.c
--- CVS/wine/scheduler/synchro.c Tue Jan 8 18:53:41 2002
+++ MW/wine/scheduler/synchro.c Wed Jan 9 20:27:16 2002
@@ -36,27 +36,60 @@
}
}
-static void CALLBACK call_completion_routine(ULONG_PTR data)
+/***********************************************************************
+ * register_async (INTERNAL)
+ *
+ * Manipulate async request queues.
+ */
+BOOL register_async (async_private *ovp)
{
- async_private* ovp = (async_private*)data;
+ BOOL ret;
+ DWORD status = ovp->ops->get_status (ovp);
- ovp->completion_func(ovp->lpOverlapped->Internal,
- ovp->lpOverlapped->InternalHigh,
- ovp->lpOverlapped);
- ovp->completion_func=NULL;
- HeapFree(GetProcessHeap(), 0, ovp);
-}
+ /* STATUS_USER_APC means this is a new request */
+ /* STATUS_PENDING means this request is rescheduled (IO incomplete) */
-void finish_async(async_private *ovp, DWORD status)
-{
- ovp->lpOverlapped->Internal=status;
+ if (status == STATUS_USER_APC)
+ {
+ status = STATUS_PENDING;
+ ovp->ops->set_status (ovp, status);
+
+ /* 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;
+ }
- /* call ReadFileEx/WriteFileEx's overlapped completion function */
- if(ovp->completion_func)
+ /* The server call will destroy all except PENDING requests */
+ SERVER_START_REQ(register_async)
{
- QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp);
+ req->handle = ovp->handle;
+ req->overlapped = ovp;
+ req->type = ovp->type;
+ req->count = ovp->ops->get_count (ovp);
+ req->func = check_async_list;
+ req->status = status;
+ ret = wine_server_call( req );
}
+ SERVER_END_REQ;
+
+ if (ret) ovp->ops->set_status ( ovp, GetLastError() );
+
+ if ( ovp->ops->get_status (ovp) != STATUS_PENDING )
+ finish_async (ovp);
+ return !ret;
+}
+
+/***********************************************************************
+ * finish_async (INTERNAL)
+ *
+ * Called after completion or cancellation of an async request.
+ * Note: The completion status must be set already.
+ */
+void finish_async(async_private *ovp)
+{
/* remove it from the active list */
if(ovp->prev)
ovp->prev->next = ovp->next;
@@ -70,7 +103,9 @@
ovp->prev=NULL;
close(ovp->fd);
- if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp);
+
+ /* Queue completion function unconditionally */
+ QueueUserAPC(ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp);
}
/***********************************************************************
@@ -78,30 +113,33 @@
*
* Process a status event from the server.
*/
-void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status)
+void WINAPI check_async_list(async_private *asp, DWORD status)
{
- async_private *ovp;
+ async_private *ovp = NULL;
+ DWORD ovp_status;
/* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */
- for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next)
- if(ovp->lpOverlapped == overlapped)
- break;
+ for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
- if(!ovp)
- return;
+ if(!ovp) return;
if(status != STATUS_ALERTED)
- ovp->lpOverlapped->Internal = status;
+ {
+ ovp_status = status;
+ ovp->ops->set_status (ovp, status);
+ }
+ else ovp_status = ovp->ops->get_status (ovp);
- if(ovp->lpOverlapped->Internal==STATUS_PENDING)
- {
+ if( ovp_status == STATUS_PENDING)
+ {
ovp->func(ovp);
- FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal);
- }
+ register_async (ovp);
+ ovp_status = ovp->ops->get_status (ovp);
+ }
- if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
- finish_async(ovp,ovp->lpOverlapped->Internal);
+ if( ovp_status != STATUS_PENDING )
+ finish_async(ovp);
}
diff -ruX diffignore CVS/wine/server/async.c MW/wine/server/async.c
--- CVS/wine/server/async.c Wed Jan 2 12:50:04 2002
+++ MW/wine/server/async.c Wed Jan 9 20:04:53 2002
@@ -177,3 +177,28 @@
release_object(obj);
}
+DECL_HANDLER(cancel_async)
+{
+ struct object *obj;
+
+ if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL)) )
+ return;
+
+ if(obj->ops->queue_async)
+ {
+ struct async_queue *q = obj->ops->queue_async(obj, NULL, req->type, 0);
+ struct async *async;
+
+ async = find_async(q, current, req->overlapped);
+ if (async)
+ {
+ destroy_async(async);
+ reply->cancelled = 1;
+ set_select_events(obj,obj->ops->get_poll_events(obj));
+ }
+ else reply->cancelled = 0;
+ }
+
+ release_object(obj);
+}
+
diff -ruX diffignore CVS/wine/server/protocol.def MW/wine/server/protocol.def
--- CVS/wine/server/protocol.def Tue Jan 8 18:58:28 2002
+++ MW/wine/server/protocol.def Wed Jan 9 19:52:33 2002
@@ -1535,7 +1535,7 @@
#define SERIALINFO_SET_ERROR 0x04
-/* Create/Destroy an async I/O */
+/* Create / reschedule an async I/O */
@REQ(register_async)
handle_t handle; /* handle to comm port, socket or file */
void* func;
@@ -1549,6 +1549,14 @@
#define ASYNC_TYPE_WRITE 0x02
#define ASYNC_TYPE_WAIT 0x03
+/* Cancel an async I/O */
+@REQ(cancel_async)
+ handle_t handle;
+ int type;
+ void* overlapped;
+@REPLY
+ int cancelled;
+@END
/* Create a named pipe */
@REQ(create_named_pipe)