bool w_start_listener(const char *path) { #ifndef _WIN32 struct sigaction sa; sigset_t sigset; #endif #ifdef HAVE_LIBGIMLI_H hb = gimli_heartbeat_attach(); #endif #if defined(HAVE_KQUEUE) || defined(HAVE_FSEVENTS) { struct rlimit limit; # ifndef __OpenBSD__ int mib[2] = { CTL_KERN, # ifdef KERN_MAXFILESPERPROC KERN_MAXFILESPERPROC # else KERN_MAXFILES # endif }; # endif int maxperproc; getrlimit(RLIMIT_NOFILE, &limit); # ifndef __OpenBSD__ { size_t len; len = sizeof(maxperproc); sysctl(mib, 2, &maxperproc, &len, NULL, 0); w_log(W_LOG_ERR, "file limit is %" PRIu64 " kern.maxfilesperproc=%i\n", limit.rlim_cur, maxperproc); } # else maxperproc = limit.rlim_max; w_log(W_LOG_ERR, "openfiles-cur is %" PRIu64 " openfiles-max=%i\n", limit.rlim_cur, maxperproc); # endif if (limit.rlim_cur != RLIM_INFINITY && maxperproc > 0 && limit.rlim_cur < (rlim_t)maxperproc) { limit.rlim_cur = maxperproc; if (setrlimit(RLIMIT_NOFILE, &limit)) { w_log(W_LOG_ERR, "failed to raise limit to %" PRIu64 " (%s).\n", limit.rlim_cur, strerror(errno)); } else { w_log(W_LOG_ERR, "raised file limit to %" PRIu64 "\n", limit.rlim_cur); } } getrlimit(RLIMIT_NOFILE, &limit); #ifndef HAVE_FSEVENTS if (limit.rlim_cur < 10240) { w_log(W_LOG_ERR, "Your file descriptor limit is very low (%" PRIu64 "), " "please consult the watchman docs on raising the limits\n", limit.rlim_cur); } #endif } #endif #ifndef _WIN32 signal(SIGPIPE, SIG_IGN); /* allow SIGUSR1 and SIGCHLD to wake up a blocked thread, without restarting * syscalls */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = wakeme; sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL); sigaction(SIGCHLD, &sa, NULL); // Block SIGCHLD everywhere sigemptyset(&sigset); sigaddset(&sigset, SIGCHLD); sigprocmask(SIG_BLOCK, &sigset, NULL); if (listener_fd) { // Assume that it was prepped by w_listener_prep_inetd() w_log(W_LOG_ERR, "Using socket from inetd as listening socket\n"); } else { listener_fd = get_listener_socket(path); if (!listener_fd) { return false; } } listener_fd.setCloExec(); #endif #ifdef HAVE_LIBGIMLI_H if (hb) { gimli_heartbeat_set(hb, GIMLI_HB_RUNNING); } else { w_setup_signal_handlers(); } #else w_setup_signal_handlers(); #endif listener_fd.setNonBlock(); startSanityCheckThread(); // Now run the dispatch #ifndef _WIN32 listener_thread_event = w_event_make(); accept_loop(std::move(listener_fd)); #else named_pipe_accept_loop(path); #endif // Wait for clients, waking any sleeping clients up in the process { auto interval = std::chrono::microseconds(2000); const auto max_interval = std::chrono::seconds(1); const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); int last_count = 0, n_clients = 0; while (true) { { auto clientsLock = clients.rlock(); n_clients = clientsLock->size(); for (auto client : *clientsLock) { client->ping->notify(); } } if (n_clients == 0) { break; } if (std::chrono::steady_clock::now() >= deadline) { log(ERR, "Abandoning wait for ", n_clients, " outstanding clients\n"); break; } if (n_clients != last_count) { log(ERR, "waiting for ", n_clients, " clients to terminate\n"); } /* sleep override */ std::this_thread::sleep_for(interval); interval *= 2; if (interval > max_interval) { interval = max_interval; } } } w_state_shutdown(); return true; }