static void init_async(h2o_multithread_queue_t *queue, h2o_loop_t *loop) { #if defined(__linux__) /** * The kernel overhead of an eventfd file descriptor is * much lower than that of a pipe, and only one file descriptor is required */ int fd; fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (fd == -1) { perror("eventfd"); abort(); } queue->async.write = fd; queue->async.read = h2o_evloop_socket_create(loop, fd, 0); #else int fds[2]; if (cloexec_pipe(fds) != 0) { perror("pipe"); abort(); } fcntl(fds[1], F_SETFL, O_NONBLOCK); queue->async.write = fds[1]; queue->async.read = h2o_evloop_socket_create(loop, fds[0], 0); #endif queue->async.read->data = queue; h2o_socket_read_start(queue->async.read, on_read); }
void initialize_event_loop(bool is_main_thread, global_data_t *global_data, event_loop_t *loop) { memset(loop, 0, sizeof(*loop)); h2o_context_init(&loop->h2o_ctx, h2o_evloop_create(), &global_data->h2o_config); loop->h2o_accept_ctx.ctx = &loop->h2o_ctx; loop->h2o_accept_ctx.hosts = global_data->h2o_config.hosts; loop->h2o_accept_ctx.ssl_ctx = global_data->ssl_ctx; int listener_sd; if (is_main_thread) listener_sd = global_data->listener_sd; else { int flags; CHECK_ERRNO_RETURN(listener_sd, dup, global_data->listener_sd); CHECK_ERRNO_RETURN(flags, fcntl, listener_sd, F_GETFD); CHECK_ERRNO(fcntl, listener_sd, F_SETFD, flags | FD_CLOEXEC); } // Let all the threads race to call accept() on the socket; since the latter is // non-blocking, that will effectively act as load balancing. loop->h2o_socket = h2o_evloop_socket_create(loop->h2o_ctx.loop, listener_sd, H2O_SOCKET_FLAG_DONT_READ); loop->h2o_socket->data = loop; h2o_socket_read_start(loop->h2o_socket, accept_connection); h2o_multithread_register_receiver(loop->h2o_ctx.queue, &loop->h2o_receiver, process_messages); // libh2o's event loop does not support write polling unless it // controls sending the data as well, so do read polling on the // epoll file descriptor as a work-around. CHECK_ERRNO_RETURN(loop->epoll_fd, epoll_create1, EPOLL_CLOEXEC); loop->epoll_socket = h2o_evloop_socket_create(loop->h2o_ctx.loop, loop->epoll_fd, H2O_SOCKET_FLAG_DONT_READ); loop->epoll_socket->data = loop; h2o_socket_read_start(loop->epoll_socket, do_epoll_wait); if (is_main_thread) { global_data->signals = h2o_evloop_socket_create(loop->h2o_ctx.loop, global_data->signal_fd, H2O_SOCKET_FLAG_DONT_READ); global_data->signals->data = loop; h2o_socket_read_start(global_data->signals, shutdown_server); } }
static int on_config_port_complete(h2o_configurator_t *_conf, h2o_context_t *ctx) { struct port_configurator_t *conf = (void*)_conf; struct sockaddr_in addr; int fd, reuseaddr_flag = 1; h2o_socket_t *sock; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(0); addr.sin_port = htons(conf->port); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 || setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_flag, sizeof(reuseaddr_flag)) != 0 || bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0 || listen(fd, SOMAXCONN) != 0) { fprintf(stderr, "failed to listen to port %hu:%s\n", conf->port, strerror(errno)); return -1; } sock = h2o_evloop_socket_create(ctx->loop, fd, H2O_SOCKET_FLAG_IS_ACCEPT); sock->data = ctx; h2o_socket_read_start(sock, on_config_port_accept); return 0; }
void initialize_event_loop(bool is_main_thread, global_data_t *global_data, h2o_multithread_receiver_t *h2o_receiver, event_loop_t *loop) { h2o_socket_cb accept_cb = accept_connection; const config_t * const config = global_data->global_thread_data->config; memset(loop, 0, sizeof(*loop)); h2o_context_init(&loop->h2o_ctx, h2o_evloop_create(), &global_data->h2o_config); loop->h2o_accept_ctx.ctx = &loop->h2o_ctx; loop->h2o_accept_ctx.hosts = global_data->h2o_config.hosts; if (global_data->ssl_ctx) { loop->h2o_accept_ctx.ssl_ctx = global_data->ssl_ctx; start_accept_polling(config, accept_connection, true, loop); // Assume that the majority of the connections use HTTPS, // so HTTP can take a few extra operations. accept_cb = accept_http_connection; } start_accept_polling(config, accept_cb, false, loop); h2o_multithread_register_receiver(loop->h2o_ctx.queue, h2o_receiver, process_messages); if (is_main_thread) { global_data->signals = h2o_evloop_socket_create(loop->h2o_ctx.loop, global_data->signal_fd, H2O_SOCKET_FLAG_DONT_READ); global_data->signals->data = loop; h2o_socket_read_start(global_data->signals, shutdown_server); } }
static int on_config_port_context_create(h2o_configurator_t *_conf, h2o_context_t *ctx) { struct port_configurator_t *conf = (void*)_conf; h2o_socket_t *sock; /* FIXME use dup to support multithread? */ sock = h2o_evloop_socket_create(ctx->loop, conf->fd, H2O_SOCKET_FLAG_IS_ACCEPT); sock->data = ctx; h2o_socket_read_start(sock, on_config_port_accept); return 0; }
static void init_async(h2o_multithread_queue_t *queue, h2o_loop_t *loop) { int fds[2]; if (cloexec_pipe(fds) != 0) { perror("pipe"); abort(); } fcntl(fds[1], F_SETFL, O_NONBLOCK); queue->async.write = fds[1]; queue->async.read = h2o_evloop_socket_create(loop, fds[0], 0); queue->async.read->data = queue; h2o_socket_read_start(queue->async.read, on_read); }
static void *run_loop(void *_conf) { struct config_t *conf = _conf; h2o_evloop_t *loop; h2o_context_t ctx; struct listener_ctx_t *listeners = alloca(sizeof(*listeners) * conf->num_listeners); size_t i; /* setup loop and context */ loop = h2o_evloop_create(); h2o_context_init(&ctx, loop, &conf->global_config); /* setup listeners */ for (i = 0; i != conf->num_listeners; ++i) { listeners[i].ctx = &ctx; listeners[i].ssl_ctx = conf->listeners[i]->ssl_ctx; listeners[i].sock = h2o_evloop_socket_create( ctx.loop, conf->listeners[i]->fd, (struct sockaddr*)&conf->listeners[i]->addr, conf->listeners[i]->addrlen, H2O_SOCKET_FLAG_IS_ACCEPT); listeners[i].sock->data = listeners + i; } /* the main loop */ while (1) { /* start / stop trying to accept new connections */ if (conf->state.num_connections < conf->max_connections) { for (i = 0; i != conf->num_listeners; ++i) { if (! h2o_socket_is_reading(listeners[i].sock)) h2o_socket_read_start(listeners[i].sock, on_accept); } } else { for (i = 0; i != conf->num_listeners; ++i) { if (h2o_socket_is_reading(listeners[i].sock)) h2o_socket_read_stop(listeners[i].sock); } } /* run the loop once */ h2o_evloop_run(loop); } return NULL; }
static int create_listener(void) { struct sockaddr_in addr; int fd, reuseaddr_flag = 1; h2o_socket_t *sock; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(0x7f000001); addr.sin_port = htons(7890); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 || setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_flag, sizeof(reuseaddr_flag)) != 0 || bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0 || listen(fd, SOMAXCONN) != 0) { return -1; } sock = h2o_evloop_socket_create(ctx.loop, fd, (void *)&addr, sizeof(addr), H2O_SOCKET_FLAG_DONT_READ); h2o_socket_read_start(sock, on_accept); return 0; }
static void start_accept_polling(const config_t *config, h2o_socket_cb accept_cb, bool is_https, event_loop_t *loop) { const int listener_sd = get_listener_socket(config->bind_address, is_https ? config->https_port : config->port); // Let all the threads race to call accept() on the socket; since the latter is // non-blocking, that will virtually act as load balancing, and SO_REUSEPORT // will make it efficient. h2o_socket_t * const h2o_socket = h2o_evloop_socket_create(loop->h2o_ctx.loop, listener_sd, H2O_SOCKET_FLAG_DONT_READ); if (is_https) loop->h2o_https_socket = h2o_socket; else loop->h2o_socket = h2o_socket; h2o_socket->data = loop; h2o_socket_read_start(h2o_socket, accept_cb); }