Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
ProcessRunner.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_ProcessRunner_h_
5#define _Stroika_Foundation_Execution_ProcessRunner_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <filesystem>
10#include <optional>
11
14#include "Stroika/Foundation/Common/Common.h"
15#include "Stroika/Foundation/Containers/Mapping.h"
16#include "Stroika/Foundation/Containers/Sequence.h"
18#include "Stroika/Foundation/Execution/CommandLine.h"
19#include "Stroika/Foundation/Execution/Signals.h"
23
24#include "Process.h"
25#include "ProgressMonitor.h"
26
27/**
28 * TODO:
29 * @todo After we lose DEPRECATED APIS (STREAM STUFF) - Run and RunInBackground can become const methods
30 *
31 * @todo Cleanup ProcessRunner::CreateRunnable_ () to use more Finally {} based cleanup, instead
32 * of more redundant try/catch style.
33 *
34 * @todo Redo POSIX impl using vfork () or http://linux.die.net/man/3/posix_spawn
35 *
36 * @todo Fix POSIX version to use vfork() instead of fork () - but carefully! Must setup data just so.
37 *
38 * @todo Fix POSIX version to properly handle reading and writing streams at the same time to avoid deadlock
39 * in finite kernel buffer sizes.
40 *
41 * @todo Fix POSIX version to use pipe2 and close appropriate open file descriptors (and other 'clean invoke' stuff.
42 *
43 * @todo Redo DWORD waitResult = ::WaitForMultipleObjects()... logic to wait on thread and each read/write socket
44 * with select() AND somehow maybe eventually wait on streams (so we don't have to pre-read it all)
45 *
46 * @todo logic for THREADs and for PROGRESS support are NOT thought through, and just a rough first stab
47 *
48 * @todo Make sure it handles well without blocking
49 * (tricks I had todo in HF - forcing extra reads so writes wouldn't block).
50 * Currently structured to work off a single runnable, which implies works off a single thread. That implies
51 * it must use select() - probably a good idea anyhow - on each socket used for operations (windows and POSIX).
52 *
53 * So data pusher/buffer loop does select on external streams to see if data available.
54 *
55 * This implies I must also be able to do the moral equivalent of selects on my BinaryInput/Output streams? Maybe,
56 * unless I do all the buffering... But at least for the stdin stream - I need to be able to check if/when there
57 * is new data available!!! TRICKY
58 *
59 * @todo Decide on/document semantics if there is a change in setting STDIN/SETDOUT etc while a runner exists?
60 * If error - always detectable?
61 *
62 * And related - what if we create a runner, and then destroy the object? How to assure runner fully
63 * destroyed? Blocking/waiting or error or detached state?
64 *
65 * @todo Add optional hook to be run (at least for POSIX) inside the FORKED process, before the exec.
66 * Can be used to reset signals, and/or close file descriptors. Maybe have optional
67 * flag to auto-do this stuff and or have a preset value hook proc do do most standard things.
68 *
69 * Design Goals:
70 * o Be able to run simple processes and capture output with little overhead, and very easy to do
71 * (like perl backticks).
72 *
73 * o Be able to support pipes between processes (either within the shell, or between Stroika threads)
74 *
75 * o Support large data and blocking issues properly - automating avoidance of pipe full bugs
76 * which block processes
77 *
78 * o Efficient/Low performance overhead
79 *
80 * o For POSIX - simple to cleanly cleanup open sockets/resources (not needed on windows)
81 *
82 * o Separate threading implementation from API, so easy to externally specify the thread
83 * stuff runs on (e.g. so you can use thread pools to run the processes).
84 *
85 * o Work with stroika streams so its easy to have user-defined producers and consumers, and
86 * easy to hook together TextStreams (wrappers) - for format conversion/piping.
87 *
88 * \em Design Overview
89 * o
90 *
91 */
92
94
95 using Characters::String;
96 using Containers::Mapping;
97 using Containers::Sequence;
98
99 /**
100 * \brief Run the given command, and optionally support stdin/stdout/stderr as streams (either sync with Run, RunInBackground)
101 *
102 * \note ProcessRunner searches the PATH for the given executable: it need not be a full or even relative to
103 * cwd path.
104 *
105 * \note Historical Note:
106 * IDEA HERE IS FROM KDJ - Do something like python/perl stuff for managing subprocesses easily.
107 *
108 * Look input stream, output stream(or streams - stdout/stderr) - and some kind of external process control
109 * so can say WIAT or Terminate.
110 *
111 * Simple portable wrapper.
112 *
113 * Could use simple singly threaded approach used in TypeNValue ReportDefinition::RunExternalProcess_ (const SDKString& cmdLine, const SDKString& currentDir, const BLOBs::BLOB& stdinBLOB, const ContentType& resultFormat, float timeout)
114 * except that code has the defect that when the input pipe is full, and there is nothing in the output pipes
115 * it busy waits. We COULD fix this by doing a select.
116 *
117 * OR - as KDJ suggests - create 3 threads - one that just reads on stdout, one that just reads on stderr, and one that
118 * spits into stdin.
119 *
120 * The caller of 'subprocess' then would just wait on each of the 3 subprocesses (or would implement the aforementioned
121 * looping over reads/writes/selects etc).
122 *
123 * \par Example Usage
124 * \code
125 * String name = get<0> (ProcessRunner{"uname"}.Run (String {})).Trim ();
126 * \endcode
127 *
128 * \par Example Usage
129 * \code
130 * ProcessRunner pr{"echo hi mom"};
131 * auto [stdOutStr, stdErrStr] = pr.Run ("");
132 * EXPECT_EQ (stdOutStr.Trim (), "hi mom");
133 * EXPECT_EQ (stdErrStr, "");
134 * \endcode
135 *
136 * \par Example Usage
137 * \code
138 * ProcessRunner pr{"cat"};
139 * Memory::BLOB kData_{ Memory::BLOB::FromRaw ("this is a test") };
140 * Streams::MemoryStream::Ptr<byte> processStdIn = Streams::MemoryStream::New<byte> (kData_ );
141 * Streams::MemoryStream::Ptr<byte> processStdOut = Streams::MemoryStream::New<byte> ();
142 * pr.Run (processStdIn, processStdOut).ThrowIfFailed ();
143 * EXPECT_EQ (processStdOut.ReadAll (), kData_);
144 * \endcode
145 *
146 */
148 public:
149 static constexpr CommandLine::WrapInShell kDefaultShell =
150#if qStroika_Foundation_Common_Platform_Windows
151 CommandLine::WrapInShell::eWindowsCMD
152#else
153 CommandLine::WrapInShell::eBash
154#endif
155 ;
156
157 public:
158 /**
159 */
160 struct Options {
161 /**
162 * \brief pwd/cwd of the created process
163 * defaults to 'missing'. If missing, then WellKnownDirectories::GetTemporary () is
164 * used (since this is a generally safe place to run an executable); use filesystem::current_path () if that is the intention.
165 */
166 optional<filesystem::path> fWorkingDirectory;
167
168 /**
169 * If provided, child executed with this replacing its 'environment'; Variant 'Sequence<path>' means just the PATH part replaced.
170 * If Mapping<String,...> converted to SDKString codepage, and if SDKString provided, used as-is.
171 */
172 optional<variant<Sequence<filesystem::path>, Mapping<String, String>, Mapping<Characters::SDKString, Characters::SDKString>>> fEnvironment;
173
174 /**
175 * If true, then any nullptr input / output pipes are replaced with /dev/null (or equivalent)
176 * And any 'terminal' associated with the calling process is eliminated from the child
177 * process.
178 *
179 * Case POSIX:
180 * This also detaches from the terminal driver, to avoid spurious SIGHUP
181 * and SIGTTIN and SIGTTOU (setsid);
182 *
183 * Case Windoze:
184 * From: https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
185 * DETACHED_PROCESS - the new process does not inherit its parent's console
186 * This flag is ignored if the application is not a console application, or if it is used with either CREATE_NEW_CONSOLE or DETACHED_PROCESS
187 *
188 * \note replaces the Stroika v2.1 DetachedProcessRunner API
189 */
190 optional<bool> fDetached;
191
192#if qStroika_Foundation_Common_Platform_POSIX
193 /**
194 * \brief set umask of child process
195 *
196 * mostly harmless, not clearly needed, but suggested in http://codingfreak.blogspot.com/2012/03/daemon-izing-process-in-linux.html
197 */
198 optional<mode_t> fChildUMask{027};
199#endif
200
201#if qStroika_Foundation_Common_Platform_Windows
202 /**
203 * From: https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
204 * CONSOLE handle from this app not passed to child process. Obviates fDetachConsole.
205 */
206 bool fCreateNoWindow : 1 {true};
207
208#endif
209 };
210
211 public:
212 /**
213 * \brief Construct ProcessRunner with a CommandLine to run (doesn't actually RUN til you call Run or RunInBackground).
214 *
215 * \note overload with executable allows specifying an alternate executable to run, even though args[0] will be what is reported
216 * to that application (a somewhat common trick in unix-land).
217 *
218 * \note overload with String commandLine:
219 * Simple commands are run directly, and strings with apparent shell-isms, like pipes and quotes etc, are run through kDefaultShell.
220 * This overload is handy, but easy to explicitly control shell used with CommandLine argument instead.
221 */
222 ProcessRunner () = delete;
223 ProcessRunner (const ProcessRunner&) = delete;
224
225#if qCompilerAndStdLib_DefaultMemberInitializerNeededEnclosingForDefaultFunArg_Buggy
226 ProcessRunner (const filesystem::path& executable, const CommandLine& args);
227 ProcessRunner (const CommandLine& args);
228 ProcessRunner (const String& commandLine);
229 ProcessRunner (const filesystem::path& executable, const CommandLine& args, const Options& o);
230 ProcessRunner (const CommandLine& args, const Options& o);
231 ProcessRunner (const String& commandLine, const Options& o);
232#else
233 ProcessRunner (const filesystem::path& executable, const CommandLine& args, const Options& o = {});
234 ProcessRunner (const CommandLine& args, const Options& o = {});
235 ProcessRunner (const String& commandLine, const Options& o = {});
236#endif
237
238 public:
239 nonvirtual ProcessRunner& operator= (const ProcessRunner&) = delete;
240
241 public:
242#if qStroika_Foundation_Common_Platform_POSIX
243 using ExitStatusType = uint8_t;
244#elif qStroika_Foundation_Common_Platform_Windows
245 using ExitStatusType = DWORD;
246#else
247 using ExitStatusType = int;
248#endif
249
250 public:
251 class Exception;
252
253 public:
254 /**
255 */
256 nonvirtual CommandLine GetCommandLine () const;
257 nonvirtual void SetCommandLine (const CommandLine& args);
258
259 public:
260 /**
261 */
262 nonvirtual Options GetOptions () const;
263 nonvirtual void SetOptions (const Options& o);
264
265 public:
266 /**
267 * Zero means success. Run() returns optional<ProcessResultType> by reference, and that
268 * value is only provided if the child process exited. If exited, we return the exit
269 * status and signal number (if any) - see waitpid - http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html
270 */
271 struct [[nodiscard]] ProcessResultType {
272 optional<ExitStatusType> fExitStatus;
273 optional<SignalID> fTerminatedByUncaughtSignalNumber;
274
275 void ThrowIfFailed ();
276 };
277
278 public:
279 /**
280 * \brief Run () options for mapping Strings - what code page converters to use.
281 *
282 * \note defaults now are UTF-8, but don't count on this if you care about the encoding used (subject to change).
283 */
285 /**
286 * Input refers to the input of the sub-process being run. So this conversion is applied before sending the data to
287 * that process.
288 */
289 optional<Characters::CodeCvt<>> fInputCodeCvt;
290
291 /**
292 * Output refers to the output of the sub-process being run. So this conversion is applied to the data retrieved
293 * from that process.
294 */
295 optional<Characters::CodeCvt<>> fOutputCodeCvt;
296 };
297
298 public:
299 /**
300 * \brief Run the given external command/process (set by constructor) - with the given arguments, and block until that completes and return the results
301 *
302 * Run the given external command/process (set by constructor) - with the given arguments, and block until
303 * that completes and return the results.
304 *
305 * Run STREAMS overload:
306 * This overload takes input/output/error binary streams
307 *
308 * STDIN/STDOUT/STDERR:
309 * * If nullptr/not specified, will redirected to /dev/null
310 *
311 * Run STRING overload:
312 * This is the simplest API. Just pass in a string, and get back a string (first one is stdout, second is stderr).
313 *
314 * The cmdStdInValue is passed as stdin (stream) to the subprocess.
315 *
316 * Run ()/0:
317 * Treat as Run("") - so stderr captured automatically and inserted into exception (and logged).
318 *
319 * BOTH overloads will throw if there is any sort of error, including error exit from the process called.
320 * Use RunInBackground () to examine the results of the sub-process.
321 *
322 * \note Exceptions:
323 * A number of issues before the process is run will generate an exception.
324 * If the argument processResult is null, failure (non SUCCESS exit or signal termination) will trigger an exception, and otherwise the
325 * parameter *processResult will be filled in.
326 *
327 * \note if this is called with a timeout, and it times out, the child is killed immediately upon timeout.
328 * To avoid this behavior, use RunInBackground
329 *
330 * \par Example Usage (using strings in/out)
331 * \code
332 * String name = get<0> (ProcessRunner{"uname"}.Run (String {})).Trim ();
333 * \endcode
334 *
335 * \par Example Usage (using binary streams)
336 * \code
337 * ProcessRunner pr{"cat"};
338 * Memory::BLOB kData_{ Memory::BLOB::FromRaw ("this is a test") };
339 * Streams::MemoryStream::Ptr<byte> processStdIn = Streams::MemoryStream::New<byte> (kData_);
340 * Streams::MemoryStream::Ptr<byte> processStdOut = Streams::MemoryStream::New<byte> ();
341 * pr.Run (processStdIn, processStdOut);
342 * EXPECT_EQ (processStdOut.ReadAll (), kData_);
343 * \endcode
344 *
345 * @see RunInBackground
346 */
347 nonvirtual void Run (const Streams::InputStream::Ptr<byte>& in, const Streams::OutputStream::Ptr<byte>& out = nullptr,
348 const Streams::OutputStream::Ptr<byte>& error = nullptr, ProgressMonitor::Updater progress = nullptr,
349 Time::DurationSeconds timeout = Time::kInfinity);
350 nonvirtual tuple<Characters::String, Characters::String> Run (const Characters::String& cmdStdInValue = ""sv,
351 const StringOptions& stringOpts = {}, ProgressMonitor::Updater progress = nullptr,
352 Time::DurationSeconds timeout = Time::kInfinity);
353
354 public:
355 class BackgroundProcess;
356
357 public:
358 /**
359 * \brief Run the given external command/process (set by constructor) - with the given arguments in the background,
360 * and return a handle to the results.
361 *
362 * This function is generally quick, and non-blocking - just creates a thread todo the work.
363 *
364 * \note it is perfectly legal to launch a subprocess, and not track it in any way, just ignoring (not saving)
365 * the BackgroundProcess object.
366 *
367 * @see Run
368 */
370 const Streams::OutputStream::Ptr<byte>& out = nullptr,
371 const Streams::OutputStream::Ptr<byte>& error = nullptr,
372 ProgressMonitor::Updater progress = nullptr);
373
374 private:
375 /**
376 * Note that 'in' will be sent to the stdin of the subprocess, 'out' will be read from the
377 * stdout of the subprocess and error will be read from the stderr of the subprocess.
378 *
379 * Each of these CAN be null, and will if so, that will be interpreted as an empty stream
380 * (for in/stdin), and for out/error, just means the results will be redirected to /dev/null.
381 */
382 nonvirtual function<void ()> CreateRunnable_ (Synchronized<optional<ProcessResultType>>* processResult,
383 Synchronized<optional<pid_t>>* runningPID, ProgressMonitor::Updater progress);
384
385 private:
386 optional<filesystem::path> fExecutable_; // if omitted, derived from fArgs[0]
387 CommandLine fArgs_;
388 Options fOptions_;
389 Streams::InputStream::Ptr<byte> fStdIn_; // just while we support deprecated API
392 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
393
394 public:
395 [[deprecated ("Since Stroika v3.0d12 - pass stdin/stdout/stderr to ProcessRunner Run() method (if needed)")]] ProcessRunner (
396 const filesystem::path& executable, const CommandLine& args, const Streams::InputStream::Ptr<byte>& in,
397 const Streams::OutputStream::Ptr<byte>& out = nullptr, const Streams::OutputStream::Ptr<byte>& error = nullptr);
398 [[deprecated ("Since Stroika v3.0d12 - pass stdin/stdout/stderr to ProcessRunner Run() method (if needed)")]] ProcessRunner (
399 const CommandLine& args, const Streams::InputStream::Ptr<byte>& in, const Streams::OutputStream::Ptr<byte>& out = nullptr,
400 const Streams::OutputStream::Ptr<byte>& error = nullptr);
401 [[deprecated ("Since Stroika v3.0d12 - pass stdin/stdout/stderr to ProcessRunner Run() method (if needed)")]] ProcessRunner (
402 const String& commandLine, const Streams::InputStream::Ptr<byte>& in, const Streams::OutputStream::Ptr<byte>& out = nullptr,
403 const Streams::OutputStream::Ptr<byte>& error = nullptr)
404 : ProcessRunner{commandLine}
405 {
406 this->fStdIn_ = in;
407 this->fStdOut_ = out;
408 this->fStdErr_ = error;
409 }
410
411 [[deprecated ("Since Stroika v3.0d12 - use other overloads for ProcessRunner")]] ProcessRunner (
412 const filesystem::path& executable, const Containers::Sequence<String>& args, const Streams::InputStream::Ptr<byte>& in = nullptr,
413 const Streams::OutputStream::Ptr<byte>& out = nullptr, const Streams::OutputStream::Ptr<byte>& error = nullptr)
414 : ProcessRunner{executable, CommandLine{args}}
415 {
416 this->fStdIn_ = in;
417 this->fStdOut_ = out;
418 this->fStdErr_ = error;
419 }
420
421 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
422 Run (optional<ProcessResultType>* processResult, ProgressMonitor::Updater progress = nullptr, Time::DurationSeconds timeout = Time::kInfinity);
423
424 [[deprecated ("Since Stroika v3.0d12 pass in/out/error(can be nullptr) in RunInbackground() method")]] BackgroundProcess
425 RunInBackground (ProgressMonitor::Updater progress);
426
427 public:
428 /**
429 */
430 [[deprecated ("Since Stroika v3.0d12 - use GetOptions().fWorkingDirectory")]] optional<filesystem::path> GetWorkingDirectory () const;
431 [[deprecated ("Since Stroika v3.0d12 - use SetOptions({.fWorkingDirectory})")]] void SetWorkingDirectory (const optional<filesystem::path>& d);
432
433 public:
434 /**
435 * If empty, stdin will not be empty (redirected from /dev/null).
436 *
437 * Otherwise, the stream will be 'read' by the ProcessRunner and 'fed' downstream to
438 * the running subprocess.
439 */
440 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] Streams::InputStream::Ptr<byte>
441 GetStdIn () const;
442 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
443 SetStdIn (const Streams::InputStream::Ptr<byte>& in);
444
445 public:
446 /**
447 * If empty, stdout will not be captured (redirected to /dev/null)
448 */
449 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] Streams::OutputStream::Ptr<byte>
450 GetStdOut () const;
451 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
452 SetStdOut (const Streams::OutputStream::Ptr<byte>& out);
453
454 public:
455 /**
456 * If empty, stderr will not be captured (redirected to /dev/null)
457 */
458 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] Streams::OutputStream::Ptr<byte>
459 GetStdErr () const;
460 [[deprecated ("Since Stroika v3.0d12 - pass in/out/error streams(can be nullptr) to Run method instead of CTOR")]] void
461 SetStdErr (const Streams::OutputStream::Ptr<byte>& err);
462 };
463
464 /**
465 * Exceptions generated by ProcessRunner are typically of this sort.
466 */
468 private:
470
471 public:
472 /**
473 */
474 Exception (const String& failureMessage, const optional<String>& stderrFragment = nullopt,
475 const optional<ExitStatusType>& wExitStatus = nullopt, const optional<SignalID>& wTermSig = nullopt);
476
477 public:
478 /**
479 * High level summary - not including stuff like exit status, stderr results etc
480 */
482
483 public:
484 const optional<String> fStderrFragment;
485
486 public:
487 const optional<ExitStatusType> fExitStatus;
488
489 public:
490 const optional<SignalID> fTermSignal;
491
492 private:
493 static String mkMsg_ (const String& errorMessage, const optional<String>& stderrSubset, const optional<ExitStatusType>& wExitStatus,
494 const optional<SignalID>& wTermSig);
495 };
496
497 /**
498 * Support more controlled running of sub-process, where wait timeouts don't necessarily kill the child process.
499 *
500 * \note it is perfectly legal to launch a subprocess, and not track it in any way, just ignoring (not saving)
501 * the BackgroundProcess object.
502 */
504 private:
506
507 public:
508 BackgroundProcess (const BackgroundProcess&) = default;
509
510 public:
511 /**
512 * Return missing if process still running, and if completed, return the results.
513 */
514 nonvirtual optional<ProcessResultType> GetProcessResult () const;
515
516 public:
517 /**
518 * \brief maybe missing if process not yet (or ever successfully) launched. Child process may have
519 * already exited by the time this is returned.
520 */
521 optional<pid_t> GetChildProcessID () const;
522
523 public:
524 /**
525 * \brief wait until GetChildProcessID () returns a valid answer, or until the process failed to start
526 * (in which case calls PropagateIfException).
527 */
528 nonvirtual void WaitForStarted (Time::DurationSeconds timeout = Time::kInfinity) const;
529
530 public:
531 /**
532 *
533 * @see Join ()
534 * @see JoinUntil ()
535 */
536 nonvirtual void WaitForDone (Time::DurationSeconds timeout = Time::kInfinity) const;
537
538 public:
539 /**
540 * \brief Join () does WaitForDone () and throw exception if there was any error (see PropagateIfException).
541 *
542 * \note Aliases - this used to be called WaitForDoneAndPropagateErrors; but used the name Join () to mimic the name used with Threads - NOT
543 * because that's used in the implementation, but because its essentially logically the same thing.
544 *
545 * @see JoinUntil ()
546 * @see WaitForDone ()
547 */
548 nonvirtual void Join (Time::DurationSeconds timeout = Time::kInfinity) const;
549
550 public:
551 /**
552 * \brief WaitForDoneUntil () and throw exception if there was any error (see PropagateIfException).
553 *
554 * @see Join ()
555 * @see WaitForDone ()
556 */
557 nonvirtual void JoinUntil (Time::TimePointSeconds timeoutAt) const;
558
559 public:
560 /**
561 * If the process has completed with an error, throw exception reflecting that failure.
562 *
563 * \note if the process has not completed, this likely does nothing.
564 */
565 nonvirtual void PropagateIfException () const;
566
567 public:
568 /**
569 * If the process is still running, terminate it.
570 */
571 nonvirtual void Terminate ();
572
573 private:
574 struct Rep_ {
575 virtual ~Rep_ () = default;
576 Thread::CleanupPtr fProcessRunner{Thread::CleanupPtr::eAbortBeforeWaiting};
579 };
580 shared_ptr<Rep_> fRep_;
581 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
582
583 private:
584 friend class ProcessRunner;
585 };
586
587}
588
589/*
590 ********************************************************************************
591 ***************************** Implementation Details ***************************
592 ********************************************************************************
593 */
594#include "ProcessRunner.inl"
595
596#endif /*_Stroika_Foundation_Execution_ProcessRunner_h_*/
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
nonvirtual void WaitForStarted(Time::DurationSeconds timeout=Time::kInfinity) const
wait until GetChildProcessID () returns a valid answer, or until the process failed to start (in whic...
nonvirtual optional< ProcessResultType > GetProcessResult() const
nonvirtual void WaitForDone(Time::DurationSeconds timeout=Time::kInfinity) const
nonvirtual void Join(Time::DurationSeconds timeout=Time::kInfinity) const
Join () does WaitForDone () and throw exception if there was any error (see PropagateIfException).
nonvirtual void JoinUntil(Time::TimePointSeconds timeoutAt) const
WaitForDoneUntil () and throw exception if there was any error (see PropagateIfException).
optional< pid_t > GetChildProcessID() const
maybe missing if process not yet (or ever successfully) launched. Child process may have already exit...
Run the given command, and optionally support stdin/stdout/stderr as streams (either sync with Run,...
nonvirtual void Run(const Streams::InputStream::Ptr< byte > &in, const Streams::OutputStream::Ptr< byte > &out=nullptr, const Streams::OutputStream::Ptr< byte > &error=nullptr, ProgressMonitor::Updater progress=nullptr, Time::DurationSeconds timeout=Time::kInfinity)
Run the given external command/process (set by constructor) - with the given arguments,...
Streams::InputStream::Ptr< byte > GetStdIn() const
Streams::OutputStream::Ptr< byte > GetStdOut() const
nonvirtual BackgroundProcess RunInBackground(const Streams::InputStream::Ptr< byte > &in=nullptr, const Streams::OutputStream::Ptr< byte > &out=nullptr, const Streams::OutputStream::Ptr< byte > &error=nullptr, ProgressMonitor::Updater progress=nullptr)
Run the given external command/process (set by constructor) - with the given arguments in the backgro...
ProcessRunner()=delete
Construct ProcessRunner with a CommandLine to run (doesn't actually RUN til you call Run or RunInBack...
Streams::OutputStream::Ptr< byte > GetStdErr() const
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
Run () options for mapping Strings - what code page converters to use.