From 6d8aa96ab66a8ab3ca4d06be628490cd279a0013 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 8 May 2011 00:27:12 +0200 Subject: [PATCH] Check/prepare/idle for windows. No tests yes, so bugs are likely. --- oio-win.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++- oio-win.h | 6 ++ 2 files changed, 197 insertions(+), 1 deletion(-) diff --git a/oio-win.c b/oio-win.c index 0c06394a..a7305390 100644 --- a/oio-win.c +++ b/oio-win.c @@ -126,6 +126,7 @@ static LPFN_TRANSMITFILE pTransmitFile; #define OIO_HANDLE_CONNECTION 0x0010 #define OIO_HANDLE_CONNECTED 0x0020 #define OIO_HANDLE_READING 0x0040 +#define OIO_HANDLE_ACTIVE 0x0040 #define OIO_HANDLE_EOF 0x0080 #define OIO_HANDLE_SHUTTING 0x0100 #define OIO_HANDLE_SHUT 0x0200 @@ -148,6 +149,17 @@ RB_PROTOTYPE_STATIC(oio_timer_s, oio_req_s, tree_entry, oio_timer_compare); static struct oio_timer_s oio_timers_ = RB_INITIALIZER(oio_timers_); +/* Lists of active oio_prepare / oio_check / oio_idle watchers */ +static oio_handle* oio_prepare_handles_ = NULL; +static oio_handle* oio_check_handles_ = NULL; +static oio_handle* oio_idle_handles_ = NULL; + +/* This pointer will refer to the prepare/check/idle handle whose callback */ +/* is scheduled to be called next. This is needed to allow safe removal */ +/* from one of the lists above while that list being iterated. */ +static oio_handle* oio_next_loop_handle_ = NULL; + + /* Head of a single-linked list of closed handles */ static oio_handle* oio_endgame_handles_ = NULL; @@ -496,6 +508,20 @@ static void oio_tcp_endgame(oio_handle* handle) { } +static void oio_loop_endgame(oio_handle* handle) { + if (handle->flags & OIO_HANDLE_CLOSING) { + assert(!(handle->flags & OIO_HANDLE_CLOSED)); + handle->flags |= OIO_HANDLE_CLOSED; + + if (handle->close_cb) { + handle->close_cb(handle, 0); + } + + oio_refs_--; + } +} + + static void oio_call_endgames() { oio_handle* handle; @@ -510,6 +536,12 @@ static void oio_call_endgames() { oio_tcp_endgame(handle); break; + case OIO_PREPARE: + case OIO_CHECK: + case OIO_IDLE: + oio_loop_endgame(handle); + break; + default: assert(0); break; @@ -542,6 +574,21 @@ static int oio_close_error(oio_handle* handle, oio_err e) { oio_want_endgame(handle); return 0; + case OIO_PREPARE: + oio_prepare_stop(handle); + oio_want_endgame(handle); + return 0; + + case OIO_CHECK: + oio_check_stop(handle); + oio_want_endgame(handle); + return 0; + + case OIO_IDLE: + oio_idle_stop(handle); + oio_want_endgame(handle); + return 0; + default: /* Not supported */ assert(0); @@ -936,6 +983,137 @@ int64_t oio_now() { } +int oio_loop_init(oio_handle* handle, oio_close_cb cb, void* data) { + handle->data = data; + handle->flags = 0; + handle->error = oio_ok_; + + oio_refs_++; + + return 0; +} + + +static int oio_loop_start(oio_handle* handle, oio_loop_cb loop_cb, + oio_handle** list) { + oio_handle* old_head; + + if (handle->flags & OIO_HANDLE_ACTIVE) + return 0; + + old_head = *list; + + handle->loop_next = old_head; + handle->loop_prev = NULL; + + if (old_head) { + old_head->loop_prev = handle; + } + + *list = handle; + + handle->loop_cb = loop_cb; + handle->flags |= OIO_HANDLE_ACTIVE; + + return 0; +} + + +static int oio_loop_stop(oio_handle* handle, oio_handle** list) { + if (!(handle->flags & OIO_HANDLE_ACTIVE)) + return 0; + + /* Update loop head if needed */ + if (*list == handle) { + *list = handle->loop_next; + } + + /* Update the iterator-next pointer of needed */ + if (oio_next_loop_handle_ == handle) { + oio_next_loop_handle_ = handle->loop_next; + } + + if (handle->loop_prev) { + handle->loop_prev->loop_next = handle->loop_next; + } + if (handle->loop_next) { + handle->loop_next->loop_prev = handle->loop_prev; + } + + handle->flags &= ~OIO_HANDLE_ACTIVE; + + return 0; +} + + +static void oio_loop_invoke(oio_handle* list) { + oio_handle *handle; + + oio_next_loop_handle_ = list; + + while (oio_next_loop_handle_ != NULL) { + handle = oio_next_loop_handle_; + oio_next_loop_handle_ = handle->loop_next; + + ((oio_loop_cb)handle->loop_cb)(handle, 0); + } +} + + +int oio_prepare_init(oio_handle* handle, oio_close_cb close_cb, void* data) { + handle->type = OIO_PREPARE; + return oio_loop_init(handle, close_cb, data); +} + + +int oio_check_init(oio_handle* handle, oio_close_cb close_cb, void* data) { + handle->type = OIO_CHECK; + return oio_loop_init(handle, close_cb, data); +} + + +int oio_idle_init(oio_handle* handle, oio_close_cb close_cb, void* data) { + handle->type = OIO_IDLE; + return oio_loop_init(handle, close_cb, data); +} + + +int oio_prepare_start(oio_handle* handle, oio_loop_cb loop_cb) { + assert(handle->type == OIO_PREPARE); + return oio_loop_start(handle, loop_cb, &oio_prepare_handles_); +} + + +int oio_check_start(oio_handle* handle, oio_loop_cb loop_cb) { + assert(handle->type == OIO_CHECK); + return oio_loop_start(handle, loop_cb, &oio_check_handles_); +} + + +int oio_idle_start(oio_handle* handle, oio_loop_cb loop_cb) { + assert(handle->type == OIO_IDLE); + return oio_loop_start(handle, loop_cb, &oio_idle_handles_); +} + + +int oio_prepare_stop(oio_handle* handle) { + assert(handle->type == OIO_PREPARE); + return oio_loop_stop(handle, &oio_prepare_handles_); +} + + +int oio_check_stop(oio_handle* handle) { + assert(handle->type == OIO_CHECK); + return oio_loop_stop(handle, &oio_check_handles_); +} + + +int oio_idle_stop(oio_handle* handle) { + assert(handle->type == OIO_IDLE); + return oio_loop_stop(handle, &oio_idle_handles_); +} + + static void oio_poll() { BOOL success; DWORD bytes; @@ -955,6 +1133,8 @@ static void oio_poll() { if (oio_refs_ == 0) return; + oio_loop_invoke(oio_prepare_handles_); + oio_update_time(); /* Check if there are any running timers */ @@ -982,8 +1162,12 @@ static void oio_poll() { &overlapped, timeout); - /* Call timer callbacks */ oio_update_time(); + + /* Call check callbacks */ + oio_loop_invoke(oio_check_handles_); + + /* Call timer callbacks */ for (req = RB_MIN(oio_timer_s, &oio_timers_); req != NULL && req->due <= oio_now_; req = RB_MIN(oio_timer_s, &oio_timers_)) { @@ -1134,6 +1318,12 @@ static void oio_poll() { oio_want_endgame(handle); } } /* if (overlapped) */ + + /* Call idle callbacks */ + while (oio_idle_handles_) { + oio_loop_invoke(oio_idle_handles_); + oio_call_endgames(); + } } diff --git a/oio-win.h b/oio-win.h index 554c12e6..b44ba45d 100644 --- a/oio-win.h +++ b/oio-win.h @@ -76,10 +76,16 @@ typedef struct oio_buf { struct { oio_tcp_server_fields }; \ }; +#define oio_loop_fields \ + oio_handle* loop_prev; \ + oio_handle* loop_next; \ + void* loop_cb; + #define oio_handle_private_fields \ oio_handle* endgame_next; \ unsigned int flags; \ oio_err error; \ union { \ struct { oio_tcp_fields }; \ + struct { oio_loop_fields }; \ };