#include #include #include #include #include #include #include #include #include #include #include static void mainloop(int, const struct sockaddr_in *, int); static void usage(const char *cmd) { fprintf(stderr, "%s -p port [-i n_instance] [-r] [-B]\n", cmd); exit(1); } static int create_socket(const struct sockaddr_in *in, int reuseport) { int serv_s, on; serv_s = socket(AF_INET, SOCK_STREAM, 0); if (serv_s < 0) err(1, "socket failed"); on = 1; if (!reuseport) { if (setsockopt(serv_s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) err(1, "setsockopt(REUSEADDR) failed"); } else { if (setsockopt(serv_s, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) err(1, "setsockopt(REUSEPORT) failed"); } if (bind(serv_s, (const struct sockaddr *)in, sizeof(*in)) < 0) err(1, "bind failed"); if (listen(serv_s, -1) < 0) err(1, "listen failed"); return serv_s; } int main(int argc, char *argv[]) { struct sockaddr_in in; int opt, ninst, serv_s, i, reuseport, bindcpu; size_t prm_len; prm_len = sizeof(ninst); if (sysctlbyname("hw.ncpu", &ninst, &prm_len, NULL, 0) != 0) err(2, "sysctl hw.ncpu failed"); memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_addr.s_addr = INADDR_ANY; bindcpu = 0; reuseport = 0; while ((opt = getopt(argc, argv, "Bp:i:r")) != -1) { switch (opt) { case 'p': in.sin_port = htons(atoi(optarg)); break; case 'i': ninst = atoi(optarg); break; case 'r': reuseport = 1; break; case 'B': bindcpu = 1; break; default: usage(argv[0]); } } if (ninst < 1 || in.sin_port == 0) usage(argv[0]); if (!reuseport) bindcpu = 0; serv_s = -1; if (!reuseport) serv_s = create_socket(&in, 0); for (i = 1; i < ninst; ++i) { pid_t pid; pid = fork(); if (pid == 0) { mainloop(serv_s, &in, bindcpu); exit(0); } else if (pid < 0) { err(1, "fork failed"); } } mainloop(serv_s, &in, bindcpu); exit(0); } static void mainloop(int serv_s, const struct sockaddr_in *in, int bindcpu) { if (serv_s < 0) serv_s = create_socket(in, 1); if (bindcpu) { socklen_t cpu_len; int cpu; cpu_len = sizeof(cpu); if (getsockopt(serv_s, SOL_SOCKET, SO_CPUHINT, &cpu, &cpu_len) < 0) err(1, "getsockopt(CPUHINT) failed"); if (cpu >= 0) usched_set(getpid(), USCHED_SET_CPU, &cpu, sizeof(cpu)); } for (;;) { int s; s = accept(serv_s, NULL, NULL); if (s >= 0) close(s); } /* NEVER REACHED */ }