- move async activation into the server
- implement async queues
diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index 4e82c1e..3b74114 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -1512,27 +1512,19 @@
* 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 @@
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 @@
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 @@
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 995ae3e..b3ef897 100644
--- a/files/file.c
+++ b/files/file.c
@@ -1248,12 +1248,34 @@
/***********************************************************************
+ * 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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 5efc9a5..73d5ef3 100644
--- a/include/file.h
+++ b/include/file.h
@@ -33,22 +33,23 @@
/* 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 @@
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 58cac3f..ccb317b 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2181,18 +2181,21 @@
-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 @@
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 @@
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 @@
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 @@
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 5220f0e..6678374 100644
--- a/scheduler/synchro.c
+++ b/scheduler/synchro.c
@@ -36,14 +36,6 @@
}
}
-#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 @@
/***********************************************************************
* 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)
+void check_async_list(LPOVERLAPPED overlapped, DWORD status)
{
- finish_async(ovp,STATUS_UNSUCCESSFUL);
- continue;
- }
+ async_private *ovp;
- if(ovp->timeout && time_before(&ovp->tv,&now))
- {
- finish_async(ovp,STATUS_TIMEOUT);
- continue;
- }
+ /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */
- fds[n].fd=ovp->fd;
- fds[n].events=ovp->event;
- fds[n].revents=0;
- user[n] = ovp;
+ for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next)
+ if(ovp->lpOverlapped == overlapped)
+ break;
- 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)
+ if(!ovp)
return;
- r = poll(fds, n, timeout);
+ if(status != STATUS_ALERTED)
+ ovp->lpOverlapped->Internal = status;
- /* if there were any errors, return immediately */
- if( (r<0) || (fds[0].revents==POLLNVAL) )
- return;
-
- if( r==0 )
+ if(ovp->lpOverlapped->Internal==STATUS_PENDING)
{
- finish_async(timeout_user, STATUS_TIMEOUT);
- continue;
+ ovp->func(ovp);
+ FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal);
}
- /* 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],user[i]->lpOverlapped->Internal);
- }
-
- if(fds[0].revents == POLLIN)
- return;
- }
+ if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
+ finish_async(ovp,ovp->lpOverlapped->Internal);
}
@@ -184,7 +118,6 @@
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 5e16000..567631e 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;
- /* FIXME: this should be a function pointer */
- reply->timeout = get_serial_async_timeout(obj,req->type,req->count);
+ async = find_async(q, current, req->overlapped);
+ if(req->status==STATUS_PENDING)
+ {
+ if(!async)
+ async = create_async(obj, current, req->func, req->overlapped);
+
+ 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 0000000..b022524
--- /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 7d0b52c..debe186 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -59,6 +59,7 @@
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 1162b6a..8d3a37c 100644
--- a/server/change.c
+++ b/server/change.c
@@ -37,6 +37,7 @@
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 16fe874..a48e11b 100644
--- a/server/console.c
+++ b/server/console.c
@@ -40,6 +40,7 @@
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 @@
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 @@
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 3790292..e487eb0 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -58,6 +58,7 @@
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 @@
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 6c37c19..c3601f2 100644
--- a/server/device.c
+++ b/server/device.c
@@ -44,6 +44,7 @@
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 7318aef..727b8ed 100644
--- a/server/event.c
+++ b/server/event.c
@@ -38,6 +38,7 @@
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 ae9033c..db539ea 100644
--- a/server/file.c
+++ b/server/file.c
@@ -65,6 +65,7 @@
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 f4b004f..9679092 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -92,6 +92,7 @@
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 8f4508b..a944d6a 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -51,6 +51,7 @@
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 ee145d9..e27ccc1 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -42,6 +42,7 @@
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 0635039..309407e 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -80,6 +80,7 @@
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 @@
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 c805b51..07230da 100644
--- a/server/object.h
+++ b/server/object.h
@@ -22,6 +22,7 @@
struct file;
struct wait_queue_entry;
struct async;
+struct async_queue;
/* operations valid on all objects */
struct object_ops
@@ -48,6 +49,8 @@
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 ddd200b..d1f02b1 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -53,6 +53,7 @@
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 9643aaf..9b71108 100644
--- a/server/process.c
+++ b/server/process.c
@@ -53,6 +53,7 @@
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 @@
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 6010dac..835b3ad 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1529,14 +1529,16 @@
#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 87e85a0..a639ebe 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -112,6 +112,7 @@
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 f8e82f4..902d065 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -142,6 +142,7 @@
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 9f2b8ad..0c79dc2 100644
--- a/server/request.c
+++ b/server/request.c
@@ -66,6 +66,7 @@
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 b1409aa..ee18ecb 100644
--- a/server/request.h
+++ b/server/request.h
@@ -209,7 +209,7 @@
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 @@
(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 022fc73..1ccaeea 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -38,6 +38,7 @@
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 da682bf..5a55c80 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 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 @@
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 @@
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 @@
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 @@
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;
}
- return 0;
+
+ if(async)
+ {
+ if(!async->q)
+ {
+ async_add_timeout(async,timeout);
+ async_insert(q, async);
+ }
}
+ return q;
+}
/* create a serial */
DECL_HANDLER(create_serial)
diff --git a/server/snapshot.c b/server/snapshot.c
index 1d73873..9bd05df 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -50,6 +50,7 @@
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 a18dc6e..0cc4a3f 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -77,6 +77,7 @@
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 ff1e652..17093e3 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -76,6 +76,7 @@
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 fd9604a..90e1f32 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -45,6 +45,7 @@
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 f5098cb..0f12a0e 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1738,16 +1738,14 @@
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 @@
(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 @@
(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 @@
"create_serial",
"get_serial_info",
"set_serial_info",
- "create_async",
+ "register_async",
"create_named_pipe",
"open_named_pipe",
"connect_named_pipe",