124 lines
3.5 KiB
Plaintext
Raw Normal View History

2025-01-12 20:41:24 +08:00
[section:quickstart Quickstart]
A process needs four things to be launched:
* an asio execution_context / executor
* a path to an executable
* a list of arguments
* a variadic set of initializers
```
// process(asio::any_io_executor, filesystem::path, range<string> args, AdditionalInitializers...)
asio::io_context ctx;
process proc(ctx, "/usr/bin/cp", {"source.txt", "target.txt"});
```
The started process can then be awaited or terminated.
[section:lifetime Lifetime]
If the process handle goes out of scope, it will terminate the subprocess.
You can prevent this, by calling `proc.detach()`; do however note that this
can lead to zombie processes.
A process that completed will deliver an exit-code,
which can be obtained by calling `.exit_code` on the exited process and which is
also returned from `.wait()`.
```
process proc("/bin/ls", {});
assert(proc.wait() == 0);
```
The normal exit-code is what the subprocess returned from `main`;
posix will however add additional information about the process.
This is called the `native_exit_code`.
The `.running()` function can be used to detect if the process is still active.
[endsect]
[section:signal Signalling the subprocess]
The parent process can signal the subprocess demanding certain actions.
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
This is the only reliable & portable way to end a subprocess.
```
process proc("/bin/totally-not-a-virus", {});
proc.terminate();
```
`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix),
which the subprocess might ignore.
```
process proc("/bin/bash", {});
proc.request_exit();
proc.wait();
```
`.interrupt` will send an SIGINT to the subprocess, which a subprocess might
interpret as a signal to shutdown.
[warning interrupt requires the initializer `windows::create_new_process_group` to be set]
```
process proc("/usr/bin/addr2line", {});
proc.request_exit();
proc.wait();
```
[endsect]
[section:execute Execute functions]
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
```
assert(execute(process("/bin/ls", {}) == 0));
```
The async version supports cancellation and will forward cancellation types as follows:
- asio::cancellation_type::total -> interrupt
- asio::cancellation_type::partial -> request_exit
- asio::cancellation_type::terminal -> terminate
```
asio::io_context ctx;
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
asio::cancellation_signal sig;
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
asio::bind_cancellation_slot(sig.slot(),
[&](error_code ec, int exit_code)
{
timeout.cancel(); // we're done earlier
}));
timeout.async_wait(
[&](error_code ec)
{
if (ec) // we were cancelled, do nothing
return ;
sig.emit(asio::cancellation_type::partial);
// request exit first, but terminate after another 10 sec
timeout.expires_after(std::chrono::seconds(10));
timeout.async_wait(
[&](error_code ec)
{
if (!ec)
sig.emit(asio::cancellation_type::terminal);
});
);
});
```
[endsect]
[endsect]