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 { int interval = 2000; int last_count = 0, n_clients = 0; const int max_interval = 1000000; // 1 second do { { auto clientsLock = clients.rlock(); n_clients = clientsLock->size(); for (auto client : *clientsLock) { client->ping->notify(); } } if (n_clients != last_count) { w_log(W_LOG_ERR, "waiting for %d clients to terminate\n", n_clients); } usleep(interval); interval = std::min(interval * 2, max_interval); } while (n_clients > 0); } w_state_shutdown(); return true; }
bool KQueueWatcher::startWatchFile(struct watchman_file* file) { struct kevent k; auto full_name = w_dir_path_cat_str(file->parent, file->getName()); { auto rlock = maps_.rlock(); if (rlock->name_to_fd.find(full_name) != rlock->name_to_fd.end()) { // Already watching it return true; } } w_log(W_LOG_DBG, "watch_file(%s)\n", full_name.c_str()); FileDescriptor fdHolder(open(full_name.c_str(), O_EVTONLY | O_CLOEXEC)); auto rawFd = fdHolder.fd(); if (rawFd == -1) { watchman::log( watchman::ERR, "failed to open ", full_name, ", O_EVTONLY: ", strerror(errno), "\n"); return false; } memset(&k, 0, sizeof(k)); EV_SET( &k, rawFd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_RENAME | NOTE_ATTRIB, 0, (w_string_t*)full_name); { auto wlock = maps_.wlock(); wlock->name_to_fd[full_name] = std::move(fdHolder); wlock->fd_to_name[rawFd] = full_name; } if (kevent(kq_fd.fd(), &k, 1, nullptr, 0, 0)) { watchman::log( watchman::DBG, "kevent EV_ADD file ", full_name, " failed: ", full_name.c_str(), strerror(errno), "\n"); auto wlock = maps_.wlock(); wlock->name_to_fd.erase(full_name); wlock->fd_to_name.erase(rawFd); } else { watchman::log( watchman::DBG, "kevent file ", full_name, " -> ", rawFd, "\n"); } return true; }