5#include "../Common/CompilerMacrosExport.h"
6#ifndef SC_EXPORT_LIBRARY_PROCESS
7#define SC_EXPORT_LIBRARY_PROCESS 0
9#define SC_PROCESS_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_PROCESS)
11#include "../Common/AlignedStorage.h"
12#include "../Common/Assert.h"
13#include "../Common/IGrowableBufferSpan.h"
14#include "../Common/IGrowableBufferStringPath.h"
15#include "../File/File.h"
19SC_DECLARE_ASSERT_PROVIDER(ProcessAssert, SC_PROCESS_EXPORT);
21#define SC_PROCESS_ASSERT_RELEASE(e) SC_ASSERT_PROVIDER_RELEASE(SC::ProcessAssert, e)
22#define SC_PROCESS_ASSERT_DEBUG(e) SC_ASSERT_PROVIDER_DEBUG(SC::ProcessAssert, e)
23#define SC_PROCESS_TRUST_RESULT(expression) SC_PROCESS_ASSERT_RELEASE(expression)
25struct SC_PROCESS_EXPORT ProcessChain;
29 using Handle = detail::FileDescriptorDefinition::Handle;
30 static constexpr auto Invalid = detail::FileDescriptorDefinition::Invalid;
86 static constexpr size_t InlineCommandStorageCapacity = StringPath::MaxPath + 1024;
99 growableBuffer = &destination;
100 operation = Operation::GrowableBuffer;
106 operation = Operation::FileDescriptor;
107 (void)file.content.get(fileDescriptor, Result::Error(
"Invalid redirection file descriptor"));
108 file.content.detach();
111 StdStream(GrowableBuffer<PipeDescriptor>& pipe)
113 operation = Operation::ExternalPipe;
114 pipeDescriptor = &pipe.content;
117 StdStream(
const StdStream&) =
delete;
118 StdStream(StdStream&&) =
delete;
119 StdStream& operator=(
const StdStream&) =
delete;
120 StdStream& operator=(StdStream&&) =
delete;
142 Operation operation = Operation::Inherit;
144 Span<const char> readableSpan;
145 Span<char>* writableSpan =
nullptr;
147 IGrowableBuffer* growableBuffer =
nullptr;
149 FileDescriptor::Handle fileDescriptor;
162 StdOut(GrowableBuffer<StdOut::Ignore>) { operation = Operation::Ignore; }
165 StdOut(GrowableBuffer<StdOut::Inherit>) { operation = Operation::Inherit; }
166 StdOut(GrowableBuffer<StdOut>) { operation = Operation::Inherit; }
167 StdOut() { operation = Operation::Inherit; }
170 StdOut(GrowableBuffer<Span<char>>& span) { operation = Operation::WritableSpan; writableSpan = &span.content; span.setContentInDestructor =
false; }
172 using StdStream::StdStream;
177 using StdErr = StdOut;
185 StdIn(GrowableBuffer<Inherit>) { operation = Operation::Inherit; }
186 StdIn(GrowableBuffer<StdIn>) { operation = Operation::Inherit; }
187 StdIn() { operation = Operation::Inherit; }
190 template <
int N>
StdIn(GrowableBuffer<
const char [N]>& item) { operation = Operation::ReadableSpan; readableSpan = {item.content, N - 1}; }
193 StdIn(GrowableBuffer<StringSpan>
string) { operation = Operation::ReadableSpan; readableSpan =
string.content.toCharSpan();}
196 StdIn(GrowableBuffer<Span<const char>> span) { operation = Operation::ReadableSpan; readableSpan = span.content;}
198 using StdStream::StdStream;
206 ProcessDescriptor::Handle handle = ProcessDescriptor::Invalid;
218 template <
typename Out = StdOut,
typename In = StdIn,
typename Err = StdErr>
219 Result
launch(Span<const StringSpan> cmd, Out&& stdOut = Out(), In&& stdIn = In(), Err&& stdErr = Err())
221 SC_TRY(formatArguments(cmd));
222 GrowableBuffer<typename TypeTraits::RemoveReference<Out>::type> gbOut = {stdOut};
223 GrowableBuffer<typename TypeTraits::RemoveReference<In>::type> gbIn = {stdIn};
224 GrowableBuffer<typename TypeTraits::RemoveReference<Err>::type> gbErr = {stdErr};
235 template <
typename Out = StdOut,
typename In = StdIn,
typename Err = StdErr>
236 Result
exec(Span<const StringSpan> cmd, Out&& stdOut = Out(), In&& stdIn = In(), Err&& stdErr = Err())
238 SC_TRY(launch(cmd, stdOut, stdIn, stdErr));
239 return waitForExitSync();
266 Process(Span<native_char_t> commandMemory = {}, Span<native_char_t> environmentMemory = {})
267 : command({commandMemory}), environment({environmentMemory})
269 if (commandMemory.empty())
270 command = {commandStorage};
271 if (environmentMemory.empty())
272 environment = {environmentStorage};
276 ProcessExitStatus exitStatus;
278 FileDescriptor stdInFd;
279 FileDescriptor stdOutFd;
280 FileDescriptor stdErrFd;
282 Result launch(
const StdOut& stdOutput,
const StdIn& stdInput,
const StdErr& stdError);
284 Result formatArguments(Span<const StringSpan> cmd);
286 StringPath currentDirectory;
287#if SC_PLATFORM_WINDOWS
288 StringPath executablePathForLaunch;
289 bool executablePathLooksLikeFile =
false;
296 native_char_t commandStorage[InlineCommandStorageCapacity];
297 StringSpan::NativeWritable command;
298#if !SC_PLATFORM_WINDOWS
299 static constexpr size_t MAX_NUM_ARGUMENTS = 64;
300 size_t commandArgumentsByteOffset[MAX_NUM_ARGUMENTS];
301 size_t commandArgumentsNumber = 0;
304 native_char_t environmentStorage[4096 * 8];
305 StringSpan::NativeWritable environment;
307 static constexpr size_t MAX_NUM_ENVIRONMENT = 256;
309 size_t environmentByteOffset[MAX_NUM_ENVIRONMENT];
310 size_t environmentNumber = 0;
312 bool inheritEnv =
true;
314 friend struct ProcessChain;
315 ProcessChain* parent =
nullptr;
317 Process* next =
nullptr;
318 Process* prev =
nullptr;
321 friend struct ProcessFork;
322 Result launchImplementation();
323 Result launchForkChild(PipeDescriptor& pipe);
324 Result launchForkParent(PipeDescriptor& pipe,
const void* previousSignals);
355 template <
typename Out = Process::StdOut,
typename In = Process::StdIn,
typename Err = Process::StdErr>
356 Result
launch(Out&& stdOut = Out(), In&& stdIn = In(), Err&& stdErr = Err())
358 GrowableBuffer<typename TypeTraits::RemoveReference<Out>::type> gbOut = {stdOut};
359 GrowableBuffer<typename TypeTraits::RemoveReference<In>::type> gbIn = {stdIn};
360 GrowableBuffer<typename TypeTraits::RemoveReference<Err>::type> gbErr = {stdErr};
361 return internalLaunch(gbOut, gbIn, gbErr);
370 template <
typename Out = Process::StdOut,
typename In = Process::StdIn,
typename Err = Process::StdErr>
371 Result
exec(Out&& stdOut = Out(), In&& stdIn = In(), Err&& stdErr = Err())
373 SC_TRY(launch(stdOut, stdIn, stdErr));
374 return waitForExitSync();
380 struct ProcessLinkedList
385 [[nodiscard]]
bool isEmpty()
const {
return front ==
nullptr; }
388 void queueBack(Process& process);
390 ProcessLinkedList processes;
408 [[nodiscard]]
size_t size()
const {
return numberOfEnvironment; }
414 [[nodiscard]]
bool get(
size_t index, StringSpan& name, StringSpan& value)
const;
420 [[nodiscard]]
bool contains(StringSpan variableName,
size_t* index =
nullptr)
const;
426 [[nodiscard]]
bool get(StringSpan variableName, StringSpan& value)
const;
429 size_t numberOfEnvironment = 0;
430#if SC_PLATFORM_WINDOWS
431 static constexpr size_t MAX_ENVIRONMENTS = 256;
433 StringSpan envStrings[MAX_ENVIRONMENTS];
434 wchar_t* environment =
nullptr;
436 char** environment =
nullptr;
506 Side side = ForkParent;
507#if SC_PLATFORM_WINDOWS
508 ProcessDescriptor::Handle processHandle = ProcessDescriptor::Invalid;
509 ProcessDescriptor::Handle threadHandle = ProcessDescriptor::Invalid;
[UniqueHandleDeclaration2Snippet]
Definition File.h:130
Read / Write pipe (Process stdin/stdout and IPC communication)
Definition File.h:302
Execute multiple child processes chaining input / output between them.
Definition Process.h:344
Result launch(Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Launch the entire chain of processes.
Definition Process.h:356
Result pipe(Process &process, const Span< const StringSpan > cmd)
Add a process to the chain, with given arguments.
Result exec(Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Launch the entire chain of processes and waits for the results (calling ProcessChain::waitForExitSync...
Definition Process.h:371
Result waitForExitSync()
Waits (blocking) for entire process chain to exit.
Reads current process environment variables.
Definition Process.h:398
bool get(size_t index, StringSpan &name, StringSpan &value) const
Get the environment variable at given index, returning its name and value.
bool get(StringSpan variableName, StringSpan &value) const
Gets the value of an environment variable from current process.
size_t size() const
Returns the total number of environment variables for current process.
Definition Process.h:408
bool contains(StringSpan variableName, size_t *index=nullptr) const
Checks if an environment variable exists in current process.
Wraps the code returned by a process that has exited.
Definition Process.h:35
Forks current process exiting child at end of process A fork duplicates a parent process execution st...
Definition Process.h:466
Result waitForChild()
Waits for child fork to finish execution.
State
Definition Process.h:482
@ Suspended
Start the forked process suspended (resume it with ProcessFork::resumeChildFork)
Definition Process.h:483
@ Immediate
Start the forked process immediately.
Definition Process.h:484
Side getSide() const
Obtain process parent / fork side.
Definition Process.h:479
FileDescriptor & getWritePipe()
Gets the descriptor to "write" something to the other side.
Side
Definition Process.h:473
@ ForkParent
Parent side of the fork.
Definition Process.h:474
@ ForkChild
Child side of the fork.
Definition Process.h:475
Result resumeChildFork()
Sends 1 byte on parentToFork to resume State::Paused child fork.
FileDescriptor & getReadPipe()
Gets the descriptor to "read" something from the other side.
Result fork(State state)
Forks current process (use ForkProcess::getType to know the side)
int32_t getExitStatus() const
Gets the return code from the exited child fork.
Definition Process.h:497
Native os handle to a process identifier.
Definition Process.h:47
bool windowsHide
[Windows] Hides child process window (default == Process::isWindowsConsoleSubsystem)
Definition Process.h:90
StdIn(GrowableBuffer< Span< const char > > span)
Fills standard input with content of a Span.
Definition Process.h:196
StdIn(GrowableBuffer< Inherit >)
Inherits child process Input from parent process.
Definition Process.h:185
StdIn(GrowableBuffer< const char[N]> &item)
Fills standard input with content of a C-String.
Definition Process.h:190
StdIn(GrowableBuffer< StringSpan > string)
Fills standard input with content of a StringSpan.
Definition Process.h:193
StdOut(GrowableBuffer< Span< char > > &span)
Read the process standard output/error into the given Span.
Definition Process.h:170
StdOut(GrowableBuffer< StdOut::Inherit >)
Inherits child process standard output/error (child process will print into parent process console)
Definition Process.h:165
StdOut(GrowableBuffer< StdOut::Ignore >)
Ignores child process standard output/error (child process output will be silenced)
Definition Process.h:162
StdStream(GrowableBuffer< FileDescriptor > &file)
Redirects child process standard output/error to a given file descriptor.
Definition Process.h:104
StdStream(IGrowableBuffer &destination)
Read the process standard output/error into the given String / Buffer.
Definition Process.h:97
Execute a child process with standard file descriptors redirection.
Definition Process.h:85
int32_t getExitStatus() const
gets the return code from the exited child process (valid only after exec or waitForExitSync)
Definition Process.h:243
Result exec(Span< const StringSpan > cmd, Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Executes a child process with the given arguments, waiting (blocking) until it's fully finished.
Definition Process.h:236
Result setEnvironment(StringSpan environmentVariable, StringSpan value)
Sets the environment variable for the newly spawned child process.
Process(Span< native_char_t > commandMemory={}, Span< native_char_t > environmentMemory={})
Constructs a Process object passing (optional) memory storage for command and environment variables.
Definition Process.h:266
Options options
Options for the child process (hide console window etc.)
Definition Process.h:204
static bool isWindowsEmulatedProcess()
Returns true if we're emulating x64 on ARM64 or the inverse on Windows.
void inheritParentEnvironmentVariables(bool inherit)
Controls if the newly spawned child process will inherit parent process environment variables.
Definition Process.h:249
ProcessID processID
ID of the process (can be the same as handle on Posix)
Definition Process.h:203
static bool isWindowsConsoleSubsystem()
Returns true only under Windows if executable is compiled with /SUBSYSTEM:Console
Result launch(Span< const StringSpan > cmd, Out &&stdOut=Out(), In &&stdIn=In(), Err &&stdErr=Err())
Launch child process with the given arguments.
Definition Process.h:219
static size_t getNumberOfProcessors()
Returns number of (virtual) processors available.
Result setWorkingDirectory(StringSpan processWorkingDirectory)
Sets the starting working directory of the process that will be launched / executed.
Result waitForExitSync()
Waits (blocking) for process to exit after launch. It can only be called if Process::launch succeeded...