pthread_t setup_listener(config_t *config) { pthread_t server_tid= 0; socketize(config->argv[0], s_listen, IPPROTO_UDP, RELAY_CONN_IS_INBOUND, "listener" ); /* must open the socket BEFORE we create the worker pool */ open_socket(s_listen, DO_BIND|DO_REUSEADDR|DO_EPOLLFD, 0, config->server_socket_rcvbuf); /* create worker pool /after/ we open the socket, otherwise we * might leak worker threads. */ if (s_listen->proto == IPPROTO_UDP) spawn(&server_tid, udp_server, s_listen, PTHREAD_CREATE_JOINABLE); else spawn(&server_tid, tcp_server, s_listen, PTHREAD_CREATE_JOINABLE); return server_tid; }
/* initialize a worker safely */ socket_worker_t *socket_worker_create(const char *arg, const config_t * config) { socket_worker_t *worker = calloc_or_fatal(sizeof(*worker)); disk_writer_t *disk_writer = calloc_or_fatal(sizeof(disk_writer_t)); if (worker == NULL || disk_writer == NULL) return NULL; int create_err; worker->base.config = config; worker->base.arg = strdup(arg); worker->exists = 1; if (!socketize(arg, &worker->base.output_socket, IPPROTO_TCP, RELAY_CONN_IS_OUTBOUND, "worker")) { FATAL("Failed to socketize worker"); return NULL; } worker->disk_writer = disk_writer; disk_writer->base.config = config; disk_writer->counters = &worker->counters; disk_writer->recents = &worker->recents; disk_writer->totals = &worker->totals; #define DECAY_1MIN 60 #define DECAY_5MIN (5 * DECAY_1MIN) #define DECAY_15MIN (15 * DECAY_1MIN) rates_init(&worker->rates[0], DECAY_1MIN); rates_init(&worker->rates[1], DECAY_5MIN); rates_init(&worker->rates[2], DECAY_15MIN); LOCK_INIT(&worker->lock); /* setup spill_path */ int wrote = snprintf(disk_writer->spill_path, PATH_MAX, "%s/event_relay.%s", config->spill_root, worker->base.output_socket.arg_clean); if (wrote < 0 || wrote >= PATH_MAX) { FATAL("Failed to construct spill_path %s", disk_writer->spill_path); return NULL; } /* Create the disk_writer before we create the main worker. * We do this because the disk_writer only consumes things * that have been handled by the main worker, and vice versa * when the main worker fails to send then it might want to give * the item to the disk worker. If we did it the other way round * we might have something to assign to the disk worker but no * disk worker to assign it to. */ create_err = pthread_create(&disk_writer->base.tid, NULL, disk_writer_thread, disk_writer); if (create_err) { FATAL("Failed to create disk worker, pthread error: %d", create_err); return NULL; } /* and finally create the thread */ create_err = pthread_create(&worker->base.tid, NULL, socket_worker_thread, worker); if (create_err) { int join_err; /* we died, so shut down our "pet" disk worker, and then exit with a message */ RELAY_ATOMIC_OR(disk_writer->base.stopping, WORKER_STOPPING); /* have to handle failure of the shutdown too */ join_err = pthread_join(disk_writer->base.tid, NULL); if (join_err) { FATAL ("Failed to create socket worker, pthread error: %d, and also failed to join disk worker, pthread error: %d", create_err, join_err); } else { FATAL("Failed to create socket worker, pthread error: %d, disk worker shut down ok", create_err); } return NULL; } /* return the worker */ return worker; }