static ALWAYS_INLINE void spawn_coro(lwan_connection_t *conn, coro_switcher_t *switcher, struct death_queue_t *dq) { assert(!conn->coro); assert(!(conn->flags & CONN_IS_ALIVE)); assert(!(conn->flags & CONN_SHOULD_RESUME_CORO)); conn->coro = coro_new(switcher, process_request_coro, conn); death_queue_insert(dq, conn); conn->flags |= (CONN_IS_ALIVE | CONN_SHOULD_RESUME_CORO); conn->flags &= ~CONN_WRITE_EVENTS; }
static ALWAYS_INLINE void spawn_or_reset_coro_if_needed(lwan_connection_t *conn, coro_switcher_t *switcher, struct death_queue_t *dq) { if (conn->coro) { if (conn->flags & CONN_SHOULD_RESUME_CORO) return; coro_reset(conn->coro, process_request_coro, conn); } else { conn->coro = coro_new(switcher, process_request_coro, conn); death_queue_insert(dq, conn); conn->flags |= CONN_IS_ALIVE; } conn->flags |= CONN_SHOULD_RESUME_CORO; conn->flags &= ~CONN_WRITE_EVENTS; }
struct lwan_fd_watch *lwan_watch_fd(struct lwan *l, int fd, uint32_t events, coro_function_t coro_fn, void *data) { struct lwan_fd_watch *watch; watch = malloc(sizeof(*watch)); if (!watch) return NULL; watch->coro = coro_new(&l->switcher, coro_fn, data); if (!watch->coro) goto out; struct epoll_event ev = {.events = events, .data.ptr = watch->coro}; if (epoll_ctl(l->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { coro_free(watch->coro); goto out; } watch->fd = fd; return watch; out: free(watch); return NULL; } void lwan_unwatch_fd(struct lwan *l, struct lwan_fd_watch *w) { if (l->main_socket != w->fd) { if (epoll_ctl(l->epfd, EPOLL_CTL_DEL, w->fd, NULL) < 0) lwan_status_perror("Could not unwatch fd %d", w->fd); } coro_free(w->coro); free(w); } void lwan_main_loop(struct lwan *l) { struct epoll_event evs[16]; struct lwan_fd_watch *watch; assert(main_socket == -1); main_socket = l->main_socket; if (signal(SIGINT, sigint_handler) == SIG_ERR) lwan_status_critical("Could not set signal handler"); watch = lwan_watch_fd(l, l->main_socket, EPOLLIN | EPOLLHUP | EPOLLRDHUP, accept_connection_coro, l); if (!watch) lwan_status_critical("Could not watch main socket"); lwan_status_info("Ready to serve"); while (true) { int n_evs = epoll_wait(l->epfd, evs, N_ELEMENTS(evs), -1); if (UNLIKELY(n_evs < 0)) { if (main_socket < 0) break; if (errno == EINTR || errno == EAGAIN) continue; break; } for (int i = 0; i < n_evs; i++) { if (!coro_resume_value(evs[i].data.ptr, (int)evs[i].events)) break; } } lwan_unwatch_fd(l, watch); } #ifdef CLOCK_MONOTONIC_COARSE __attribute__((constructor)) static void detect_fastest_monotonic_clock(void) { struct timespec ts; if (!clock_gettime(CLOCK_MONOTONIC_COARSE, &ts)) monotonic_clock_id = CLOCK_MONOTONIC_COARSE; } #endif void lwan_set_thread_name(const char *name) { char thread_name[16]; char process_name[PATH_MAX]; char *tmp; int ret; if (proc_pidpath(getpid(), process_name, sizeof(process_name)) < 0) return; tmp = strrchr(process_name, '/'); if (!tmp) return; ret = snprintf(thread_name, sizeof(thread_name), "%s %s", tmp + 1, name); if (ret < 0) return; pthread_set_name_np(pthread_self(), thread_name); }
void coro_run(coro *next) { coro *caller = coro_new(NULL, NULL); coro_call(caller, next); coro_release(caller); }