DebugServer2
Loading...
Searching...
No Matches
ProcessSpawner.h
1//
2// Copyright (c) 2014-present, Facebook, Inc.
3// All rights reserved.
4//
5// This source code is licensed under the University of Illinois/NCSA Open
6// Source License found in the LICENSE file in the root directory of this
7// source tree. An additional grant of patent rights can be found in the
8// PATENTS file in the same directory.
9//
10
11#pragma once
12
13#include "DebugServer2/Types.h"
14
15#include <array>
16#include <functional>
17#include <mutex>
18#include <string>
19#include <thread>
20
21namespace ds2 {
22namespace Host {
23
25protected:
26 enum class RedirectMode {
27 unset,
28 console,
29 null,
30 file,
31 buffer,
32 };
33
34protected:
35 // Named indices into _descriptors/_redirectThreads and the parallel local
36 // arrays run() builds up, one per standard stream.
37 enum class StreamIndex {
38 input,
39 output,
40 error,
41 count,
42 };
43
44 // StreamIndex doesn't implicitly convert to the array index types
45 // (size_t/DWORD) it is used with; this is the one place that conversion
46 // happens.
47 static constexpr size_t Index(StreamIndex stream) {
48 return static_cast<size_t>(stream);
49 }
50
51 // Deliberately not Index(StreamIndex::count): MSVC's C2131 rejects a
52 // static data member's in-class initializer calling a member function of
53 // the still-incomplete enclosing class, even a constexpr one.
54 static constexpr size_t kStreamCount =
55 static_cast<size_t>(StreamIndex::count);
56
57protected:
58 typedef std::function<void(void *buf, size_t size)> RedirectDelegate;
59
60protected:
62 RedirectMode mode;
63 std::string path;
64 // The parent's end of a pipe, valid only for RedirectMode::buffer
65 // streams while the redirection thread is reading from it.
66 HANDLE handle;
67
68 RedirectDescriptor() : mode(RedirectMode::unset), handle(nullptr) {}
69 };
70
71protected:
72 std::string _executablePath;
73 StringCollection _arguments;
74 // Appended to the command line completely verbatim, after all quoted
75 // _arguments -- used only by setShellCommand(). cmd.exe re-parses its
76 // command text itself (via its own separate, and separately quirky, /C
77 // handling) rather than treating it as a normal, quoted argv element, so
78 // it needs to reach cmd.exe exactly as given rather than quoted the way a
79 // standard argv-consuming program would expect.
80 std::string _rawTrailingArgument;
81 EnvironmentBlock _environment;
82 // Whether setEnvironment()/addEnvironment() was ever called, as opposed
83 // to _environment merely being empty. A caller can legitimately want an
84 // explicitly empty launch environment (ProcessLaunchMixin always calls
85 // setEnvironment(), even with nothing accumulated in it); that must still
86 // reach CreateProcessW as a valid, empty environment block, not collapse
87 // to "no environment was configured, inherit ours" the way run() treats
88 // callers (onLaunchDebugServer, onExecuteProgram) that never call either
89 // method at all.
90 bool _environmentSet;
91 std::string _workingDirectory;
92 std::array<RedirectDescriptor, kStreamCount> _descriptors;
93 // One reader thread per RedirectMode::buffer stream (there can be up to two,
94 // output and error, draining concurrently -- a single multiplexed reader
95 // would risk a classic pipe deadlock: blocked reading a currently-empty
96 // stream while the child blocks writing to the other stream's full pipe).
97 std::array<std::thread, kStreamCount> _redirectThreads;
98 std::mutex _outputBufferMutex;
99 std::string _outputBuffer;
100 bool _debugOnCreate;
101 int _exitStatus;
102 ProcessId _pid;
103 HANDLE _handle;
104 ThreadId _tid;
105 HANDLE _threadHandle;
106
107public:
110
111public:
112 ProcessSpawner(const ProcessSpawner &) = delete;
113 ProcessSpawner &operator=(const ProcessSpawner &) = delete;
114
115public:
116 bool setExecutable(const std::string &path);
117 bool setShellCommand(const std::string &command);
118 bool setWorkingDirectory(const std::string &path);
119
120public:
121 bool setArguments(const StringCollection &args);
122
123 template <typename... Args> inline bool setArguments(const Args &...args) {
124 std::string args_[] = {args...};
125 return setArguments(StringCollection(&args_[0], &args_[sizeof...(Args)]));
126 }
127
128public:
129 bool setEnvironment(const EnvironmentBlock &args);
130 bool addEnvironment(const std::string &key, const std::string &val);
131
132public:
133 // Whether the created process should be started as a debuggee
134 // (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS). Defaults to false. Only
135 // Target::Windows::Process needs this set: it is the only caller that goes
136 // on to pump WaitForDebugEvent/ContinueDebugEvent for the child. Helper
137 // processes spawned to service platform-mode RPCs (launching a slave debug
138 // server, running a shell command, ...) must not be debugged, since
139 // nothing would ever continue them past their initial debug event and
140 // they would hang forever.
141 void setDebugOnCreate(bool debug) { _debugOnCreate = debug; }
142
143public:
144 bool redirectInputToConsole();
145 bool redirectOutputToConsole();
146 bool redirectErrorToConsole();
147
148public:
149 bool redirectInputToNull();
150 bool redirectOutputToNull();
151 bool redirectErrorToNull();
152
153public:
154 bool redirectInputToFile(const std::string &path);
155 bool redirectOutputToFile(const std::string &path);
156 bool redirectErrorToFile(const std::string &path);
157
158public:
159 bool redirectOutputToBuffer();
160 bool redirectErrorToBuffer();
161
162public:
163 bool redirectInputToTerminal() { return false; }
164
165public:
166 bool redirectOutputToDelegate(RedirectDelegate delegate) { return false; }
167 bool redirectErrorToDelegate(RedirectDelegate delegate) { return false; }
168
169public:
170 ErrorCode run(std::function<bool()> preExecAction = []() { return true; });
171 ErrorCode wait();
172 bool isRunning() const;
173 void flushAndExit();
174
175public:
176 inline ProcessId pid() const { return _pid; }
177 inline HANDLE handle() const { return _handle; }
178 inline ThreadId tid() const { return _tid; }
179 inline HANDLE threadHandle() const { return _threadHandle; }
180 inline int exitStatus() const { return _exitStatus; }
181 inline int signalCode() const { return 0; }
182 inline const std::string &executable() const { return _executablePath; }
183 inline const StringCollection &arguments() const { return _arguments; }
184 inline const EnvironmentBlock &environment() const { return _environment; }
185
186public:
187 ErrorCode input(const ByteVector &buf) { return kErrorUnsupported; }
188
189 inline const std::string &output() const { return _outputBuffer; }
190
191private:
192 void redirectionThread(size_t index);
193};
194} // namespace Host
195} // namespace ds2
Definition ProcessSpawner.h:24
Definition ProcessSpawner.h:61