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_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_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; }
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_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 }
int async_yield_flags(unsigned const flags) { if(ASYNC_CANCELABLE & flags) return async_yield_cancelable(); async_yield(); return 0; }