in watchman/listener.cpp [381:564]
bool w_start_listener() {
#ifndef _WIN32
struct sigaction sa;
sigset_t sigset;
#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);
logf(
ERR,
"file limit is {} kern.maxfilesperproc={}\n",
limit.rlim_cur,
maxperproc);
}
#else
maxperproc = limit.rlim_max;
logf(
ERR,
"openfiles-cur is {} openfiles-max={}\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)) {
logf(
ERR,
"failed to raise limit to {} ({}).\n",
limit.rlim_cur,
folly::errnoStr(errno));
} else {
logf(ERR, "raised file limit to {}\n", limit.rlim_cur);
}
}
getrlimit(RLIMIT_NOFILE, &limit);
#ifndef HAVE_FSEVENTS
if (limit.rlim_cur < 10240) {
logf(
ERR,
"Your file descriptor limit is very low ({})"
"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 = [](int) {};
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);
#endif
setup_signal_handlers();
std::optional<AcceptLoop> tcp_loop;
std::optional<AcceptLoop> unix_loop;
// When we unwind, ensure that we stop the accept threads
SCOPE_EXIT {
if (!w_is_stopping()) {
w_request_shutdown();
}
unix_loop.reset();
tcp_loop.reset();
};
if (listener_fd) {
// Assume that it was prepped by w_listener_prep_inetd()
logf(ERR, "Using socket from inetd as listening socket\n");
} else {
listener_fd = get_listener_unix_domain_socket(get_unix_sock_name().c_str());
if (!listener_fd) {
logf(ERR, "Failed to initialize unix domain listener\n");
return false;
}
}
if (listener_fd && !disable_unix_socket) {
unix_loop = AcceptLoop("unix-listener", std::move(listener_fd));
}
if (Configuration().getBool("enable-sanity-check", true)) {
startSanityCheckThread();
}
#ifdef _WIN32
// Start the named pipes and join them; this will
// block until the server is shutdown.
if (!disable_named_pipe) {
named_pipe_accept_loop();
}
#endif
// Clearing these will cause .join() to be called,
// so the next two lines will block until the server
// shutdown is initiated, rather than cause the server
// to shutdown.
unix_loop.reset();
tcp_loop.reset();
// 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);
size_t last_count = 0;
size_t n_clients = 0;
while (true) {
{
auto clients = UserClient::getAllClients();
n_clients = clients.size();
for (auto& client : clients) {
client->ping->notify();
}
}
// The clients lock and shared_ptr refcounts are released here, so entries
// may be removed from the active clients table.
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;
}