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. */
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 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];
int n_vec;
// XXXX use ok
EVBUFFER_LOCK(evbuf, EVTHREAD_WRITE);
buf->read_in_progress = 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. */
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 evbuffer_overlapped *buf = buf_o->buf;

View File

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

View File

@ -34,7 +34,7 @@ extern "C" {
struct event_overlapped;
struct event_iocp_port;
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
* 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,
ev_ssize_t n);
ev_ssize_t n, int ok);
static struct accepting_socket *
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,
&pending, &as->overlapped.overlapped)) {
/* Immediate success! */
accepted_socket_cb(&as->overlapped, 1, 0);
accepted_socket_cb(&as->overlapped, 1, 0, 1);
result = 0;
} else {
int err = WSAGetLastError();
@ -395,10 +395,11 @@ stop_accepting(struct accepting_socket *as)
#endif
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 */
/* XXX needs locking. */
/* XXX use ok */
struct sockaddr *sa_local=NULL, *sa_remote=NULL;
int socklen_local=0, socklen_remote=0;