static void spawn_handling_thread(struct ns_connection *nc) { struct ns_mgr dummy = {}; sock_t sp[2]; struct ns_connection *c[2]; /* * Create a socket pair, and wrap each socket into the connection with * dummy event manager. * c[0] stays in this thread, c[1] goes to another thread. */ ns_socketpair(sp, SOCK_STREAM); c[0] = ns_add_sock(&dummy, sp[0], forwarder_ev_handler); c[1] = ns_add_sock(&dummy, sp[1], nc->listener->priv_1); /* Interlink client connection with c[0] */ link_conns(c[0], nc); /* * Switch c[0] manager from the dummy one to the real one. c[1] manager * will be set in another thread, allocated on stack of that thread. */ ns_add_conn(nc->mgr, c[0]); /* * Dress c[1] as nc. * TODO(lsm): code in accept_conn() looks similar. Refactor. */ c[1]->listener = nc->listener; c[1]->proto_handler = nc->proto_handler; c[1]->proto_data = nc->proto_data; c[1]->user_data = nc->user_data; ns_start_thread(per_connection_thread_function, c[1]); }
/* Associate a socket to a connection and and add to the manager. */ NS_INTERNAL void ns_set_sock(struct ns_connection *nc, sock_t sock) { ns_set_non_blocking_mode(sock); ns_set_close_on_exec(sock); nc->sock = sock; ns_add_conn(nc->mgr, nc); DBG(("%p %d", nc, sock)); }
/* * This thread function executes user event handler. * It runs an event manager that has only one connection, until that * connection is alive. */ static void *per_connection_thread_function(void *param) { struct ns_connection *c = (struct ns_connection *) param; struct ns_mgr m; ns_mgr_init(&m, NULL); ns_add_conn(&m, c); while (m.active_connections != NULL) { ns_mgr_poll(&m, 1000); } ns_mgr_free(&m); return param; }
/* * Create a connection, associate it with the given socket and event handler, * and add to the manager. * * See the `ns_add_sock_opts` structure for a description of the options. */ struct ns_connection *ns_add_sock_opt(struct ns_mgr *s, sock_t sock, ns_event_handler_t callback, struct ns_add_sock_opts opts) { struct ns_connection *conn; if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) { memset(conn, 0, sizeof(*conn)); ns_set_non_blocking_mode(sock); ns_set_close_on_exec(sock); conn->sock = sock; conn->handler = callback; conn->mgr = s; conn->last_io_time = time(NULL); conn->flags = opts.flags; conn->user_data = opts.user_data; ns_add_conn(s, conn); DBG(("%p %d", conn, sock)); } return conn; }