Refactor IOCP callback interface

Chris Davis points out that GetQueuedCompletionStatus
sometimes returns false not to report "No events for
you!" but instead to report "An overlapped operation
failed."  Add a way to tell an event_overlapped that
its operation failed.

svn:r1490
This commit is contained in:
Nick Mathewson 2009-11-02 19:51:26 +00:00
parent 9a772148f2
commit a84c87d76a
4 changed files with 22 additions and 15 deletions

View File

@ -111,7 +111,7 @@ pin_release(struct event_overlapped *eo, unsigned flag)
/** IOCP callback invoked when a read operation is finished. */ /** IOCP callback invoked when a read operation is finished. */
static void static void
read_completed(struct event_overlapped *eo, uintptr_t _, ev_ssize_t nBytes) read_completed(struct event_overlapped *eo, uintptr_t _, ev_ssize_t nBytes, int ok)
{ {
struct buffer_overlapped *buf_o = upcast_overlapped(eo); struct buffer_overlapped *buf_o = upcast_overlapped(eo);
struct evbuffer_overlapped *buf = buf_o->buf; struct evbuffer_overlapped *buf = buf_o->buf;
@ -120,6 +120,8 @@ read_completed(struct event_overlapped *eo, uintptr_t _, ev_ssize_t nBytes)
struct evbuffer_iovec iov[2]; struct evbuffer_iovec iov[2];
int n_vec; int n_vec;
// XXXX use ok
EVBUFFER_LOCK(evbuf, EVTHREAD_WRITE); EVBUFFER_LOCK(evbuf, EVTHREAD_WRITE);
buf->read_in_progress = 0; buf->read_in_progress = 0;
evbuffer_unfreeze(evbuf, 0); evbuffer_unfreeze(evbuf, 0);
@ -145,8 +147,9 @@ read_completed(struct event_overlapped *eo, uintptr_t _, ev_ssize_t nBytes)
/** IOCP callback invoked when a write operation is finished. */ /** IOCP callback invoked when a write operation is finished. */
static void static void
write_completed(struct event_overlapped *eo, uintptr_t _, ev_ssize_t nBytes) write_completed(struct event_overlapped *eo, uintptr_t _, ev_ssize_t nBytes, int ok)
{ {
// XXX use ok
struct buffer_overlapped *buf_o = upcast_overlapped(eo); struct buffer_overlapped *buf_o = upcast_overlapped(eo);
struct evbuffer_overlapped *buf = buf_o->buf; struct evbuffer_overlapped *buf = buf_o->buf;

View File

@ -47,28 +47,29 @@ event_overlapped_init(struct event_overlapped *o, iocp_callback cb)
} }
static void static void
handle_entry(OVERLAPPED *o, ULONG_PTR completion_key, DWORD nBytes) handle_entry(OVERLAPPED *o, ULONG_PTR completion_key, DWORD nBytes, int ok)
{ {
struct event_overlapped *eo = struct event_overlapped *eo =
EVUTIL_UPCAST(o, struct event_overlapped, overlapped); EVUTIL_UPCAST(o, struct event_overlapped, overlapped);
eo->cb(eo, completion_key, nBytes); eo->cb(eo, completion_key, nBytes, ok);
} }
static void static void
loop(void *_port) loop(void *_port)
{ {
struct event_iocp_port *port = _port; struct event_iocp_port *port = _port;
OVERLAPPED *overlapped;
ULONG_PTR key;
DWORD bytes;
long ms = port->ms; long ms = port->ms;
HANDLE p = port->port; HANDLE p = port->port;
if (ms <= 0) if (ms <= 0)
ms = INFINITE; ms = INFINITE;
while (GetQueuedCompletionStatus(p, &bytes, &key, while (1) {
&overlapped, ms)) { OVERLAPPED *overlapped=NULL;
ULONG_PTR key=0;
DWORD bytes=0;
int ok = GetQueuedCompletionStatus(p, &bytes, &key,
&overlapped, ms);
EnterCriticalSection(&port->lock); EnterCriticalSection(&port->lock);
if (port->shutdown) { if (port->shutdown) {
if (--port->n_live_threads == 0) if (--port->n_live_threads == 0)
@ -78,8 +79,10 @@ loop(void *_port)
} }
LeaveCriticalSection(&port->lock); LeaveCriticalSection(&port->lock);
if (key != NOTIFICATION_KEY) if (key != NOTIFICATION_KEY && overlapped)
handle_entry(overlapped, key, bytes); handle_entry(overlapped, key, bytes, ok);
else if (!overlapped)
break;
} }
event_warnx("GetQueuedCompletionStatus exited with no event."); event_warnx("GetQueuedCompletionStatus exited with no event.");
EnterCriticalSection(&port->lock); EnterCriticalSection(&port->lock);

View File

@ -34,7 +34,7 @@ extern "C" {
struct event_overlapped; struct event_overlapped;
struct event_iocp_port; struct event_iocp_port;
struct evbuffer; struct evbuffer;
typedef void (*iocp_callback)(struct event_overlapped *, uintptr_t, ev_ssize_t); typedef void (*iocp_callback)(struct event_overlapped *, uintptr_t, ev_ssize_t, int success);
/* This whole file is actually win32 only. We wrap the structures in a win32 /* This whole file is actually win32 only. We wrap the structures in a win32
* ifdef so that we can test-compile code that uses these interfaces on * ifdef so that we can test-compile code that uses these interfaces on

View File

@ -297,7 +297,7 @@ struct accepting_socket {
}; };
static void accepted_socket_cb(struct event_overlapped *o, uintptr_t key, static void accepted_socket_cb(struct event_overlapped *o, uintptr_t key,
ev_ssize_t n); ev_ssize_t n, int ok);
static struct accepting_socket * static struct accepting_socket *
new_accepting_socket(struct evconnlistener_iocp *lev, int family) new_accepting_socket(struct evconnlistener_iocp *lev, int family)
@ -370,7 +370,7 @@ start_accepting(struct accepting_socket *as)
as->buflen/2, as->buflen/2, as->buflen/2, as->buflen/2,
&pending, &as->overlapped.overlapped)) { &pending, &as->overlapped.overlapped)) {
/* Immediate success! */ /* Immediate success! */
accepted_socket_cb(&as->overlapped, 1, 0); accepted_socket_cb(&as->overlapped, 1, 0, 1);
result = 0; result = 0;
} else { } else {
int err = WSAGetLastError(); int err = WSAGetLastError();
@ -395,10 +395,11 @@ stop_accepting(struct accepting_socket *as)
#endif #endif
static void static void
accepted_socket_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n) accepted_socket_cb(struct event_overlapped *o, uintptr_t key, ev_ssize_t n, int ok)
{ {
/* Run this whole thing deferred unless some MT flag is set */ /* Run this whole thing deferred unless some MT flag is set */
/* XXX needs locking. */ /* XXX needs locking. */
/* XXX use ok */
struct sockaddr *sa_local=NULL, *sa_remote=NULL; struct sockaddr *sa_local=NULL, *sa_remote=NULL;
int socklen_local=0, socklen_remote=0; int socklen_local=0, socklen_remote=0;