static void shutdown_server(h2o_socket_t *listener, const char *err) { if (err) ERROR(err); else { thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t, event_loop, listener->data); ctx->global_data->shutdown = true; // Close the listening sockets immediately, so that if another instance // of the application is started before the current one exits (e.g. when // doing an update), it will accept all incoming connections. if (ctx->event_loop.h2o_https_socket) { h2o_socket_read_stop(ctx->event_loop.h2o_https_socket); h2o_socket_close(ctx->event_loop.h2o_https_socket); ctx->event_loop.h2o_https_socket = NULL; } if (ctx->event_loop.h2o_socket) { h2o_socket_read_stop(ctx->event_loop.h2o_socket); h2o_socket_close(ctx->event_loop.h2o_socket); ctx->event_loop.h2o_socket = NULL; } for (size_t i = ctx->config->thread_num - 1; i > 0; i--) h2o_multithread_send_message(&ctx->global_thread_data[i].h2o_receiver, NULL); } }
static void discard_req(h2o_memcached_req_t *req) { switch (req->type) { case REQ_TYPE_GET: h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message); break; default: free_req(req); break; } }
static void shutdown_server(h2o_socket_t *listener, const char *err) { if (!err) { thread_context_t * const ctx = H2O_STRUCT_FROM_MEMBER(thread_context_t, event_loop, listener->data); ctx->global_data->shutdown = true; h2o_socket_read_stop(ctx->event_loop.h2o_socket); for (size_t i = 1; i < ctx->global_data->config->thread_num; i++) h2o_multithread_send_message(&ctx[i].event_loop.h2o_receiver, NULL); } }
static void lookup_and_respond(h2o_hostinfo_getaddr_req_t *req) { struct addrinfo *res; int ret = getaddrinfo(req->_in.name, req->_in.serv, &req->_in.hints, &res); req->_out.message = (h2o_multithread_message_t){0}; if (ret != 0) { req->_out.errstr = gai_strerror(ret); req->_out.ai = NULL; } else { req->_out.errstr = NULL; req->_out.ai = res; } h2o_multithread_send_message(req->_receiver, &req->_out.message); }
static void send_empty_message(h2o_multithread_receiver_t *receiver) { h2o_multithread_message_t *message = h2o_mem_alloc(sizeof(*message)); *message = (h2o_multithread_message_t){{NULL}}; h2o_multithread_send_message(receiver, message); }
static void reader_main(h2o_memcached_context_t *ctx) { struct st_h2o_memcached_conn_t conn = {ctx, {}, PTHREAD_MUTEX_INITIALIZER, {&conn.inflight, &conn.inflight}, 0}; pthread_t writer_thread; yrmcds_response resp; yrmcds_error err; /* connect to server and start the writer thread */ connect_to_server(conn.ctx, &conn.yrmcds); pthread_create(&writer_thread, NULL, writer_main, &conn); pthread_mutex_lock(&conn.ctx->mutex); ++conn.ctx->num_threads_connected; pthread_mutex_unlock(&conn.ctx->mutex); /* receive data until an error occurs */ while (1) { if ((err = yrmcds_recv(&conn.yrmcds, &resp)) != YRMCDS_OK) { fprintf(stderr, "[lib/common/memcached.c] yrmcds_recv:%s\n", yrmcds_strerror(err)); break; } h2o_memcached_req_t *req = pop_inflight(&conn, resp.serial); if (req == NULL) { fprintf(stderr, "[lib/common/memcached.c] received unexpected serial\n"); break; } if (resp.status == YRMCDS_STATUS_OK) { req->data.get.value = h2o_iovec_init(h2o_mem_alloc(resp.data_len), resp.data_len); memcpy(req->data.get.value.base, resp.data, resp.data_len); h2o_mem_set_secure((void *)resp.data, 0, resp.data_len); } h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message); } /* send error to all the reqs in-flight */ pthread_mutex_lock(&conn.mutex); while (!h2o_linklist_is_empty(&conn.inflight)) { h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, conn.inflight.next); h2o_linklist_unlink(&req->inflight); assert(req->type == REQ_TYPE_GET); h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message); } pthread_mutex_unlock(&conn.mutex); /* stop the writer thread */ __sync_add_and_fetch(&conn.writer_exit_requested, 1); pthread_mutex_lock(&conn.ctx->mutex); pthread_cond_broadcast(&conn.ctx->cond); pthread_mutex_unlock(&conn.ctx->mutex); pthread_join(writer_thread, NULL); /* decrement num_threads_connected, and discard all the pending requests if no connections are alive */ pthread_mutex_lock(&conn.ctx->mutex); if (--conn.ctx->num_threads_connected == 0) { while (!h2o_linklist_is_empty(&conn.ctx->pending)) { h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, pending, conn.ctx->pending.next); h2o_linklist_unlink(&req->pending); discard_req(req); } } pthread_mutex_unlock(&conn.ctx->mutex); /* close the connection */ yrmcds_close(&conn.yrmcds); }