Implement uv_timer for windows

This commit is contained in:
Bert Belder 2011-05-17 02:24:58 +02:00
parent a730165312
commit c28fe6e170
2 changed files with 95 additions and 31 deletions

114
uv-win.c
View File

@ -141,9 +141,9 @@ static LPFN_TRANSMITFILE pTransmitFile;
/* Binary tree used to keep the list of timers sorted. */
static int uv_timer_compare(uv_req_t* t1, uv_req_t* t2);
RB_HEAD(uv_timer_s, uv_req_s);
RB_PROTOTYPE_STATIC(uv_timer_s, uv_req_s, tree_entry, uv_timer_compare);
static int uv_timer_compare(uv_handle_t* handle1, uv_handle_t* handle2);
RB_HEAD(uv_timer_s, uv_handle_s);
RB_PROTOTYPE_STATIC(uv_timer_s, uv_handle_s, tree_entry, uv_timer_compare);
/* The head of the timers tree */
static struct uv_timer_s uv_timers_ = RB_INITIALIZER(uv_timers_);
@ -538,6 +538,20 @@ static void uv_tcp_endgame(uv_handle_t* handle) {
}
static void uv_timer_endgame(uv_handle_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
if (handle->close_cb) {
handle->close_cb(handle, 0);
}
uv_refs_--;
}
}
static void uv_loop_endgame(uv_handle_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
@ -581,6 +595,10 @@ static void uv_call_endgames() {
uv_tcp_endgame(handle);
break;
case UV_TIMER:
uv_timer_endgame(handle);
break;
case UV_PREPARE:
case UV_CHECK:
case UV_IDLE:
@ -626,6 +644,11 @@ static int uv_close_error(uv_handle_t* handle, uv_err_t e) {
}
return 0;
case UV_TIMER:
uv_timer_stop(handle);
uv_want_endgame(handle);
return 0;
case UV_PREPARE:
uv_prepare_stop(handle);
uv_want_endgame(handle);
@ -1167,7 +1190,7 @@ static void uv_tcp_return_req(uv_handle_t* handle, uv_req_t* req) {
}
static int uv_timer_compare(uv_req_t* a, uv_req_t* b) {
static int uv_timer_compare(uv_handle_t* a, uv_handle_t* b) {
if (a->due < b->due)
return -1;
if (a->due > b->due)
@ -1180,22 +1203,48 @@ static int uv_timer_compare(uv_req_t* a, uv_req_t* b) {
}
RB_GENERATE_STATIC(uv_timer_s, uv_req_s, tree_entry, uv_timer_compare);
RB_GENERATE_STATIC(uv_timer_s, uv_handle_s, tree_entry, uv_timer_compare);
int uv_timeout(uv_req_t* req, int64_t timeout) {
assert(!(req->flags & UV_REQ_PENDING));
req->type = UV_TIMEOUT;
req->due = uv_now_ + timeout;
if (RB_INSERT(uv_timer_s, &uv_timers_, req) != NULL) {
uv_set_sys_error(ERROR_INVALID_DATA);
return -1;
}
int uv_timer_init(uv_handle_t* handle, uv_close_cb close_cb, void* data) {
handle->type = UV_TIMER;
handle->close_cb = (void*) close_cb;
handle->data = data;
handle->flags = 0;
handle->error = uv_ok_;
uv_refs_++;
req->flags |= UV_REQ_PENDING;
return 0;
}
int uv_timer_start(uv_handle_t* handle, uv_loop_cb timer_cb, int64_t timeout, int64_t repeat) {
if (handle->flags & UV_HANDLE_ACTIVE) {
RB_REMOVE(uv_timer_s, &uv_timers_, handle);
}
handle->timer_cb = (void*) timer_cb;
handle->due = uv_now_ + timeout;
handle->repeat = repeat;
handle->flags |= UV_HANDLE_ACTIVE;
if (RB_INSERT(uv_timer_s, &uv_timers_, handle) != NULL) {
uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
}
return 0;
}
int uv_timer_stop(uv_handle_t* handle) {
if (!(handle->flags & UV_HANDLE_ACTIVE))
return 0;
RB_REMOVE(uv_timer_s, &uv_timers_, handle);
handle->flags &= ~UV_HANDLE_ACTIVE;
return 0;
}
@ -1439,9 +1488,9 @@ static void uv_poll() {
uv_update_time();
/* Check if there are any running timers */
req = RB_MIN(uv_timer_s, &uv_timers_);
if (req) {
delta = req->due - uv_now_;
handle = RB_MIN(uv_timer_s, &uv_timers_);
if (handle) {
delta = handle->due - uv_now_;
if (delta >= UINT_MAX) {
/* Can't have a timeout greater than UINT_MAX, and a timeout value of */
/* UINT_MAX means infinite, so that's no good either. */
@ -1469,13 +1518,26 @@ static void uv_poll() {
uv_loop_invoke(uv_check_handles_);
/* Call timer callbacks */
for (req = RB_MIN(uv_timer_s, &uv_timers_);
req != NULL && req->due <= uv_now_;
req = RB_MIN(uv_timer_s, &uv_timers_)) {
RB_REMOVE(uv_timer_s, &uv_timers_, req);
req->flags &= ~UV_REQ_PENDING;
uv_refs_--;
((uv_timer_cb)req->cb)(req, req->due - uv_now_, 0);
for (handle = RB_MIN(uv_timer_s, &uv_timers_);
handle != NULL && handle->due <= uv_now_;
handle = RB_MIN(uv_timer_s, &uv_timers_)) {
RB_REMOVE(uv_timer_s, &uv_timers_, handle);
if (handle->repeat != 0) {
/* If it is a repeating timer, reschedule with repeat timeout. */
handle->due += handle->repeat;
if (handle->due < uv_now_) {
handle->due = uv_now_;
}
if (RB_INSERT(uv_timer_s, &uv_timers_, handle) != NULL) {
uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
}
} else {
/* If non-repeating, mark the timer as inactive. */
handle->flags &= ~UV_HANDLE_ACTIVE;
}
((uv_loop_cb) handle->timer_cb)(handle, 0);
}
/* Only if a iocp package was dequeued... */

View File

@ -48,11 +48,6 @@ typedef struct uv_buf_t {
OVERLAPPED overlapped; \
size_t queued_bytes; \
}; \
/* Used by timers */ \
struct { \
RB_ENTRY(uv_req_s) tree_entry; \
int64_t due; \
}; \
}; \
int flags;
@ -79,6 +74,12 @@ typedef struct uv_buf_t {
struct { uv_tcp_server_fields }; \
};
#define uv_timer_fields \
RB_ENTRY(uv_handle_s) tree_entry; \
int64_t due; \
int64_t repeat; \
void* timer_cb;
#define uv_loop_fields \
uv_handle_t* loop_prev; \
uv_handle_t* loop_next; \
@ -95,6 +96,7 @@ typedef struct uv_buf_t {
uv_err_t error; \
union { \
struct { uv_tcp_fields }; \
struct { uv_timer_fields }; \
struct { uv_loop_fields }; \
struct { uv_async_fields }; \
};