Commit 6f011c08 authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

- move async activation into the server

- implement async queues
parent 9788815b
...@@ -1512,27 +1512,19 @@ BOOL WINAPI GetCommModemStatus( ...@@ -1512,27 +1512,19 @@ BOOL WINAPI GetCommModemStatus(
* This function is called while the client is waiting on the * This function is called while the client is waiting on the
* server, so we can't make any server calls here. * server, so we can't make any server calls here.
*/ */
static void COMM_WaitCommEventService(async_private *ovp, int events) static void COMM_WaitCommEventService(async_private *ovp)
{ {
LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
TRACE("overlapped %p wait complete %p <- %x\n",lpOverlapped,ovp->buffer,events); TRACE("overlapped %p\n",lpOverlapped);
if(events&POLLNVAL)
{ /* FIXME: detect other events */
lpOverlapped->Internal = STATUS_HANDLES_CLOSED;
return;
}
if(ovp->buffer)
{
if(events&POLLIN)
*ovp->buffer = EV_RXCHAR; *ovp->buffer = EV_RXCHAR;
}
lpOverlapped->Internal = STATUS_SUCCESS; lpOverlapped->Internal = STATUS_SUCCESS;
} }
/*********************************************************************** /***********************************************************************
* COMM_WaitCommEvent (INTERNAL) * COMM_WaitCommEvent (INTERNAL)
* *
...@@ -1560,20 +1552,6 @@ static BOOL COMM_WaitCommEvent( ...@@ -1560,20 +1552,6 @@ static BOOL COMM_WaitCommEvent(
lpOverlapped->Offset = 0; lpOverlapped->Offset = 0;
lpOverlapped->OffsetHigh = 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=wine_server_call_err( req );
}
SERVER_END_REQ;
if (ret)
return FALSE;
fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
if(fd<0) if(fd<0)
return FALSE; return FALSE;
...@@ -1585,15 +1563,13 @@ static BOOL COMM_WaitCommEvent( ...@@ -1585,15 +1563,13 @@ static BOOL COMM_WaitCommEvent(
return FALSE; return FALSE;
} }
ovp->lpOverlapped = lpOverlapped; ovp->lpOverlapped = lpOverlapped;
ovp->timeout = 0;
ovp->tv.tv_sec = 0;
ovp->tv.tv_usec = 0;
ovp->event = POLLIN;
ovp->func = COMM_WaitCommEventService; ovp->func = COMM_WaitCommEventService;
ovp->buffer = (char *)lpdwEvents; ovp->buffer = (char *)lpdwEvents;
ovp->fd = fd; ovp->fd = fd;
ovp->count = 0; ovp->count = 0;
ovp->completion_func = 0; ovp->completion_func = 0;
ovp->type = ASYNC_TYPE_WAIT;
ovp->handle = hFile;
ovp->next = NtCurrentTeb()->pending_list; ovp->next = NtCurrentTeb()->pending_list;
ovp->prev = NULL; ovp->prev = NULL;
...@@ -1601,6 +1577,21 @@ static BOOL COMM_WaitCommEvent( ...@@ -1601,6 +1577,21 @@ static BOOL COMM_WaitCommEvent(
ovp->next->prev=ovp; ovp->next->prev=ovp;
NtCurrentTeb()->pending_list = 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;
if (!ret)
SetLastError(ERROR_IO_PENDING); SetLastError(ERROR_IO_PENDING);
return FALSE; return FALSE;
......
...@@ -1248,12 +1248,34 @@ BOOL WINAPI GetOverlappedResult( ...@@ -1248,12 +1248,34 @@ BOOL WINAPI GetOverlappedResult(
/*********************************************************************** /***********************************************************************
* 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.@) * CancelIo (KERNEL32.@)
*/ */
BOOL WINAPI CancelIo(HANDLE handle) BOOL WINAPI CancelIo(HANDLE handle)
{ {
FIXME("(%d) stub\n",handle); return FILE_StartAsync(handle, NULL, ASYNC_TYPE_NONE, 0, STATUS_CANCELLED);
return FALSE;
} }
/*********************************************************************** /***********************************************************************
...@@ -1262,28 +1284,12 @@ BOOL WINAPI CancelIo(HANDLE handle) ...@@ -1262,28 +1284,12 @@ BOOL WINAPI CancelIo(HANDLE handle)
* This function is called while the client is waiting on the * This function is called while the client is waiting on the
* server, so we can't make any server calls here. * server, so we can't make any server calls here.
*/ */
static void FILE_AsyncReadService(async_private *ovp, int events) static void FILE_AsyncReadService(async_private *ovp)
{ {
LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
int result, r; int result, r;
TRACE("%p %p %08x\n", lpOverlapped, ovp->buffer, events ); TRACE("%p %p\n", lpOverlapped, ovp->buffer );
/* 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;
goto async_end;
}
/* check to see if the data is ready (non-blocking) */ /* check to see if the data is ready (non-blocking) */
result = read(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh], result = read(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh],
...@@ -1316,41 +1322,6 @@ async_end: ...@@ -1316,41 +1322,6 @@ async_end:
lpOverlapped->Internal = r; lpOverlapped->Internal = r;
} }
/* 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_GetTimeout (INTERNAL)
*/
static BOOL FILE_GetTimeout(HANDLE hFile, DWORD txcount, DWORD type, int *timeout)
{
BOOL ret;
SERVER_START_REQ(create_async)
{
req->count = txcount;
req->type = type;
req->file_handle = hFile;
ret = wine_server_call( req );
if(timeout)
*timeout = reply->timeout;
}
SERVER_END_REQ;
return !ret;
}
/*********************************************************************** /***********************************************************************
* FILE_ReadFileEx (INTERNAL) * FILE_ReadFileEx (INTERNAL)
*/ */
...@@ -1359,7 +1330,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ...@@ -1359,7 +1330,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{ {
async_private *ovp; async_private *ovp;
int fd, timeout=0; int fd;
TRACE("file %d to buf %p num %ld %p func %p\n", TRACE("file %d to buf %p num %ld %p func %p\n",
hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine); hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
...@@ -1372,12 +1343,6 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ...@@ -1372,12 +1343,6 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
return FALSE; return FALSE;
} }
if ( !FILE_GetTimeout(hFile, bytesToRead, ASYNC_TYPE_READ, &timeout ) )
{
TRACE("FILE_GetTimeout failed\n");
return FALSE;
}
fd = FILE_GetUnixHandle( hFile, GENERIC_READ ); fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
if(fd<0) if(fd<0)
{ {
...@@ -1396,13 +1361,11 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ...@@ -1396,13 +1361,11 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
ovp->lpOverlapped = overlapped; ovp->lpOverlapped = overlapped;
ovp->count = bytesToRead; ovp->count = bytesToRead;
ovp->completion_func = lpCompletionRoutine; ovp->completion_func = lpCompletionRoutine;
ovp->timeout = timeout;
gettimeofday(&ovp->tv,NULL);
add_timeout(&ovp->tv,timeout);
ovp->event = POLLIN;
ovp->func = FILE_AsyncReadService; ovp->func = FILE_AsyncReadService;
ovp->buffer = buffer; ovp->buffer = buffer;
ovp->fd = fd; ovp->fd = fd;
ovp->type = ASYNC_TYPE_READ;
ovp->handle = hFile;
/* hook this overlap into the pending async operation list */ /* hook this overlap into the pending async operation list */
ovp->next = NtCurrentTeb()->pending_list; ovp->next = NtCurrentTeb()->pending_list;
...@@ -1411,6 +1374,13 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ...@@ -1411,6 +1374,13 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
ovp->next->prev = ovp; ovp->next->prev = ovp;
NtCurrentTeb()->pending_list = ovp; NtCurrentTeb()->pending_list = ovp;
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;
}
return TRUE; return TRUE;
} }
...@@ -1548,28 +1518,12 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ...@@ -1548,28 +1518,12 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
* This function is called while the client is waiting on the * This function is called while the client is waiting on the
* server, so we can't make any server calls here. * server, so we can't make any server calls here.
*/ */
static void FILE_AsyncWriteService(struct async_private *ovp, int events) static void FILE_AsyncWriteService(struct async_private *ovp)
{ {
LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
int result, r; int result, r;
TRACE("(%p %p %08x)\n",lpOverlapped,ovp->buffer,events); TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
/* 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("write timed out\n");
r = STATUS_TIMEOUT;
goto async_end;
}
/* write some data (non-blocking) */ /* write some data (non-blocking) */
result = write(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh], result = write(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh],
...@@ -1609,7 +1563,6 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, ...@@ -1609,7 +1563,6 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{ {
async_private *ovp; async_private *ovp;
int timeout=0;
TRACE("file %d to buf %p num %ld %p func %p stub\n", TRACE("file %d to buf %p num %ld %p func %p stub\n",
hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
...@@ -1623,9 +1576,9 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, ...@@ -1623,9 +1576,9 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
overlapped->Internal = STATUS_PENDING; overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0; overlapped->InternalHigh = 0;
if (!FILE_GetTimeout(hFile, bytesToWrite, ASYNC_TYPE_WRITE, &timeout)) if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
{ {
TRACE("FILE_GetTimeout failed\n"); TRACE("FILE_StartAsync failed\n");
return FALSE; return FALSE;
} }
...@@ -1637,15 +1590,14 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, ...@@ -1637,15 +1590,14 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
return FALSE; return FALSE;
} }
ovp->lpOverlapped = overlapped; ovp->lpOverlapped = overlapped;
ovp->timeout = timeout;
gettimeofday(&ovp->tv,NULL);
add_timeout(&ovp->tv,timeout);
ovp->event = POLLOUT;
ovp->func = FILE_AsyncWriteService; ovp->func = FILE_AsyncWriteService;
ovp->buffer = (LPVOID) buffer; ovp->buffer = (LPVOID) buffer;
ovp->count = bytesToWrite; ovp->count = bytesToWrite;
ovp->completion_func = lpCompletionRoutine; ovp->completion_func = lpCompletionRoutine;
ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
ovp->type = ASYNC_TYPE_WRITE;
ovp->handle = hFile;
if(ovp->fd <0) if(ovp->fd <0)
{ {
HeapFree(GetProcessHeap(), 0, ovp); HeapFree(GetProcessHeap(), 0, ovp);
......
...@@ -33,22 +33,23 @@ typedef struct ...@@ -33,22 +33,23 @@ typedef struct
/* overlapped private structure */ /* overlapped private structure */
struct async_private; struct async_private;
typedef void (*async_handler)(struct async_private *ovp, int revents); typedef void (*async_handler)(struct async_private *ovp);
typedef struct async_private typedef struct async_private
{ {
LPOVERLAPPED lpOverlapped; LPOVERLAPPED lpOverlapped;
HANDLE handle;
int fd; int fd;
int timeout;
struct timeval tv;
int event;
char *buffer; char *buffer;
async_handler func; async_handler func;
int count; int count;
int type;
LPOVERLAPPED_COMPLETION_ROUTINE completion_func; LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
struct async_private *next; struct async_private *next;
struct async_private *prev; struct async_private *prev;
} async_private; } async_private;
extern void check_async_list(LPOVERLAPPED ov, DWORD status);
/* locale-independent case conversion */ /* locale-independent case conversion */
inline static char FILE_tolower( char c ) inline static char FILE_tolower( char c )
{ {
...@@ -80,6 +81,7 @@ extern HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing, ...@@ -80,6 +81,7 @@ extern HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing,
DWORD attributes, HANDLE template, BOOL fail_read_only, DWORD attributes, HANDLE template, BOOL fail_read_only,
UINT drive_type ); UINT drive_type );
extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa ); 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); extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG);
......
...@@ -2181,18 +2181,21 @@ struct set_serial_info_reply ...@@ -2181,18 +2181,21 @@ struct set_serial_info_reply
struct create_async_request struct register_async_request
{ {
struct request_header __header; struct request_header __header;
handle_t file_handle; handle_t handle;
int count; void* func;
int type; int type;
void* overlapped;
int count;
unsigned int status;
}; };
struct create_async_reply struct register_async_reply
{ {
struct reply_header __header; struct reply_header __header;
int timeout;
}; };
#define ASYNC_TYPE_NONE 0x00
#define ASYNC_TYPE_READ 0x01 #define ASYNC_TYPE_READ 0x01
#define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WRITE 0x02
#define ASYNC_TYPE_WAIT 0x03 #define ASYNC_TYPE_WAIT 0x03
...@@ -2699,7 +2702,7 @@ enum request ...@@ -2699,7 +2702,7 @@ enum request
REQ_create_serial, REQ_create_serial,
REQ_get_serial_info, REQ_get_serial_info,
REQ_set_serial_info, REQ_set_serial_info,
REQ_create_async, REQ_register_async,
REQ_create_named_pipe, REQ_create_named_pipe,
REQ_open_named_pipe, REQ_open_named_pipe,
REQ_connect_named_pipe, REQ_connect_named_pipe,
...@@ -2854,7 +2857,7 @@ union generic_request ...@@ -2854,7 +2857,7 @@ union generic_request
struct create_serial_request create_serial_request; struct create_serial_request create_serial_request;
struct get_serial_info_request get_serial_info_request; struct get_serial_info_request get_serial_info_request;
struct set_serial_info_request set_serial_info_request; struct set_serial_info_request set_serial_info_request;
struct create_async_request create_async_request; struct register_async_request register_async_request;
struct create_named_pipe_request create_named_pipe_request; struct create_named_pipe_request create_named_pipe_request;
struct open_named_pipe_request open_named_pipe_request; struct open_named_pipe_request open_named_pipe_request;
struct connect_named_pipe_request connect_named_pipe_request; struct connect_named_pipe_request connect_named_pipe_request;
...@@ -3007,7 +3010,7 @@ union generic_reply ...@@ -3007,7 +3010,7 @@ union generic_reply
struct create_serial_reply create_serial_reply; struct create_serial_reply create_serial_reply;
struct get_serial_info_reply get_serial_info_reply; struct get_serial_info_reply get_serial_info_reply;
struct set_serial_info_reply set_serial_info_reply; struct set_serial_info_reply set_serial_info_reply;
struct create_async_reply create_async_reply; struct register_async_reply register_async_reply;
struct create_named_pipe_reply create_named_pipe_reply; struct create_named_pipe_reply create_named_pipe_reply;
struct open_named_pipe_reply open_named_pipe_reply; struct open_named_pipe_reply open_named_pipe_reply;
struct connect_named_pipe_reply connect_named_pipe_reply; struct connect_named_pipe_reply connect_named_pipe_reply;
...@@ -3035,6 +3038,6 @@ union generic_reply ...@@ -3035,6 +3038,6 @@ union generic_reply
struct get_window_properties_reply get_window_properties_reply; struct get_window_properties_reply get_window_properties_reply;
}; };
#define SERVER_PROTOCOL_VERSION 66 #define SERVER_PROTOCOL_VERSION 67
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -36,14 +36,6 @@ inline static void get_timeout( struct timeval *when, int timeout ) ...@@ -36,14 +36,6 @@ 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 CALLBACK call_completion_routine(ULONG_PTR data) static void CALLBACK call_completion_routine(ULONG_PTR data)
{ {
async_private* ovp = (async_private*)data; async_private* ovp = (async_private*)data;
...@@ -85,90 +77,32 @@ static void finish_async(async_private *ovp, DWORD status) ...@@ -85,90 +77,32 @@ static void finish_async(async_private *ovp, DWORD status)
/*********************************************************************** /***********************************************************************
* check_async_list * check_async_list
* *
* Create a list of fds for poll to check while waiting on the server * Process a status event from 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) void check_async_list(LPOVERLAPPED overlapped, DWORD status)
{
/* 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)
{ {
finish_async(ovp,STATUS_UNSUCCESSFUL); async_private *ovp;
continue;
}
if(ovp->timeout && time_before(&ovp->tv,&now)) /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */
{
finish_async(ovp,STATUS_TIMEOUT);
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))) for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next)
{ if(ovp->lpOverlapped == overlapped)
timeout = (ovp->tv.tv_sec - now.tv_sec) * 1000 break;
+ (ovp->tv.tv_usec - now.tv_usec) / 1000;
timeout_user = ovp;
}
n++;
}
/* if there aren't any active asyncs return */ if(!ovp)
if(n==1)
return; return;
r = poll(fds, n, timeout); if(status != STATUS_ALERTED)
ovp->lpOverlapped->Internal = status;
/* if there were any errors, return immediately */ if(ovp->lpOverlapped->Internal==STATUS_PENDING)
if( (r<0) || (fds[0].revents==POLLNVAL) )
return;
if( r==0 )
{ {
finish_async(timeout_user, STATUS_TIMEOUT); ovp->func(ovp);
continue; FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal);
} }
/* search for async operations that are ready */ if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
for( i=1; i<n; i++) finish_async(ovp,ovp->lpOverlapped->Internal);
{
if (fds[i].revents)
user[i]->func(user[i],fds[i].revents);
if(user[i]->lpOverlapped->Internal!=STATUS_PENDING)
finish_async(user[i],user[i]->lpOverlapped->Internal);
}
if(fds[0].revents == POLLIN)
return;
}
} }
...@@ -184,7 +118,6 @@ static int wait_reply( void *cookie ) ...@@ -184,7 +118,6 @@ static int wait_reply( void *cookie )
for (;;) for (;;)
{ {
int ret; int ret;
if (NtCurrentTeb()->pending_list) check_async_list();
ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) ); ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
if (ret == sizeof(reply)) if (ret == sizeof(reply))
{ {
......
...@@ -12,23 +12,168 @@ ...@@ -12,23 +12,168 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h>
#include "handle.h" #include "handle.h"
#include "thread.h" #include "thread.h"
#include "request.h" #include "request.h"
#include "async.h"
DECL_HANDLER(create_async) void destroy_async( struct async *async )
{
struct async_queue *aq = async->q;
/*fprintf(stderr,"destroyed async %p\n",async->overlapped); */
if(async->timeout)
remove_timeout_user(async->timeout);
async->timeout = NULL;
if(async->prev)
async->prev->next = async->next;
else
aq->head = async->next;
if(async->next)
async->next->prev = async->prev;
else
aq->tail = async->prev;
async->q = NULL;
async->next = NULL;
async->prev = NULL;
free(async);
}
void async_notify(struct async *async, int status)
{
/* fprintf(stderr,"notifying %p!\n",async->overlapped); */
async->status = status;
thread_queue_apc(async->thread, NULL, async->func, APC_ASYNC, 1, 2, async->overlapped, status);
}
void destroy_async_queue( struct async_queue *q )
{
while(q->head)
{
async_notify(q->head, STATUS_HANDLES_CLOSED);
destroy_async(q->head);
}
}
struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped)
{
struct async *async;
/* fprintf(stderr,"find_async: %p\n",overlapped); */
if(!q)
return NULL;
for(async = q->head; async; async = async->next)
if((async->overlapped==overlapped) && (async->thread == thread))
return async;
return NULL;
}
void async_insert(struct async_queue *q, struct async *async)
{
async->q = q;
async->prev = q->tail;
async->next = NULL;
if(q->tail)
q->tail->next = async;
else
q->head = async;
q->tail = async;
}
static void async_callback(void *private)
{
struct async *async = (struct async *)private;
/* fprintf(stderr,"%p timeout out\n",async->overlapped); */
async->timeout = NULL;
async_notify(async, STATUS_TIMEOUT);
destroy_async(async);
}
struct async *create_async(struct object *obj, struct thread *thread, void *func,
void *overlapped)
{
struct async *async = (struct async *) malloc(sizeof(struct async));
if(!async)
{
set_error(STATUS_NO_MEMORY);
return NULL;
}
async->obj = obj;
async->thread = thread;
async->func = func;
async->overlapped = overlapped;
async->next = NULL;
async->prev = NULL;
async->q = NULL;
async->status = STATUS_PENDING;
async->timeout = NULL;
return async;
}
void async_add_timeout(struct async *async, int timeout)
{
if(timeout)
{
gettimeofday( &async->when, 0 );
add_timeout( &async->when, timeout );
async->timeout = add_timeout_user( &async->when, async_callback, async );
}
}
DECL_HANDLER(register_async)
{ {
struct object *obj; struct object *obj;
if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) ) if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL)) )
return; return;
/* FIXME: check if this object is allowed to do overlapped I/O */ 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(req->status==STATUS_PENDING)
{
if(!async)
async = create_async(obj, current, req->func, req->overlapped);
/* FIXME: this should be a function pointer */ if(async)
reply->timeout = get_serial_async_timeout(obj,req->type,req->count); {
async->status = req->status;
if(!obj->ops->queue_async(obj, async, req->type, req->count))
destroy_async(async);
}
}
else
{
if(async)
destroy_async(async);
else
set_error(STATUS_INVALID_PARAMETER);
}
set_select_events(obj,obj->ops->get_poll_events(obj));
}
else
set_error(STATUS_INVALID_HANDLE);
release_object(obj); release_object(obj);
} }
#ifndef _SERVER_ASYNC_
#define _SERVER_ASYNC_
#include <sys/time.h>
#include "object.h"
struct async_queue;
struct async
{
struct object *obj;
struct thread *thread;
void *func;
void *overlapped;
unsigned int status;
struct timeval when;
struct timeout_user *timeout;
struct async *next,*prev;
struct async_queue *q;
};
struct async_queue
{
struct async *head;
struct async *tail;
};
void destroy_async( struct async *async );
void destroy_async_queue( struct async_queue *q );
void async_notify(struct async *async, int status);
struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped);
void async_insert(struct async_queue *q, struct async *async);
struct async *create_async(struct object *obj, struct thread *thread,
void *func, void *overlapped);
void async_add_timeout(struct async *async, int timeout);
static inline void init_async_queue(struct async_queue *q)
{
q->head = q->tail = NULL;
}
#define IS_READY(q) (((q).head) && ((q).head->status==STATUS_PENDING))
#endif /* _SERVER_ASYNC_ */
...@@ -59,6 +59,7 @@ static const struct object_ops atom_table_ops = ...@@ -59,6 +59,7 @@ static const struct object_ops atom_table_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
atom_table_destroy /* destroy */ atom_table_destroy /* destroy */
}; };
......
...@@ -37,6 +37,7 @@ static const struct object_ops change_ops = ...@@ -37,6 +37,7 @@ static const struct object_ops change_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
no_destroy /* destroy */ no_destroy /* destroy */
}; };
......
...@@ -40,6 +40,7 @@ static const struct object_ops console_input_ops = ...@@ -40,6 +40,7 @@ static const struct object_ops console_input_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
console_get_file_info, /* get_file_info */ console_get_file_info, /* get_file_info */
NULL, /* queue_async */
console_input_destroy /* destroy */ console_input_destroy /* destroy */
}; };
...@@ -68,6 +69,7 @@ static const struct object_ops console_input_events_ops = ...@@ -68,6 +69,7 @@ static const struct object_ops console_input_events_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
console_input_events_destroy /* destroy */ console_input_events_destroy /* destroy */
}; };
...@@ -108,6 +110,7 @@ static const struct object_ops screen_buffer_ops = ...@@ -108,6 +110,7 @@ static const struct object_ops screen_buffer_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
console_get_file_info, /* get_file_info */ console_get_file_info, /* get_file_info */
NULL, /* queue_async */
screen_buffer_destroy /* destroy */ screen_buffer_destroy /* destroy */
}; };
......
...@@ -58,6 +58,7 @@ static const struct object_ops debug_event_ops = ...@@ -58,6 +58,7 @@ static const struct object_ops debug_event_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
debug_event_destroy /* destroy */ debug_event_destroy /* destroy */
}; };
...@@ -78,6 +79,7 @@ static const struct object_ops debug_ctx_ops = ...@@ -78,6 +79,7 @@ static const struct object_ops debug_ctx_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
debug_ctx_destroy /* destroy */ debug_ctx_destroy /* destroy */
}; };
......
...@@ -44,6 +44,7 @@ static const struct object_ops device_ops = ...@@ -44,6 +44,7 @@ static const struct object_ops device_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
device_get_info, /* get_file_info */ device_get_info, /* get_file_info */
NULL, /* queue_async */
no_destroy /* destroy */ no_destroy /* destroy */
}; };
......
...@@ -38,6 +38,7 @@ static const struct object_ops event_ops = ...@@ -38,6 +38,7 @@ static const struct object_ops event_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
no_destroy /* destroy */ no_destroy /* destroy */
}; };
......
...@@ -65,6 +65,7 @@ static const struct object_ops file_ops = ...@@ -65,6 +65,7 @@ static const struct object_ops file_ops =
file_get_fd, /* get_fd */ file_get_fd, /* get_fd */
file_flush, /* flush */ file_flush, /* flush */
file_get_info, /* get_file_info */ file_get_info, /* get_file_info */
NULL, /* queue_async */
file_destroy /* destroy */ file_destroy /* destroy */
}; };
......
...@@ -92,6 +92,7 @@ static const struct object_ops handle_table_ops = ...@@ -92,6 +92,7 @@ static const struct object_ops handle_table_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
handle_table_destroy /* destroy */ handle_table_destroy /* destroy */
}; };
......
...@@ -51,6 +51,7 @@ static const struct object_ops mapping_ops = ...@@ -51,6 +51,7 @@ static const struct object_ops mapping_ops =
mapping_get_fd, /* get_fd */ mapping_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
mapping_get_info, /* get_file_info */ mapping_get_info, /* get_file_info */
NULL, /* queue_async */
mapping_destroy /* destroy */ mapping_destroy /* destroy */
}; };
......
...@@ -42,6 +42,7 @@ static const struct object_ops mutex_ops = ...@@ -42,6 +42,7 @@ static const struct object_ops mutex_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
mutex_destroy /* destroy */ mutex_destroy /* destroy */
}; };
......
...@@ -80,6 +80,7 @@ static const struct object_ops named_pipe_ops = ...@@ -80,6 +80,7 @@ static const struct object_ops named_pipe_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
named_pipe_destroy /* destroy */ named_pipe_destroy /* destroy */
}; };
...@@ -101,6 +102,7 @@ static const struct object_ops pipe_user_ops = ...@@ -101,6 +102,7 @@ static const struct object_ops pipe_user_ops =
pipe_user_get_fd, /* get_fd */ pipe_user_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
pipe_user_get_info, /* get_file_info */ pipe_user_get_info, /* get_file_info */
NULL, /* queue_async */
pipe_user_destroy /* destroy */ pipe_user_destroy /* destroy */
}; };
......
...@@ -22,6 +22,7 @@ struct process; ...@@ -22,6 +22,7 @@ struct process;
struct file; struct file;
struct wait_queue_entry; struct wait_queue_entry;
struct async; struct async;
struct async_queue;
/* operations valid on all objects */ /* operations valid on all objects */
struct object_ops struct object_ops
...@@ -48,6 +49,8 @@ struct object_ops ...@@ -48,6 +49,8 @@ struct object_ops
int (*flush)(struct object *); int (*flush)(struct object *);
/* get file information */ /* get file information */
int (*get_file_info)(struct object *,struct get_file_info_reply *); int (*get_file_info)(struct object *,struct get_file_info_reply *);
/* queue an async operation */
struct async_queue* (*queue_async)(struct object *, struct async *async, int type, int count);
/* destroy on refcount == 0 */ /* destroy on refcount == 0 */
void (*destroy)(struct object *); void (*destroy)(struct object *);
}; };
......
...@@ -53,6 +53,7 @@ static const struct object_ops pipe_ops = ...@@ -53,6 +53,7 @@ static const struct object_ops pipe_ops =
pipe_get_fd, /* get_fd */ pipe_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
pipe_get_info, /* get_file_info */ pipe_get_info, /* get_file_info */
NULL, /* queue_async */
pipe_destroy /* destroy */ pipe_destroy /* destroy */
}; };
......
...@@ -53,6 +53,7 @@ static const struct object_ops process_ops = ...@@ -53,6 +53,7 @@ static const struct object_ops process_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
process_destroy /* destroy */ process_destroy /* destroy */
}; };
...@@ -92,6 +93,7 @@ static const struct object_ops startup_info_ops = ...@@ -92,6 +93,7 @@ static const struct object_ops startup_info_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
startup_info_destroy /* destroy */ startup_info_destroy /* destroy */
}; };
......
...@@ -1529,14 +1529,16 @@ enum message_type ...@@ -1529,14 +1529,16 @@ enum message_type
#define SERIALINFO_SET_ERROR 0x04 #define SERIALINFO_SET_ERROR 0x04
/* Create an async I/O */ /* Create/Destroy an async I/O */
@REQ(create_async) @REQ(register_async)
handle_t file_handle; /* handle to comm port, socket or file */ handle_t handle; /* handle to comm port, socket or file */
int count; void* func;
int type; int type;
@REPLY void* overlapped;
int timeout; int count;
unsigned int status;
@END @END
#define ASYNC_TYPE_NONE 0x00
#define ASYNC_TYPE_READ 0x01 #define ASYNC_TYPE_READ 0x01
#define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WRITE 0x02
#define ASYNC_TYPE_WAIT 0x03 #define ASYNC_TYPE_WAIT 0x03
......
...@@ -112,6 +112,7 @@ static const struct object_ops msg_queue_ops = ...@@ -112,6 +112,7 @@ static const struct object_ops msg_queue_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
msg_queue_destroy /* destroy */ msg_queue_destroy /* destroy */
}; };
......
...@@ -142,6 +142,7 @@ static const struct object_ops key_ops = ...@@ -142,6 +142,7 @@ static const struct object_ops key_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
key_destroy /* destroy */ key_destroy /* destroy */
}; };
......
...@@ -66,6 +66,7 @@ static const struct object_ops master_socket_ops = ...@@ -66,6 +66,7 @@ static const struct object_ops master_socket_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
master_socket_destroy /* destroy */ master_socket_destroy /* destroy */
}; };
......
...@@ -209,7 +209,7 @@ DECL_HANDLER(kill_win_timer); ...@@ -209,7 +209,7 @@ DECL_HANDLER(kill_win_timer);
DECL_HANDLER(create_serial); DECL_HANDLER(create_serial);
DECL_HANDLER(get_serial_info); DECL_HANDLER(get_serial_info);
DECL_HANDLER(set_serial_info); DECL_HANDLER(set_serial_info);
DECL_HANDLER(create_async); DECL_HANDLER(register_async);
DECL_HANDLER(create_named_pipe); DECL_HANDLER(create_named_pipe);
DECL_HANDLER(open_named_pipe); DECL_HANDLER(open_named_pipe);
DECL_HANDLER(connect_named_pipe); DECL_HANDLER(connect_named_pipe);
...@@ -363,7 +363,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -363,7 +363,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_create_serial, (req_handler)req_create_serial,
(req_handler)req_get_serial_info, (req_handler)req_get_serial_info,
(req_handler)req_set_serial_info, (req_handler)req_set_serial_info,
(req_handler)req_create_async, (req_handler)req_register_async,
(req_handler)req_create_named_pipe, (req_handler)req_create_named_pipe,
(req_handler)req_open_named_pipe, (req_handler)req_open_named_pipe,
(req_handler)req_connect_named_pipe, (req_handler)req_connect_named_pipe,
......
...@@ -38,6 +38,7 @@ static const struct object_ops semaphore_ops = ...@@ -38,6 +38,7 @@ static const struct object_ops semaphore_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
no_destroy /* destroy */ no_destroy /* destroy */
}; };
......
...@@ -2,10 +2,7 @@ ...@@ -2,10 +2,7 @@
* Server-side serial port communications management * Server-side serial port communications management
* *
* Copyright (C) 1998 Alexandre Julliard * Copyright (C) 1998 Alexandre Julliard
* Copyright (C) 2000 Mike McCormack * Copyright (C) 2000,2001 Mike McCormack
*
* TODO:
* Add async read, write and WaitCommEvent handling.
* *
*/ */
...@@ -34,11 +31,15 @@ ...@@ -34,11 +31,15 @@
#include "handle.h" #include "handle.h"
#include "thread.h" #include "thread.h"
#include "request.h" #include "request.h"
#include "async.h"
static void serial_dump( struct object *obj, int verbose ); static void serial_dump( struct object *obj, int verbose );
static int serial_get_fd( struct object *obj ); static int serial_get_fd( struct object *obj );
static int serial_get_info( struct object *obj, struct get_file_info_reply *reply ); static int serial_get_info( struct object *obj, struct get_file_info_reply *reply );
static int serial_get_poll_events( struct object *obj ); static int serial_get_poll_events( struct object *obj );
static struct async_queue * serial_queue_async(struct object *obj, struct async* async, int type, int count);
static void destroy_serial(struct object *obj);
static void serial_poll_event( struct object *obj, int event );
struct serial struct serial
{ {
...@@ -58,6 +59,10 @@ struct serial ...@@ -58,6 +59,10 @@ struct serial
struct termios original; struct termios original;
struct async_queue read_q;
struct async_queue write_q;
struct async_queue wait_q;
/* FIXME: add dcb, comm status, handler module, sharing */ /* FIXME: add dcb, comm status, handler module, sharing */
}; };
...@@ -70,15 +75,14 @@ static const struct object_ops serial_ops = ...@@ -70,15 +75,14 @@ static const struct object_ops serial_ops =
default_poll_signaled, /* signaled */ default_poll_signaled, /* signaled */
no_satisfied, /* satisfied */ no_satisfied, /* satisfied */
serial_get_poll_events, /* get_poll_events */ serial_get_poll_events, /* get_poll_events */
default_poll_event, /* poll_event */ serial_poll_event, /* poll_event */
serial_get_fd, /* get_fd */ serial_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
serial_get_info, /* get_file_info */ serial_get_info, /* get_file_info */
no_destroy /* destroy */ serial_queue_async, /* queue_async */
destroy_serial /* destroy */
}; };
/* SERIAL PORT functions */
static struct serial *create_serial( const char *nameptr, size_t len, unsigned int access, int attributes ) static struct serial *create_serial( const char *nameptr, size_t len, unsigned int access, int attributes )
{ {
struct serial *serial; struct serial *serial;
...@@ -132,10 +136,22 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i ...@@ -132,10 +136,22 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i
serial->writeconst = 0; serial->writeconst = 0;
serial->eventmask = 0; serial->eventmask = 0;
serial->commerror = 0; serial->commerror = 0;
init_async_queue(&serial->read_q);
init_async_queue(&serial->write_q);
init_async_queue(&serial->wait_q);
} }
return serial; return serial;
} }
static void destroy_serial( struct object *obj)
{
struct serial *serial = (struct serial *)obj;
destroy_async_queue(&serial->read_q);
destroy_async_queue(&serial->write_q);
destroy_async_queue(&serial->wait_q);
}
static void serial_dump( struct object *obj, int verbose ) static void serial_dump( struct object *obj, int verbose )
{ {
struct serial *serial = (struct serial *)obj; struct serial *serial = (struct serial *)obj;
...@@ -153,8 +169,16 @@ static int serial_get_poll_events( struct object *obj ) ...@@ -153,8 +169,16 @@ static int serial_get_poll_events( struct object *obj )
struct serial *serial = (struct serial *)obj; struct serial *serial = (struct serial *)obj;
int events = 0; int events = 0;
assert( obj->ops == &serial_ops ); assert( obj->ops == &serial_ops );
if (serial->access & GENERIC_READ) events |= POLLIN;
if (serial->access & GENERIC_WRITE) events |= POLLOUT; if(IS_READY(serial->read_q))
events |= POLLIN;
if(IS_READY(serial->write_q))
events |= POLLOUT;
if(IS_READY(serial->wait_q))
events |= POLLIN;
/* fprintf(stderr,"poll events are %04x\n",events); */
return events; return events;
} }
...@@ -190,25 +214,76 @@ static int serial_get_info( struct object *obj, struct get_file_info_reply *repl ...@@ -190,25 +214,76 @@ static int serial_get_info( struct object *obj, struct get_file_info_reply *repl
return FD_TYPE_TIMEOUT; return FD_TYPE_TIMEOUT;
} }
/* these function calculates the timeout for an async operation static void serial_poll_event(struct object *obj, int event)
on a serial port */ {
int get_serial_async_timeout(struct object *obj, int type, int count) struct serial *serial = (struct serial *)obj;
/* fprintf(stderr,"Poll event %02x\n",event); */
if(IS_READY(serial->read_q) && (POLLIN & event) )
async_notify(serial->read_q.head,STATUS_ALERTED);
if(IS_READY(serial->write_q) && (POLLOUT & event) )
async_notify(serial->write_q.head,STATUS_ALERTED);
if(IS_READY(serial->wait_q) && (POLLIN & event) )
async_notify(serial->wait_q.head,STATUS_ALERTED);
set_select_events(obj,obj->ops->get_poll_events(obj));
}
/*
* This function is an abuse of overloading that deserves some explanation.
*
* It has three purposes:
*
* 1. get the queue for a type of async operation
* 2. requeue an async operation
* 3. queue a new async operation
*
* It is overloaded so that these three functions only take one function pointer
* in the object operations list.
*
* In all cases, it returns the async queue.
*/
static struct async_queue *serial_queue_async(struct object *obj, struct async *async, int type, int count)
{ {
struct serial *serial = (struct serial *)obj; struct serial *serial = (struct serial *)obj;
struct async_queue *q;
int timeout;
if(obj->ops != &serial_ops) assert(obj->ops == &serial_ops);
return 0;
switch(type) switch(type)
{ {
case ASYNC_TYPE_READ: case ASYNC_TYPE_READ:
return serial->readconst + serial->readmult*count; q = &serial->read_q;
timeout = serial->readconst + serial->readmult*count;
break;
case ASYNC_TYPE_WAIT:
q = &serial->wait_q;
timeout = 0;
break;
case ASYNC_TYPE_WRITE: case ASYNC_TYPE_WRITE:
return serial->writeconst + serial->writemult*count; q = &serial->write_q;
timeout = serial->writeconst + serial->writemult*count;
break;
default:
set_error(STATUS_INVALID_PARAMETER);
return NULL;
}
if(async)
{
if(!async->q)
{
async_add_timeout(async,timeout);
async_insert(q, async);
} }
return 0;
} }
return q;
}
/* create a serial */ /* create a serial */
DECL_HANDLER(create_serial) DECL_HANDLER(create_serial)
......
...@@ -50,6 +50,7 @@ static const struct object_ops snapshot_ops = ...@@ -50,6 +50,7 @@ static const struct object_ops snapshot_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
snapshot_destroy /* destroy */ snapshot_destroy /* destroy */
}; };
......
...@@ -77,6 +77,7 @@ static const struct object_ops sock_ops = ...@@ -77,6 +77,7 @@ static const struct object_ops sock_ops =
sock_get_fd, /* get_fd */ sock_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
sock_get_info, /* get_file_info */ sock_get_info, /* get_file_info */
NULL, /* queue_async */
sock_destroy /* destroy */ sock_destroy /* destroy */
}; };
......
...@@ -76,6 +76,7 @@ static const struct object_ops thread_ops = ...@@ -76,6 +76,7 @@ static const struct object_ops thread_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
destroy_thread /* destroy */ destroy_thread /* destroy */
}; };
......
...@@ -45,6 +45,7 @@ static const struct object_ops timer_ops = ...@@ -45,6 +45,7 @@ static const struct object_ops timer_ops =
no_get_fd, /* get_fd */ no_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ no_get_file_info, /* get_file_info */
NULL, /* queue_async */
timer_destroy /* destroy */ timer_destroy /* destroy */
}; };
......
...@@ -1738,16 +1738,14 @@ static void dump_set_serial_info_request( const struct set_serial_info_request * ...@@ -1738,16 +1738,14 @@ static void dump_set_serial_info_request( const struct set_serial_info_request *
fprintf( stderr, " commerror=%08x", req->commerror ); fprintf( stderr, " commerror=%08x", req->commerror );
} }
static void dump_create_async_request( const struct create_async_request *req ) static void dump_register_async_request( const struct register_async_request *req )
{ {
fprintf( stderr, " file_handle=%d,", req->file_handle ); fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " func=%p,", req->func );
fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " overlapped=%p,", req->overlapped );
fprintf( stderr, " count=%d,", req->count ); fprintf( stderr, " count=%d,", req->count );
fprintf( stderr, " type=%d", req->type ); fprintf( stderr, " status=%08x", req->status );
}
static void dump_create_async_reply( const struct create_async_reply *req )
{
fprintf( stderr, " timeout=%d", req->timeout );
} }
static void dump_create_named_pipe_request( const struct create_named_pipe_request *req ) static void dump_create_named_pipe_request( const struct create_named_pipe_request *req )
...@@ -2154,7 +2152,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -2154,7 +2152,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_serial_request, (dump_func)dump_create_serial_request,
(dump_func)dump_get_serial_info_request, (dump_func)dump_get_serial_info_request,
(dump_func)dump_set_serial_info_request, (dump_func)dump_set_serial_info_request,
(dump_func)dump_create_async_request, (dump_func)dump_register_async_request,
(dump_func)dump_create_named_pipe_request, (dump_func)dump_create_named_pipe_request,
(dump_func)dump_open_named_pipe_request, (dump_func)dump_open_named_pipe_request,
(dump_func)dump_connect_named_pipe_request, (dump_func)dump_connect_named_pipe_request,
...@@ -2305,7 +2303,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -2305,7 +2303,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_serial_reply, (dump_func)dump_create_serial_reply,
(dump_func)dump_get_serial_info_reply, (dump_func)dump_get_serial_info_reply,
(dump_func)0, (dump_func)0,
(dump_func)dump_create_async_reply, (dump_func)0,
(dump_func)dump_create_named_pipe_reply, (dump_func)dump_create_named_pipe_reply,
(dump_func)dump_open_named_pipe_reply, (dump_func)dump_open_named_pipe_reply,
(dump_func)0, (dump_func)0,
...@@ -2456,7 +2454,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { ...@@ -2456,7 +2454,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"create_serial", "create_serial",
"get_serial_info", "get_serial_info",
"set_serial_info", "set_serial_info",
"create_async", "register_async",
"create_named_pipe", "create_named_pipe",
"open_named_pipe", "open_named_pipe",
"connect_named_pipe", "connect_named_pipe",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment