bool w_start_listener()

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;
}