diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c index 4e82c1e4d28af1e09b39e14aa88bf36db9a20985..3b74114637d877e96ccf4a0ea440bd9458abbb23 100644 --- a/dlls/kernel/comm.c +++ b/dlls/kernel/comm.c @@ -1512,27 +1512,19 @@ BOOL WINAPI GetCommModemStatus( * 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) +static void COMM_WaitCommEventService(async_private *ovp) { LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; - 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) + TRACE("overlapped %p\n",lpOverlapped); + + /* FIXME: detect other events */ *ovp->buffer = EV_RXCHAR; - } lpOverlapped->Internal = STATUS_SUCCESS; } - /*********************************************************************** * COMM_WaitCommEvent (INTERNAL) * @@ -1560,20 +1552,6 @@ static BOOL COMM_WaitCommEvent( 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=wine_server_call_err( req ); - } - SERVER_END_REQ; - - if (ret) - return FALSE; - fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); if(fd<0) return FALSE; @@ -1585,15 +1563,13 @@ static BOOL COMM_WaitCommEvent( 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->count = 0; ovp->completion_func = 0; + ovp->type = ASYNC_TYPE_WAIT; + ovp->handle = hFile; ovp->next = NtCurrentTeb()->pending_list; ovp->prev = NULL; @@ -1601,6 +1577,21 @@ static BOOL COMM_WaitCommEvent( ovp->next->prev=ovp; NtCurrentTeb()->pending_list = ovp; + /* start an ASYNCHRONOUS WaitCommEvent */ + SERVER_START_REQ( register_async ) + { + req->handle = hFile; + req->overlapped = lpOverlapped; + req->type = ASYNC_TYPE_WAIT; + req->count = 0; + req->func = check_async_list; + req->status = STATUS_PENDING; + + ret=wine_server_call_err(req); + } + SERVER_END_REQ; + + if (!ret) SetLastError(ERROR_IO_PENDING); return FALSE; diff --git a/files/file.c b/files/file.c index 995ae3e992f8f2161f0585d70197e946ecb7dc07..b3ef8978fb4d8135b1d4dccaee3076011a4ab87d 100644 --- a/files/file.c +++ b/files/file.c @@ -1247,13 +1247,35 @@ 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.@) */ BOOL WINAPI CancelIo(HANDLE handle) { - FIXME("(%d) stub\n",handle); - return FALSE; + return FILE_StartAsync(handle, NULL, ASYNC_TYPE_NONE, 0, STATUS_CANCELLED); } /*********************************************************************** @@ -1262,28 +1284,12 @@ BOOL WINAPI CancelIo(HANDLE handle) * 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(async_private *ovp, int events) +static void FILE_AsyncReadService(async_private *ovp) { LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; int result, r; - 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; - goto async_end; - } + TRACE("%p %p\n", lpOverlapped, ovp->buffer ); /* check to see if the data is ready (non-blocking) */ result = read(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh], @@ -1316,41 +1322,6 @@ async_end: 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) */ @@ -1359,7 +1330,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { async_private *ovp; - int fd, timeout=0; + int fd; TRACE("file %d to buf %p num %ld %p func %p\n", hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine); @@ -1372,12 +1343,6 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, return FALSE; } - if ( !FILE_GetTimeout(hFile, bytesToRead, ASYNC_TYPE_READ, &timeout ) ) - { - TRACE("FILE_GetTimeout failed\n"); - return FALSE; - } - fd = FILE_GetUnixHandle( hFile, GENERIC_READ ); if(fd<0) { @@ -1396,13 +1361,11 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ovp->lpOverlapped = overlapped; ovp->count = bytesToRead; ovp->completion_func = lpCompletionRoutine; - 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; + ovp->type = ASYNC_TYPE_READ; + ovp->handle = hFile; /* hook this overlap into the pending async operation list */ ovp->next = NtCurrentTeb()->pending_list; @@ -1411,6 +1374,13 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ovp->next->prev = 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; } @@ -1548,28 +1518,12 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, * 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(struct async_private *ovp, int events) +static void FILE_AsyncWriteService(struct async_private *ovp) { LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; int result, r; - 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("write timed out\n"); - r = STATUS_TIMEOUT; - goto async_end; - } + TRACE("(%p %p)\n",lpOverlapped,ovp->buffer); /* write some data (non-blocking) */ result = write(ovp->fd, &ovp->buffer[lpOverlapped->InternalHigh], @@ -1609,7 +1563,6 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { async_private *ovp; - int timeout=0; TRACE("file %d to buf %p num %ld %p func %p stub\n", hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); @@ -1623,9 +1576,9 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, overlapped->Internal = STATUS_PENDING; 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; } @@ -1637,15 +1590,14 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, return FALSE; } 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->count = bytesToWrite; ovp->completion_func = lpCompletionRoutine; ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); + ovp->type = ASYNC_TYPE_WRITE; + ovp->handle = hFile; + if(ovp->fd <0) { HeapFree(GetProcessHeap(), 0, ovp); diff --git a/include/file.h b/include/file.h index 5efc9a5c5b6c242a39599b07ee1c647530347586..73d5ef3f7fed0dc6d2c3508b2d7084f8aee3f3b8 100644 --- a/include/file.h +++ b/include/file.h @@ -33,22 +33,23 @@ typedef struct /* overlapped private structure */ 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 { LPOVERLAPPED lpOverlapped; + HANDLE handle; int fd; - int timeout; - struct timeval tv; - int event; char *buffer; async_handler func; int count; + int type; LPOVERLAPPED_COMPLETION_ROUTINE completion_func; struct async_private *next; struct async_private *prev; } async_private; +extern void check_async_list(LPOVERLAPPED ov, DWORD status); + /* locale-independent case conversion */ inline static char FILE_tolower( char c ) { @@ -80,6 +81,7 @@ extern HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing, DWORD attributes, HANDLE template, BOOL fail_read_only, UINT drive_type ); extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa ); +extern BOOL FILE_StartAsync(HANDLE handle, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status); extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 58cac3faf8c721dda3399f41acb12e0886ec494b..ccb317bd48527f387a1f209932c9e51566822c9d 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2181,18 +2181,21 @@ struct set_serial_info_reply -struct create_async_request +struct register_async_request { struct request_header __header; - handle_t file_handle; - int count; + handle_t handle; + void* func; int type; + void* overlapped; + int count; + unsigned int status; }; -struct create_async_reply +struct register_async_reply { struct reply_header __header; - int timeout; }; +#define ASYNC_TYPE_NONE 0x00 #define ASYNC_TYPE_READ 0x01 #define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WAIT 0x03 @@ -2699,7 +2702,7 @@ enum request REQ_create_serial, REQ_get_serial_info, REQ_set_serial_info, - REQ_create_async, + REQ_register_async, REQ_create_named_pipe, REQ_open_named_pipe, REQ_connect_named_pipe, @@ -2854,7 +2857,7 @@ union generic_request struct create_serial_request create_serial_request; struct get_serial_info_request get_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 open_named_pipe_request open_named_pipe_request; struct connect_named_pipe_request connect_named_pipe_request; @@ -3007,7 +3010,7 @@ union generic_reply struct create_serial_reply create_serial_reply; struct get_serial_info_reply get_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 open_named_pipe_reply open_named_pipe_reply; struct connect_named_pipe_reply connect_named_pipe_reply; @@ -3035,6 +3038,6 @@ union generic_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 */ diff --git a/scheduler/synchro.c b/scheduler/synchro.c index 5220f0e28583b2afd7baa813138367c4f1cdbb91..667837408e61ad635655482c2bf9d52ab240e286 100644 --- a/scheduler/synchro.c +++ b/scheduler/synchro.c @@ -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) { async_private* ovp = (async_private*)data; @@ -85,90 +77,32 @@ static void finish_async(async_private *ovp, DWORD status) /*********************************************************************** * 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? + * Process a status event from the server. */ -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) - { - finish_async(ovp,STATUS_UNSUCCESSFUL); - continue; - } - - if(ovp->timeout && time_before(&ovp->tv,&now)) +void check_async_list(LPOVERLAPPED overlapped, DWORD status) { - finish_async(ovp,STATUS_TIMEOUT); - continue; - } + async_private *ovp; - fds[n].fd=ovp->fd; - fds[n].events=ovp->event; - fds[n].revents=0; - user[n] = ovp; + /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */ - 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); + for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next) + if(ovp->lpOverlapped == overlapped) + break; - /* if there were any errors, return immediately */ - if( (r<0) || (fds[0].revents==POLLNVAL) ) + if(!ovp) return; - if( r==0 ) - { - finish_async(timeout_user, STATUS_TIMEOUT); - continue; - } + if(status != STATUS_ALERTED) + ovp->lpOverlapped->Internal = status; - /* search for async operations that are ready */ - for( i=1; i<n; i++) + if(ovp->lpOverlapped->Internal==STATUS_PENDING) { - 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); + ovp->func(ovp); + FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal); } - if(fds[0].revents == POLLIN) - return; - } + if(ovp->lpOverlapped->Internal!=STATUS_PENDING) + finish_async(ovp,ovp->lpOverlapped->Internal); } @@ -184,7 +118,6 @@ static int wait_reply( void *cookie ) for (;;) { int ret; - if (NtCurrentTeb()->pending_list) check_async_list(); ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) ); if (ret == sizeof(reply)) { diff --git a/server/async.c b/server/async.c index 5e160004e050366b4f0081d53edfbb8beea248a9..567631ee6d9b4a2fa0f7143dc4082e3e6e88cd91 100644 --- a/server/async.c +++ b/server/async.c @@ -12,23 +12,168 @@ #include <string.h> #include <stdlib.h> #include <unistd.h> +#include <stdio.h> #include "handle.h" #include "thread.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; - if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) ) + if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL)) ) 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 */ - reply->timeout = get_serial_async_timeout(obj,req->type,req->count); + if(async) + { + 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); } + diff --git a/server/async.h b/server/async.h new file mode 100644 index 0000000000000000000000000000000000000000..b0225245dd22015e8cbd2c271e2e9d4e70440eb1 --- /dev/null +++ b/server/async.h @@ -0,0 +1,45 @@ + +#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_ */ + diff --git a/server/atom.c b/server/atom.c index 7d0b52cd0fb9cec1247bfeeb3efb3b15f83f7833..debe1867ac115986e769c2f3a5a51fa7e677662c 100644 --- a/server/atom.c +++ b/server/atom.c @@ -59,6 +59,7 @@ static const struct object_ops atom_table_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ atom_table_destroy /* destroy */ }; diff --git a/server/change.c b/server/change.c index 1162b6a7e9602c7cb4210d1bb738a49f4c73f06d..8d3a37c3f5cbc84bb6a33d16c06edee2b12d5ee1 100644 --- a/server/change.c +++ b/server/change.c @@ -37,6 +37,7 @@ static const struct object_ops change_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ no_destroy /* destroy */ }; diff --git a/server/console.c b/server/console.c index 16fe874ddd5f2df63daa803a33e5498d02c615fd..a48e11bec67bfbd2bb356e85f9b76ad23db25330 100644 --- a/server/console.c +++ b/server/console.c @@ -40,6 +40,7 @@ static const struct object_ops console_input_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ console_get_file_info, /* get_file_info */ + NULL, /* queue_async */ console_input_destroy /* destroy */ }; @@ -68,6 +69,7 @@ static const struct object_ops console_input_events_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ console_input_events_destroy /* destroy */ }; @@ -108,6 +110,7 @@ static const struct object_ops screen_buffer_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ console_get_file_info, /* get_file_info */ + NULL, /* queue_async */ screen_buffer_destroy /* destroy */ }; diff --git a/server/debugger.c b/server/debugger.c index 3790292a0c1a629cd724f6658d3dc4548bc36873..e487eb0480c0c4df43ece4473e147896eb9684d9 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -58,6 +58,7 @@ static const struct object_ops debug_event_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ debug_event_destroy /* destroy */ }; @@ -78,6 +79,7 @@ static const struct object_ops debug_ctx_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ debug_ctx_destroy /* destroy */ }; diff --git a/server/device.c b/server/device.c index 6c37c19c303f2c638f8fed80e1d9801e3ef7d092..c3601f22cda5533c507d8d804084ab1930ab6a03 100644 --- a/server/device.c +++ b/server/device.c @@ -44,6 +44,7 @@ static const struct object_ops device_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ device_get_info, /* get_file_info */ + NULL, /* queue_async */ no_destroy /* destroy */ }; diff --git a/server/event.c b/server/event.c index 7318aef1791685fe9999235e5c28c930d231216b..727b8ed794e8db392b6d723b521b67fb6aeec398 100644 --- a/server/event.c +++ b/server/event.c @@ -38,6 +38,7 @@ static const struct object_ops event_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ no_destroy /* destroy */ }; diff --git a/server/file.c b/server/file.c index ae9033c1dcffa1d517bec7670b1c6244c5bf4160..db539ea6c2ca73b434490c715e70c9a8050d6e47 100644 --- a/server/file.c +++ b/server/file.c @@ -65,6 +65,7 @@ static const struct object_ops file_ops = file_get_fd, /* get_fd */ file_flush, /* flush */ file_get_info, /* get_file_info */ + NULL, /* queue_async */ file_destroy /* destroy */ }; diff --git a/server/handle.c b/server/handle.c index f4b004f1ce6882af6126601f439c210155fce1d8..967909207708da779745a7c29d76fcc4438b579c 100644 --- a/server/handle.c +++ b/server/handle.c @@ -92,6 +92,7 @@ static const struct object_ops handle_table_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ handle_table_destroy /* destroy */ }; diff --git a/server/mapping.c b/server/mapping.c index 8f4508be85899ef910eda8f0332d27006e9958b2..a944d6a9fc3698e666c509f97478dbf00205bc72 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -51,6 +51,7 @@ static const struct object_ops mapping_ops = mapping_get_fd, /* get_fd */ no_flush, /* flush */ mapping_get_info, /* get_file_info */ + NULL, /* queue_async */ mapping_destroy /* destroy */ }; diff --git a/server/mutex.c b/server/mutex.c index ee145d94591d0ad92a3909af71c648164a01915a..e27ccc193264990c29e6e25c56bc3278f6f53be3 100644 --- a/server/mutex.c +++ b/server/mutex.c @@ -42,6 +42,7 @@ static const struct object_ops mutex_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ mutex_destroy /* destroy */ }; diff --git a/server/named_pipe.c b/server/named_pipe.c index 06350396134f8b65fa2bc7cc8f07de77add5e083..309407e5b0114aab1f9694b8b510f297a6f52db9 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -80,6 +80,7 @@ static const struct object_ops named_pipe_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ named_pipe_destroy /* destroy */ }; @@ -101,6 +102,7 @@ static const struct object_ops pipe_user_ops = pipe_user_get_fd, /* get_fd */ no_flush, /* flush */ pipe_user_get_info, /* get_file_info */ + NULL, /* queue_async */ pipe_user_destroy /* destroy */ }; diff --git a/server/object.h b/server/object.h index c805b51f26342a5a4c1f013d67453272c184366f..07230dadf0bf5253e8c4fc554fccdef410dc7151 100644 --- a/server/object.h +++ b/server/object.h @@ -22,6 +22,7 @@ struct process; struct file; struct wait_queue_entry; struct async; +struct async_queue; /* operations valid on all objects */ struct object_ops @@ -48,6 +49,8 @@ struct object_ops int (*flush)(struct object *); /* get file information */ 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 */ void (*destroy)(struct object *); }; diff --git a/server/pipe.c b/server/pipe.c index ddd200bbac4c22d086a4f2be314a6624f43bfffe..d1f02b174eaf2edce7980d720fdcbf352d38436f 100644 --- a/server/pipe.c +++ b/server/pipe.c @@ -53,6 +53,7 @@ static const struct object_ops pipe_ops = pipe_get_fd, /* get_fd */ no_flush, /* flush */ pipe_get_info, /* get_file_info */ + NULL, /* queue_async */ pipe_destroy /* destroy */ }; diff --git a/server/process.c b/server/process.c index 9643aaf33dba0806115fc236651d68c210f69773..9b711080b4957ea4e5c04adaa4c8256a771bf3d8 100644 --- a/server/process.c +++ b/server/process.c @@ -53,6 +53,7 @@ static const struct object_ops process_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ process_destroy /* destroy */ }; @@ -92,6 +93,7 @@ static const struct object_ops startup_info_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ startup_info_destroy /* destroy */ }; diff --git a/server/protocol.def b/server/protocol.def index 6010dac2be18a2d198436c1ba28931d149edbfa0..835b3ad31f34dc31bc0d173fdda8063b428f01cd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1529,14 +1529,16 @@ enum message_type #define SERIALINFO_SET_ERROR 0x04 -/* Create an async I/O */ -@REQ(create_async) - handle_t file_handle; /* handle to comm port, socket or file */ - int count; +/* Create/Destroy an async I/O */ +@REQ(register_async) + handle_t handle; /* handle to comm port, socket or file */ + void* func; int type; -@REPLY - int timeout; + void* overlapped; + int count; + unsigned int status; @END +#define ASYNC_TYPE_NONE 0x00 #define ASYNC_TYPE_READ 0x01 #define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WAIT 0x03 diff --git a/server/queue.c b/server/queue.c index 87e85a0fa6afbb2cfe3bc8ac4955789751c9d274..a639ebe21131e7b123d739864907d222d615aaff 100644 --- a/server/queue.c +++ b/server/queue.c @@ -112,6 +112,7 @@ static const struct object_ops msg_queue_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ msg_queue_destroy /* destroy */ }; diff --git a/server/registry.c b/server/registry.c index f8e82f4fc4a36ac25b00917731b3856f9e14f7c4..902d065437d67a67421e511c19471138d4547954 100644 --- a/server/registry.c +++ b/server/registry.c @@ -142,6 +142,7 @@ static const struct object_ops key_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ key_destroy /* destroy */ }; diff --git a/server/request.c b/server/request.c index 9f2b8ad5e49185400c03d3b80c3e8a2936980d32..0c79dc278a5ea3d6b52403beb06106953b093ab1 100644 --- a/server/request.c +++ b/server/request.c @@ -66,6 +66,7 @@ static const struct object_ops master_socket_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ master_socket_destroy /* destroy */ }; diff --git a/server/request.h b/server/request.h index b1409aae054320d143f41ef772f69cbdd6c406ed..ee18ecbb7f8f3b5efcaa7d8ce47e424cb2e3728a 100644 --- a/server/request.h +++ b/server/request.h @@ -209,7 +209,7 @@ DECL_HANDLER(kill_win_timer); DECL_HANDLER(create_serial); DECL_HANDLER(get_serial_info); DECL_HANDLER(set_serial_info); -DECL_HANDLER(create_async); +DECL_HANDLER(register_async); DECL_HANDLER(create_named_pipe); DECL_HANDLER(open_named_pipe); DECL_HANDLER(connect_named_pipe); @@ -363,7 +363,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_create_serial, (req_handler)req_get_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_open_named_pipe, (req_handler)req_connect_named_pipe, diff --git a/server/semaphore.c b/server/semaphore.c index 022fc738383046774ce2e623a0ad3be240cb65be..1ccaeea03eb36ddafedd4ac2ccb33aa85e64043f 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -38,6 +38,7 @@ static const struct object_ops semaphore_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ no_destroy /* destroy */ }; diff --git a/server/serial.c b/server/serial.c index da682bfeac4cd4d2938eddf326667e1ba2c69ebc..5a55c80416b9dd9129afc856fdd934d431dee4fb 100644 --- a/server/serial.c +++ b/server/serial.c @@ -2,10 +2,7 @@ * Server-side serial port communications management * * Copyright (C) 1998 Alexandre Julliard - * Copyright (C) 2000 Mike McCormack - * - * TODO: - * Add async read, write and WaitCommEvent handling. + * Copyright (C) 2000,2001 Mike McCormack * */ @@ -34,11 +31,15 @@ #include "handle.h" #include "thread.h" #include "request.h" +#include "async.h" static void serial_dump( struct object *obj, int verbose ); 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_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 { @@ -58,6 +59,10 @@ struct serial 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 */ }; @@ -70,15 +75,14 @@ static const struct object_ops serial_ops = default_poll_signaled, /* signaled */ no_satisfied, /* satisfied */ serial_get_poll_events, /* get_poll_events */ - default_poll_event, /* poll_event */ + serial_poll_event, /* poll_event */ serial_get_fd, /* get_fd */ no_flush, /* flush */ 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 ) { struct serial *serial; @@ -132,10 +136,22 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i serial->writeconst = 0; serial->eventmask = 0; serial->commerror = 0; + init_async_queue(&serial->read_q); + init_async_queue(&serial->write_q); + init_async_queue(&serial->wait_q); } 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 ) { struct serial *serial = (struct serial *)obj; @@ -153,8 +169,16 @@ static int serial_get_poll_events( struct object *obj ) struct serial *serial = (struct serial *)obj; int events = 0; 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; } @@ -190,25 +214,76 @@ static int serial_get_info( struct object *obj, struct get_file_info_reply *repl return FD_TYPE_TIMEOUT; } -/* 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) +static void serial_poll_event(struct object *obj, int event) { struct serial *serial = (struct serial *)obj; - if(obj->ops != &serial_ops) - return 0; + /* 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 async_queue *q; + int timeout; + + assert(obj->ops == &serial_ops); switch(type) { 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: - 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 */ DECL_HANDLER(create_serial) diff --git a/server/snapshot.c b/server/snapshot.c index 1d73873e899b9e7ee44c0d1ccd7f83ba8918ec29..9bd05dfa120c0c12d7b850230d5605dca1e1e63d 100644 --- a/server/snapshot.c +++ b/server/snapshot.c @@ -50,6 +50,7 @@ static const struct object_ops snapshot_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ snapshot_destroy /* destroy */ }; diff --git a/server/sock.c b/server/sock.c index a18dc6ef5ac84944d6298f5d8669519f9c783950..0cc4a3f3257c61dce817c4e6ab06a0c76e098257 100644 --- a/server/sock.c +++ b/server/sock.c @@ -77,6 +77,7 @@ static const struct object_ops sock_ops = sock_get_fd, /* get_fd */ no_flush, /* flush */ sock_get_info, /* get_file_info */ + NULL, /* queue_async */ sock_destroy /* destroy */ }; diff --git a/server/thread.c b/server/thread.c index ff1e65273367ffe40232b020ef31f34861ed5c74..17093e352668ab12899993c59538e0bb5a2a34b5 100644 --- a/server/thread.c +++ b/server/thread.c @@ -76,6 +76,7 @@ static const struct object_ops thread_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ destroy_thread /* destroy */ }; diff --git a/server/timer.c b/server/timer.c index fd9604af4c963d1ba8a3fd8e160ecf2e4681e2de..90e1f32f74be19268f87dc8084afa19859d087c5 100644 --- a/server/timer.c +++ b/server/timer.c @@ -45,6 +45,7 @@ static const struct object_ops timer_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ + NULL, /* queue_async */ timer_destroy /* destroy */ }; diff --git a/server/trace.c b/server/trace.c index f5098cb310ac2ad7f1b5f610be7cdcc527c59ad3..0f12a0ee3cf04c6dc05cd536038a23729795e406 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1738,16 +1738,14 @@ static void dump_set_serial_info_request( const struct set_serial_info_request * 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, " type=%d", req->type ); -} - -static void dump_create_async_reply( const struct create_async_reply *req ) -{ - fprintf( stderr, " timeout=%d", req->timeout ); + fprintf( stderr, " status=%08x", req->status ); } 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] = { (dump_func)dump_create_serial_request, (dump_func)dump_get_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_open_named_pipe_request, (dump_func)dump_connect_named_pipe_request, @@ -2305,7 +2303,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_serial_reply, (dump_func)dump_get_serial_info_reply, (dump_func)0, - (dump_func)dump_create_async_reply, + (dump_func)0, (dump_func)dump_create_named_pipe_reply, (dump_func)dump_open_named_pipe_reply, (dump_func)0, @@ -2456,7 +2454,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "create_serial", "get_serial_info", "set_serial_info", - "create_async", + "register_async", "create_named_pipe", "open_named_pipe", "connect_named_pipe",