Use poll() on the client-side during server waits to implement
overlapped I/O.
This commit is contained in:
parent
a5a872efca
commit
1c32a46d5a
|
@ -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 @@ BOOL WINAPI GetCommModemStatus(
|
|||
#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 @@ BOOL WINAPI WaitCommEvent(
|
|||
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)
|
||||
*
|
||||
|
|
254
files/file.c
254
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 @@ BOOL WINAPI GetOverlappedResult(
|
|||
*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 @@ static void FILE_AsyncReadService(void **args)
|
|||
|
||||
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 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
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 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
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 @@ static void FILE_AsyncWriteService(void **args)
|
|||
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 @@ static void FILE_AsyncWriteService(void **args)
|
|||
|
||||
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 @@ static void FILE_AsyncWriteService(void **args)
|
|||
|
||||
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 @@ async_end:
|
|||
*/
|
||||
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 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
{
|
||||
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 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* WIN16_hread
|
||||
*/
|
||||
|
|
|
@ -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 @@ typedef struct
|
|||
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 )
|
||||
{
|
||||
|
|
|
@ -1356,28 +1356,15 @@ struct set_serial_info_request
|
|||
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 @@ enum request
|
|||
REQ_get_serial_info,
|
||||
REQ_set_serial_info,
|
||||
REQ_create_async,
|
||||
REQ_async_result,
|
||||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
|
@ -1608,10 +1594,9 @@ union generic_request
|
|||
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 */
|
||||
|
|
|
@ -100,10 +100,11 @@ typedef struct _TEB
|
|||
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 */
|
||||
|
|
|
@ -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 @@ inline static void get_timeout( struct timeval *when, int timeout )
|
|||
}
|
||||
}
|
||||
|
||||
#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 @@ static int wait_reply( void *cookie )
|
|||
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 @@ static void call_apcs( BOOL alertable )
|
|||
case APC_NONE:
|
||||
return; /* no more APCs */
|
||||
case APC_ASYNC:
|
||||
proc( &args[0] );
|
||||
break;
|
||||
case APC_USER:
|
||||
proc( args[0] );
|
||||
|
|
253
server/async.c
253
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,19 +153,9 @@ extern int create_anonymous_file(void);
|
|||
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 */
|
||||
|
||||
|
|
|
@ -176,7 +176,6 @@ DECL_HANDLER(create_serial);
|
|||
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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(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 */
|
||||
|
||||
|
|
|
@ -173,76 +173,25 @@ static int serial_get_info( struct object *obj, struct get_file_info_request *re
|
|||
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)
|
||||
|
|
|
@ -1477,22 +1477,13 @@ static void dump_set_serial_info_request( const struct set_serial_info_request *
|
|||
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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(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 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"get_serial_info",
|
||||
"set_serial_info",
|
||||
"create_async",
|
||||
"async_result",
|
||||
};
|
||||
|
||||
/* ### make_requests end ### */
|
||||
|
|
Loading…
Reference in New Issue