int main()

in glean/lang/clang/index.cpp [556:708]


int main(int argc, char **argv) {
#if FACEBOOK
  facebook::initFacebook(&argc, &argv);
#else
  folly::init(&argc, &argv);
#endif

  std::signal(SIGTERM, [](int) {
    #if FACEBOOK
    LOG(CRITICAL)
    #else
    LOG(ERROR)
    #endif
      << "worker " << FLAGS_worker_index << " received SIGTERM, exiting";
    _exit(1);
  });

  Config config(argc, argv);

  std::filesystem::current_path(
    config.root / std::filesystem::path(config.cwd_subdir.value_or("")));

  const auto work_counter = FLAGS_work_file.empty()
    ? worklist::serialCounter(0, config.sources.size())
    : worklist::stealingCounter(
        FLAGS_work_file, FLAGS_worker_index, FLAGS_worker_count);

  SourceIndexer indexer(config);

  llvm::install_fatal_error_handler(&handleLLVMError, nullptr);

  const size_t n = FLAGS_stop_after != 0
    ? std::min(size_t(FLAGS_stop_after), config.sources.size())
    : config.sources.size();

  FactStats prev_stats = {0,0};
  FactStats lifetime_stats = {0,0};
  uint32_t lifetime_files = 0;

  bool error_exit = false;
  bool memory_exit = false;
  int rss = 0;
  for (auto next = work_counter->next();
        next.has_value();
        next = work_counter->next()) {
    const auto i = next.value().start;
    auto errorGuard = folly::makeGuard([&] {
      LOG_CFG(ERROR,config) << "error guard at "
        << i+1 << "/" << next.value().end << " [" << n << "] "
        << config.sources[i].file;
    });

    if (FLAGS_log_every != 0 && (lifetime_files % FLAGS_log_every) == 0) {
      LOG_CFG(INFO,config)
        << i+1 << "/" << next.value().end << " [" << n << "] "
        << config.sources[i].file;
      if (FLAGS_fact_stats) {
        LOG_CFG(INFO,config)
          << "fact buffer: " << showStats(indexer.batch.bufferStats())
          << " cache: " << showStats(indexer.batch.cacheStats().facts)
          << " lifetime: " << showStats(lifetime_stats);
      }
    }

    const auto& source = config.sources[i];
    const auto buf_stats = indexer.batch.bufferStats();
    const auto cache_stats = indexer.batch.cacheStats();
    try {
      bool ok = config
        .logger("clang/index")
        .log_index(source, buf_stats, cache_stats, [&]() {
          return indexer.index(source);
        });
      if (!ok && FLAGS_fail_on_error) {
        LOG(ERROR) << "compilation failed for " << source.file;
        error_exit = true;
      }
    } catch(const FatalLLVMError& e) {
      // TODO: log this to Scuba if it turns out to happen a lot
      LOG(ERROR) << "fatal LLVM error in " << source.file << ": " << e.what();
      error_exit = true;
    } catch(const std::exception& e) {
      LOG(ERROR) << "while indexing " << source.file << ": " << e.what();
      error_exit = FLAGS_fail_on_error;
    }

    lifetime_stats.memory += buf_stats.memory - prev_stats.memory;
    lifetime_stats.count += buf_stats.count - prev_stats.count;
    config.counters.fact_buffer_size->store(buf_stats.memory);
    config.counters.fact_cache_size->store(cache_stats.facts.memory);
    config.counters.fact_cache_hits->store(cache_stats.hits);
    config.counters.fact_cache_misses->store(cache_stats.misses);
    if (!FLAGS_dry_run) {
      const bool wait =
        FLAGS_fact_buffer != 0 && buf_stats.memory >= FLAGS_fact_buffer;
      if (wait) {
        LOG_CFG(INFO,config)
          << "fact buffer size " << buf_stats.memory << ", waiting";
      }
      config.logger(wait ? "clang/wait" : "clang/send").log([&]() {
        config.sender->rebaseAndSend(indexer.batch.base(), wait);
      });
    }
    prev_stats = indexer.batch.bufferStats();
    ++lifetime_files;

    memory_exit = FLAGS_max_rss != 0 && (rss = getSelfRSS()) > FLAGS_max_rss;

    errorGuard.dismiss();

    if ((FLAGS_stop_after != 0 && lifetime_files >= FLAGS_stop_after)
        || memory_exit
        || error_exit) {
      LOG_CFG(WARNING,config)
        << "Exiting after "
        << i+1 << "/" << next.value().end << " [" << n << "] "
        << config.sources[i].file;
      // we do not want the for loop to call work_counter->next()
      // because that will skip the next target for no good reason
      break;
    }
  }

  if (!FLAGS_dry_run) {
    LOG_CFG(INFO,config) << "flushing";
    config.logger("clang/flush").log([&]() {
      config.sender->flush(indexer.batch.base());
    });
  }

  config.counters.fact_buffer_size->store(0);
  config.counters.fact_cache_size->store(0);

  if (memory_exit) {
    LOG_CFG(ERROR, config)
      << "Exiting due to memory pressure, RSS was " << rss
      << " kB, RSS after flushing is " << getSelfRSS()
      << " kB, --max-rss is " << FLAGS_max_rss << " kB";
  }

  LOG_CFG(INFO,config)
    << (error_exit || memory_exit ? "aborting" : "finished")
    << ", lifetime files: " << lifetime_files
    << " facts: " << showStats(lifetime_stats);

  if (memory_exit) {
    return 147;
  }
  if (error_exit) {
    return 1;
  }
  return 0;
}