void async_wakeup(async_t *const thread) { assert(thread != async_main); async_t *const original = async_main; async_main = async_active(); async_switch(thread); async_main = original; }
void async_close(uv_handle_t *const handle) { if(UV_UNKNOWN_HANDLE == handle->type) return; handle->data = async_active(); uv_close(handle, close_cb); async_yield(); memset(handle, 0, uv_handle_size(handle->type)); // Luckily UV_UNKNOWN_HANDLE is 0. }
int async_canceled(void) { async_t *const thread = async_active(); if(ASYNC_CANCELED & thread->flags) { thread->flags &= ~ASYNC_CANCELED; return UV_ECANCELED; } return 0; }
int async_tcp_connect(uv_tcp_t *const stream, struct sockaddr const *const addr) { async_state state[1]; state->thread = async_active(); uv_connect_t req[1]; req->data = state; int rc = uv_tcp_connect(req, stream, addr, connect_cb); if(rc < 0) return rc; async_yield(); return state->status; }
int async_write(uv_stream_t *const stream, uv_buf_t const bufs[], unsigned const nbufs) { async_state state[1]; state->thread = async_active(); uv_write_t req[1]; req->data = &state; int rc = uv_write(req, stream, bufs, nbufs, write_cb); if(rc < 0) return rc; async_yield(); return state->status; }
int async_getnameinfo(uv_getnameinfo_t *const req, struct sockaddr const *const addr, int const flags) { uv_getnameinfo_cb cb = NULL; if(async_main) { req->data = async_active(); cb = getnameinfo_cb; } int rc = uv_getnameinfo(async_loop, req, cb, addr, flags); if(rc < 0) return rc; if(cb) async_yield(); return req->retcode; }
int async_spawn(size_t const stack, void (*const func)(void *), void *const arg) { cothread_t const fiber = co_create(stack, async_start); if(!fiber) return UV_ENOMEM; arg_func = func; arg_arg = arg; // Similar to async_wakeup but the new thread is not created yet async_t *const original = async_main; async_main = async_active(); co_switch(fiber); async_main = original; return 0; }
int async_sleep(uint64_t const milliseconds) { uv_timer_t timer[1]; timer->data = async_active(); int rc = uv_timer_init(async_loop, timer); if(rc < 0) return rc; if(milliseconds > 0) { rc = uv_timer_start(timer, timer_cb, milliseconds, 0); if(rc < 0) return rc; async_yield(); } // Not worth calling async_close. uv_close((uv_handle_t *)timer, close_cb); async_yield(); return 0; }
void async_rwlock_wrlock(async_rwlock_t *const lock) { assert(lock); assert(async_main); assert(async_active() != async_main); if(async_rwlock_trywrlock(lock) >= 0) return; async_thread_list us = { .thread = async_active(), .next = NULL, }; if(!lock->wrhead) lock->wrhead = &us; if(lock->wrtail) lock->wrtail->next = &us; lock->wrtail = &us; async_yield(); assert(s_write == lock->state); assert(!lock->upgrade); }
int async_rwlock_upgrade(async_rwlock_t *const lock) { assert(lock); assert(lock->state > 0); assert(lock->state <= READERS_MAX); if(lock->upgrade) return -1; --lock->state; if(lock->state > 0) { lock->upgrade = async_active(); async_yield(); assert(!lock->upgrade && "Upgrade not cleared"); assert(s_write == lock->state && "Wrong upgrade woken"); } else { lock->state = s_write; } return 0; }
int async_yield_cancelable(void) { async_t *const thread = async_active(); if(ASYNC_CANCELED & thread->flags) { thread->flags &= ~ASYNC_CANCELED; return UV_ECANCELED; } assert(!(ASYNC_CANCELABLE & thread->flags)); thread->flags |= ASYNC_CANCELABLE; async_yield(); thread->flags &= ~ASYNC_CANCELABLE; if(ASYNC_CANCELED & thread->flags) { thread->flags &= ~ASYNC_CANCELED; return UV_ECANCELED; } return 0; }
int async_poll_socket(uv_os_sock_t const socket, int *const events) { assert(events); struct poll_state state[1]; state->thread = async_active(); state->status = 0; state->events = 0; uv_poll_t poll[1]; poll->data = state; int rc = uv_poll_init_socket(async_loop, poll, socket); if(rc < 0) return rc; rc = uv_poll_start(poll, *events, poll_cb); if(rc < 0) return rc; async_yield(); async_close((uv_handle_t *)poll); *events = state->events; return state->status; }
void async_rwlock_rdlock(async_rwlock_t *const lock) { assert(lock); assert(async_main); assert(async_active() != async_main); if(async_rwlock_tryrdlock(lock) >= 0) return; async_thread_list us = { .thread = async_active(), .next = NULL, }; if(!lock->rdhead) lock->rdhead = &us; if(lock->rdtail) lock->rdtail->next = &us; lock->rdtail = &us; async_yield(); assert(lock->state > 0); assert(lock->state <= READERS_MAX); assert(!lock->wrhead); assert(!lock->upgrade); }
int async_read(uv_stream_t *const stream, size_t const size, uv_buf_t *const out) { if(!stream) return UV_EINVAL; if(!out) return UV_EINVAL; async_state state[1]; state->thread = async_active(); state->size = size; state->status = 0; *state->buf = uv_buf_init(NULL, 0); stream->data = state; int rc = uv_read_start(stream, alloc_cb, read_cb); if(rc < 0) return rc; rc = async_yield_cancelable(); uv_read_stop(stream); if(rc < 0) { free(state->buf->base); return rc; } out->base = state->buf->base; out->len = state->buf->len; return state->status; }
int async_getaddrinfo(char const *const node, char const *const service, struct addrinfo const *const hints, struct addrinfo **const res) { // uv_getaddrinfo kind of sucks so we try to avoid it. // TODO: We don't ever define __POSIX__ currently. #if defined(__POSIX__) || defined(CORO_USE_VALGRIND) async_pool_enter(NULL); int rc = getaddrinfo(node, service, hints, res); async_pool_leave(NULL); return rc; #else getaddrinfo_state state[1]; uv_getaddrinfo_t req[1]; req->data = state; uv_getaddrinfo_cb cb = NULL; if(async_main) { state->thread = async_active(); cb = getaddrinfo_cb; } int rc = uv_getaddrinfo(async_loop, req, cb, node, service, hints); if(rc < 0) return rc; if(cb) async_yield(); if(res) *res = state->res; return state->status; #endif }