mirror of
https://github.com/facebook/sapling.git
synced 2024-10-09 08:18:15 +03:00
154d7309c9
Summary: This commit introduces a new process spawning class derived from the ChildProcess class in the watchman codebase. `SpawnedProcess` is similar to folly::Subprocess but is designed around the idea that we will use a system provided spawning API to start a process, rather than assuming the use of `fork`. `fork` is to be avoided because it can be expensive for processes with large address spaces and also because it interacts poorly with threads on macOS. In particular, we see the objC runtime terminating our process in some scenarios where fork and threads are mixed. There are some important differences from `folly::Subprocess` and that means that some assumptions and uses need to be altered slightly from their prior workings. For example, detaching a SpawnedProcess moves the responsibility of waiting on the child to a periodic task as there is no way to detach via posix_spawn without also using fork. On the plus side, this commit allows unifying spawning between posix and windows systems, which simplifies the code! Reviewed By: xavierd Differential Revision: D23287763 fbshipit-source-id: b662af1d7eaaa9ed445c42f6c5765ae9af975eea
78 lines
2.1 KiB
C++
78 lines
2.1 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This software may be used and distributed according to the terms of the
|
|
* GNU General Public License version 2.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <folly/Synchronized.h>
|
|
#include <list>
|
|
#include "eden/fs/telemetry/ScribeLogger.h"
|
|
#include "eden/fs/utils/SpawnedProcess.h"
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
/**
|
|
* SubprocessScribeLogger manages an external unix process and asynchronously
|
|
* forwards newline-delimited messages to its stdin.
|
|
*/
|
|
class SubprocessScribeLogger : public ScribeLogger {
|
|
public:
|
|
/**
|
|
* Launch `executable` with `category` as the first argument.
|
|
*/
|
|
SubprocessScribeLogger(const char* executable, folly::StringPiece category);
|
|
|
|
/**
|
|
* Launch the process specified at argv[0] with the given argv, and forward
|
|
* its stdout to `stdoutFd`, if non-negative. Otherwise, output goes to
|
|
* /dev/null.
|
|
*/
|
|
explicit SubprocessScribeLogger(
|
|
const std::vector<std::string>& argv,
|
|
FileDescriptor stdoutFd = FileDescriptor());
|
|
|
|
/**
|
|
* Waits for the managed process to exit. If it is hung and doesn't complete,
|
|
* terminates the process. Either way, this destructor will completed within a
|
|
* bounded amount of time.
|
|
*/
|
|
~SubprocessScribeLogger();
|
|
|
|
/**
|
|
* Forwards a log message to the external process. Must not contain newlines,
|
|
* since that is how the process distinguishes between messages.
|
|
*
|
|
* If the writer process is not keeping up, messages are dropped.
|
|
*/
|
|
void log(std::string message) override;
|
|
using ScribeLogger::log;
|
|
|
|
private:
|
|
void closeProcess();
|
|
void writerThread();
|
|
|
|
struct State {
|
|
bool shouldStop = false;
|
|
bool didStop = false;
|
|
|
|
/// Sum of sizes of queued messages.
|
|
size_t totalBytes = 0;
|
|
/// Invariant: empty if didStop is true
|
|
std::list<std::string> messages;
|
|
};
|
|
|
|
SpawnedProcess process_;
|
|
std::thread writerThread_;
|
|
|
|
folly::Synchronized<State, std::mutex> state_;
|
|
std::condition_variable newMessageOrStop_;
|
|
std::condition_variable allMessagesWritten_;
|
|
};
|
|
|
|
} // namespace eden
|
|
} // namespace facebook
|