The patch below implements my ideas from the "struct async_private needs generalization for Winsock" thread.
It's a patch against CVS 2002-01-08.
The Winsock stuff is still missing, that's the next step. This is only a trivial recoding of the File IO (compiles, successfully tested with my async file IO test code), whith the "generic" fields in async_private and the "fileio-specific" fields in the rest of the async_fileio structure.
Note: Since it seems agreeable to use the lpOverlapped in Winsock the same way as for file IO, I made lpOverlapped a "generic" field.
Mike (or other people interested), if you can test this against your serial port code I'd be grateful.
Martin
Patch file: async_private.diff Purpose: New winsock-friendly async_private implementation Created: 2002-01-08 Applies: CVS 2002-01-08
ChangeLog:
wine/include/file.h: struct async_private: - remove buffer, count, completion_func fields. - add call_completion field (callback function that calls the completion function). struct async_fileio: - "Derived" from async_private, contains. remove buffer, count, completion_func fields.
wine/scheduler/synchro.c: call_completion_routine(): function removed. finish_async(): use ovp->completion_func instead of call_completion_routine. check_async_list(): Initialize ovp.
wine/files/file.c: fileio_call_completion_func(): New function, FileIO-specific callback. FILE_AsyncReadService(): - use struct async_fileio for specific fields. FILE_AsyncWriteService(): - dito. FILE_ReadFileEx(): - use async_fileio struct for overlapped initialization. - initialize ovp->call_completion field. FILE_WriteFileEx(): - dito.
dlls/kernel/comm.c: COMM_WaitCommEventService(): - use struct async_fileio for "buffer" field. COMM_WaitCommEvent(): - see FILE_ReadFileEx().
Martin Wilck Martin.Wilck@Fujitsu-Siemens.com
diff -ruX diffignore CVS/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c --- CVS/wine/dlls/kernel/comm.c Tue Jan 8 17:43:25 2002 +++ MW/wine/dlls/kernel/comm.c Tue Jan 8 17:47:41 2002 @@ -1515,11 +1515,12 @@ static void COMM_WaitCommEventService(async_private *ovp) { LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; + async_fileio *fileio = (async_fileio*) ovp;
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) { @@ -1556,26 +1557,27 @@ 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->lpOverlapped = lpOverlapped; - ovp->func = COMM_WaitCommEventService; + ovp->async.handle = hFile; + ovp->async.fd = fd; + ovp->async.type = ASYNC_TYPE_WAIT; + ovp->async.lpOverlapped = lpOverlapped; + ovp->async.func = COMM_WaitCommEventService; + ovp->async.call_completion = NULL; 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; + ovp->async.next = NtCurrentTeb()->pending_list; + ovp->async.prev = NULL; + if(ovp->async.next) + ovp->async.next->prev=&ovp->async; + NtCurrentTeb()->pending_list = &ovp->async;
/* start an ASYNCHRONOUS WaitCommEvent */ SERVER_START_REQ( register_async ) diff -ruX diffignore CVS/wine/files/file.c MW/wine/files/file.c --- CVS/wine/files/file.c Tue Jan 8 17:43:51 2002 +++ MW/wine/files/file.c Tue Jan 8 17:47:41 2002 @@ -1298,6 +1298,21 @@ }
/*********************************************************************** + * fileio_call_completion_func (INTERNAL) + */ +void CALLBACK fileio_call_completion_func (ULONG_PTR data) +{ + async_fileio *ovp = (async_fileio*) data; + TRACE ("data: %p\n", ovp); + + ovp->completion_func(ovp->async.lpOverlapped->Internal, + ovp->async.lpOverlapped->InternalHigh, + ovp->async.lpOverlapped); + ovp->completion_func=NULL; + HeapFree(GetProcessHeap(), 0, ovp); +} + +/*********************************************************************** * FILE_AsyncReadService (INTERNAL) * * This function is called while the client is waiting on the @@ -1305,18 +1320,19 @@ */ static void FILE_AsyncReadService(async_private *ovp) { + async_fileio *fileio = (async_fileio*) ovp; LPOVERLAPPED lpOverlapped = ovp->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))) { @@ -1336,7 +1352,7 @@ lpOverlapped->InternalHigh += result; TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
- if(lpOverlapped->InternalHigh < ovp->count) + if(lpOverlapped->InternalHigh < fileio->count) r = STATUS_PENDING; else r = STATUS_SUCCESS; @@ -1352,7 +1368,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", @@ -1372,7 +1388,7 @@ 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,21 +1396,23 @@ close(fd); return FALSE; } - ovp->lpOverlapped = overlapped; - ovp->count = bytesToRead; + + ovp->async.handle = hFile; + ovp->async.fd = fd; + ovp->async.type = ASYNC_TYPE_READ; + ovp->async.lpOverlapped = overlapped; + ovp->async.func = FILE_AsyncReadService; + ovp->async.call_completion = (lpCompletionRoutine ? fileio_call_completion_func : NULL); ovp->completion_func = lpCompletionRoutine; - ovp->func = FILE_AsyncReadService; ovp->buffer = buffer; - ovp->fd = fd; - ovp->type = ASYNC_TYPE_READ; - ovp->handle = hFile; + ovp->count = bytesToRead;
/* 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->async.next = NtCurrentTeb()->pending_list; + ovp->async.prev = NULL; + if(ovp->async.next) + ovp->async.next->prev = &ovp->async; + NtCurrentTeb()->pending_list = &ovp->async;
if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) ) { @@ -1550,18 +1568,19 @@ */ static void FILE_AsyncWriteService(struct async_private *ovp) { + async_fileio *fileio = (async_fileio *) ovp; LPOVERLAPPED lpOverlapped = ovp->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))) { @@ -1578,9 +1597,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; @@ -1596,7 +1615,7 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - async_private *ovp; + async_fileio *ovp;
TRACE("file %d to buf %p num %ld %p func %p stub\n", hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); @@ -1616,34 +1635,35 @@ 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); return FALSE; } - ovp->lpOverlapped = overlapped; - ovp->func = FILE_AsyncWriteService; + ovp->async.handle = hFile; + ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); + ovp->async.type = ASYNC_TYPE_WRITE; + ovp->async.lpOverlapped = overlapped; + ovp->async.func = FILE_AsyncWriteService; + ovp->async.call_completion = (lpCompletionRoutine ? fileio_call_completion_func : NULL); 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) + if(ovp->async.fd <0) { HeapFree(GetProcessHeap(), 0, ovp); return FALSE; }
/* 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->async.next = NtCurrentTeb()->pending_list; + ovp->async.prev = NULL; + if(ovp->async.next) + ovp->async.next->prev = &ovp->async; + NtCurrentTeb()->pending_list = &ovp->async;
return TRUE; } diff -ruX diffignore CVS/wine/include/file.h MW/wine/include/file.h --- CVS/wine/include/file.h Tue Jan 8 17:43:45 2002 +++ MW/wine/include/file.h Tue Jan 8 17:47:41 2002 @@ -33,20 +33,31 @@
/* 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); + +extern void CALLBACK fileio_call_completion_func (ULONG_PTR data); + 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; + HANDLE handle; + int fd; + int type; + LPOVERLAPPED lpOverlapped; + async_handler func; + async_call_completion_func call_completion; + struct async_private *next; + struct async_private *prev; } async_private; + +typedef struct async_fileio +{ + async_private async; + LPOVERLAPPED_COMPLETION_ROUTINE completion_func; + char *buffer; + int count; +} async_fileio;
extern void WINAPI check_async_list(LPOVERLAPPED ov, DWORD status); extern void finish_async(struct async_private *ovp, DWORD status); diff -ruX diffignore CVS/wine/scheduler/synchro.c MW/wine/scheduler/synchro.c --- CVS/wine/scheduler/synchro.c Tue Jan 8 17:43:37 2002 +++ MW/wine/scheduler/synchro.c Tue Jan 8 17:47:41 2002 @@ -36,25 +36,14 @@ } }
-static void CALLBACK call_completion_routine(ULONG_PTR data) -{ - async_private* ovp = (async_private*)data; - - ovp->completion_func(ovp->lpOverlapped->Internal, - ovp->lpOverlapped->InternalHigh, - ovp->lpOverlapped); - ovp->completion_func=NULL; - HeapFree(GetProcessHeap(), 0, ovp); -} - void finish_async(async_private *ovp, DWORD status) { ovp->lpOverlapped->Internal=status;
- /* call ReadFileEx/WriteFileEx's overlapped completion function */ - if(ovp->completion_func) + /* call overlapped completion function */ + if(ovp->call_completion) { - QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp); + QueueUserAPC(ovp->call_completion,GetCurrentThread(),(ULONG_PTR)ovp); }
/* remove it from the active list */ @@ -70,7 +59,7 @@ ovp->prev=NULL;
close(ovp->fd); - if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp); + if(!ovp->call_completion) HeapFree(GetProcessHeap(), 0, ovp); }
/*********************************************************************** @@ -80,7 +69,7 @@ */ void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status) { - async_private *ovp; + async_private *ovp = NULL;
/* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */