process-cpp: /build/process-cpp/src/process-cpp-3.0.1/tests/posix_process_test.cpp Source File

process-cpp 3.0.0 A simple convenience library for handling processes in C++11.

posix_process_test.cpp
Go to the documentation of this file.
1 /*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19 #include <core/posix/exec.h>
20 #include <core/posix/fork.h>
21 #include <core/posix/process.h>
22 #include <core/posix/signal.h>
23
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26
27 #include <chrono>
28 #include <map>
29 #include <thread>
30
31 namespace
32 {
33 ::testing::AssertionResult is_error(const std::error_code& ec)
34 {
35 return ec ? ::testing::AssertionResult{true} : ::testing::AssertionResult{false};
36 }
37
38 struct ForkedSpinningProcess : public ::testing::Test
39 {
40 void SetUp()
41 {
42 child = core::posix::fork(
43 []() { std::cout << "Child" << std::endl; while(true) {} return core::posix::exit::Status::failure;},
44 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
45 }
46
47 void TearDown()
48 {
49 }
50
51 core::posix::ChildProcess child = core::posix::ChildProcess::invalid();
52 };
53
54 struct Init
55 {
56 Init()
57 : signal_trap(
58 core::posix::trap_signals_for_all_subsequent_threads(
59 {core::posix::Signal::sig_chld})),
60 death_observer(
61 core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap(
62 signal_trap))
63 {
64 }
65
66 std::shared_ptr<core::posix::SignalTrap> signal_trap;
67 std::unique_ptr<core::posix::ChildProcess::DeathObserver> death_observer;
68 } init;
69
70 }
71
72 TEST(PosixProcess, ctor_throws_for_invalid_pid)
73 {
74 pid_t invalid_pid{-1};
75 EXPECT_ANY_THROW(core::posix::Process{invalid_pid});
76 }
77
78 TEST(PosixProcess, this_process_instance_reports_correct_pid)
79 {
80 EXPECT_EQ(getpid(), core::posix::this_process::instance().pid());
81 }
82
83 TEST(PosixProcess, this_process_instance_reports_correct_parent)
84 {
85 EXPECT_EQ(getppid(), core::posix::this_process::parent().pid());
86 }
87
88 TEST(PosixProcess, throwing_access_to_process_group_id_of_this_process_works)
89 {
90 EXPECT_EQ(getpgrp(), core::posix::this_process::instance().process_group_or_throw().id());
91 }
92
93 TEST(PosixProcess, non_throwing_access_to_process_group_id_of_this_process_works)
94 {
95 std::error_code se;
96 auto pg = core::posix::this_process::instance().process_group(se);
97 EXPECT_FALSE(is_error(se));
98 EXPECT_EQ(getpgrp(), pg.id());
99 }
100
101 TEST(PosixProcess, trying_to_access_process_group_of_invalid_process_throws)
102 {
103 EXPECT_ANY_THROW(core::posix::Process::invalid().process_group_or_throw());
104 }
105
106 TEST(PosixProcess, trying_to_access_process_group_of_invalid_process_reports_error)
107 {
108 std::error_code se;
109 core::posix::Process::invalid().process_group(se);
110 EXPECT_TRUE(is_error(se));
111 }
112
113 TEST_F(ForkedSpinningProcess, throwing_access_to_process_group_id_of_a_forked_process_works)
114 {
115 auto pg = child.process_group_or_throw();
116 EXPECT_EQ(getpgrp(), pg.id());
117 }
118
119 TEST_F(ForkedSpinningProcess, non_throwing_access_to_process_group_id_of_a_forked_process_works)
120 {
121 std::error_code se;
122 auto pg = child.process_group(se);
123
124 EXPECT_FALSE(se);
125 EXPECT_EQ(getpgrp(), pg.id());
126 }
127
128 TEST(PosixProcess, accessing_streams_of_this_process_works)
129 {
130 {
131 std::stringstream ss;
132 auto old = core::posix::this_process::cout().rdbuf(ss.rdbuf());
133 core::posix::this_process::cout() << "core::posix::this_process::instance().cout()\n";
134 EXPECT_EQ(ss.str(), "core::posix::this_process::instance().cout()\n");
135 core::posix::this_process::cout().rdbuf(old);
136 }
137
138 {
139 std::stringstream ss;
140 auto old = core::posix::this_process::cerr().rdbuf(ss.rdbuf());
141 core::posix::this_process::cerr() << "core::posix::this_process::instance().cerr()" << std::endl;
142 EXPECT_EQ(ss.str(), "core::posix::this_process::instance().cerr()\n");
143 core::posix::this_process::cerr().rdbuf(old);
144 }
145 }
146
147 TEST(Self, non_mutable_access_to_the_environment_returns_correct_results)
148 {
149 static const char* home = "HOME";
150 static const char* totally_not_existent = "totally_not_existent_42";
151 EXPECT_EQ(getenv("HOME"), core::posix::this_process::env::get(home));
152 EXPECT_EQ("", core::posix::this_process::env::get(totally_not_existent));
153 }
154
155 TEST(Self, mutable_access_to_the_environment_alters_the_environment)
156 {
157 static const char* totally_not_existent = "totally_not_existent_42";
158 static const char* totally_not_existent_value = "42";
159
160 EXPECT_EQ("", core::posix::this_process::env::get(totally_not_existent));
161 EXPECT_NO_THROW(core::posix::this_process::env::set_or_throw(
162 totally_not_existent,
163 totally_not_existent_value));
164 EXPECT_EQ(totally_not_existent_value,
165 core::posix::this_process::env::get(totally_not_existent));
166
167 EXPECT_NO_THROW(
168 core::posix::this_process::env::unset_or_throw(
169 totally_not_existent));
170 EXPECT_EQ("",
171 core::posix::this_process::env::get(totally_not_existent));
172 }
173
174 TEST(Self, getting_env_var_for_empty_key_does_not_throw)
175 {
176 EXPECT_NO_THROW(core::posix::this_process::env::get(""));
177 }
178
179 TEST(Self, setting_env_var_for_empty_key_throws)
180 {
181 EXPECT_ANY_THROW(core::posix::this_process::env::set_or_throw(
182 "",
183 "uninteresting"));
184 }
185
186 TEST(ChildProcess, fork_returns_process_object_with_valid_pid_and_wait_for_returns_correct_result)
187 {
188 core::posix::ChildProcess child = core::posix::fork(
189 []() { std::cout << "Child" << std::endl; return core::posix::exit::Status::success; },
190 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
191 EXPECT_TRUE(child.pid() > 0);
192
193 auto result = child.wait_for(core::posix::wait::Flags::untraced);
194 EXPECT_EQ(core::posix::wait::Result::Status::exited,
195 result.status);
196 EXPECT_EQ(core::posix::exit::Status::success,
197 result.detail.if_exited.status);
198
199 child = core::posix::fork(
200 []() { std::cout << "Child" << std::endl; return core::posix::exit::Status::failure; },
201 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
202 EXPECT_TRUE(child.pid() > 0);
203
204 result = child.wait_for(core::posix::wait::Flags::untraced);
205 EXPECT_EQ(core::posix::wait::Result::Status::exited,
206 result.status);
207 EXPECT_EQ(core::posix::exit::Status::failure,
208 result.detail.if_exited.status);
209 }
210
211 TEST_F(ForkedSpinningProcess, signalling_a_forked_child_makes_wait_for_return_correct_result)
212 {
213 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_kill));
214 auto result = child.wait_for(core::posix::wait::Flags::untraced);
215 EXPECT_EQ(core::posix::wait::Result::Status::signaled,
216 result.status);
217 EXPECT_EQ(core::posix::Signal::sig_kill,
218 result.detail.if_signaled.signal);
219
220 child = core::posix::fork(
221 []() { std::cout << "Child" << std::endl; while(true) {} return core::posix::exit::Status::failure;},
222 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
223 EXPECT_TRUE(child.pid() > 0);
224
225 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_term));
226 result = child.wait_for(core::posix::wait::Flags::untraced);
227 EXPECT_EQ(core::posix::wait::Result::Status::signaled,
228 result.status);
229 EXPECT_EQ(core::posix::Signal::sig_term,
230 result.detail.if_signaled.signal);
231 }
232
233 TEST(ChildProcess, stopping_a_forked_child_makes_wait_for_return_correct_result)
234 {
235 core::posix::ChildProcess child = core::posix::fork(
236 []()
237 {
238 std::string line;
239 while(true)
240 {
241 std::cin >> line;
242 std::cout << line << std::endl;
243 }
244 return core::posix::exit::Status::failure;
245 },
246 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
247 EXPECT_TRUE(child.pid() > 0);
248
249 const std::string echo_value{"42"};
250 child.cin() << echo_value << std::endl;
251 std::string line; child.cout() >> line;
252
253 EXPECT_EQ(echo_value, line);
254
255 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_stop));
256 auto result = child.wait_for(core::posix::wait::Flags::untraced);
257 EXPECT_EQ(core::posix::wait::Result::Status::stopped,
258 result.status);
259 EXPECT_EQ(core::posix::Signal::sig_stop,
260 result.detail.if_stopped.signal);
261
262 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_kill));
263 result = child.wait_for(core::posix::wait::Flags::untraced);
264 EXPECT_EQ(core::posix::wait::Result::Status::signaled,
265 result.status);
266 EXPECT_EQ(core::posix::Signal::sig_kill,
267 result.detail.if_signaled.signal);
268 }
269
270 TEST(ChildProcess, exec_returns_process_object_with_valid_pid_and_wait_for_returns_correct_result)
271 {
272 const std::string program{"/usr/bin/sleep"};
273 const std::vector<std::string> argv = {"10"};
274 std::map<std::string, std::string> env;
275 core::posix::this_process::env::for_each([&env](const std::string& key, const std::string& value)
276 {
277 env.insert(std::make_pair(key, value));
278 });
279
280 core::posix::ChildProcess child = core::posix::exec(program,
281 argv,
282 env,
283 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
284 EXPECT_TRUE(child.pid() > 0);
285 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_kill));
286 auto result = child.wait_for(core::posix::wait::Flags::untraced);
287 EXPECT_EQ(core::posix::wait::Result::Status::signaled,
288 result.status);
289 EXPECT_EQ(core::posix::Signal::sig_kill,
290 result.detail.if_signaled.signal);
291 }
292
293 TEST(ChildProcess, exec_child_setup)
294 {
295 const std::string program{"/usr/bin/sleep"};
296 const std::vector<std::string> argv = {"10"};
297 std::map<std::string, std::string> env;
298 std::function<void()> child_setup = []()
299 {
300 std::cout << "hello_there" << std::endl;
301 };
302
303 core::posix::ChildProcess child = core::posix::exec(program,
304 argv,
305 env,
306 core::posix::StandardStream::stdout,
307 child_setup);
308 EXPECT_TRUE(child.pid() > 0);
309 std::string output;
310 child.cout() >> output;
311 EXPECT_EQ("hello_there", output);
312 }
313
314 TEST(ChildProcess, signalling_an_execd_child_makes_wait_for_return_correct_result)
315 {
316 const std::string program{"/usr/bin/env"};
317 const std::vector<std::string> argv = {};
318 std::map<std::string, std::string> env;
319 core::posix::this_process::env::for_each([&env](const std::string& key, const std::string& value)
320 {
321 env.insert(std::make_pair(key, value));
322 });
323
324 core::posix::ChildProcess child = core::posix::exec(
325 program,
326 argv,
327 env,
328 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
329
330 EXPECT_TRUE(child.pid() > 0);
331
332 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_kill));
333 auto result = child.wait_for(core::posix::wait::Flags::untraced);
334 EXPECT_EQ(core::posix::wait::Result::Status::signaled,
335 result.status);
336 EXPECT_EQ(core::posix::Signal::sig_kill,
337 result.detail.if_signaled.signal);
338
339 child = core::posix::exec(program,
340 argv,
341 env,
342 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
343 EXPECT_TRUE(child.pid() > 0);
344
345 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_term));
346 result = child.wait_for(core::posix::wait::Flags::untraced);
347 EXPECT_EQ(core::posix::wait::Result::Status::signaled,
348 result.status);
349 EXPECT_EQ(core::posix::Signal::sig_term,
350 result.detail.if_signaled.signal);
351 }
352
353 TEST(ChildProcess, stopping_an_execd_child_makes_wait_for_return_correct_result)
354 {
355 const std::string program{"/usr/bin/sleep"};
356 const std::vector<std::string> argv = {"10"};
357 std::map<std::string, std::string> env;
358 core::posix::this_process::env::for_each([&env](const std::string& key, const std::string& value)
359 {
360 env.insert(std::make_pair(key, value));
361 });
362
363 core::posix::ChildProcess child = core::posix::exec(program,
364 argv,
365 env,
366 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
367 EXPECT_TRUE(child.pid() > 0);
368
369 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_stop));
370 auto result = child.wait_for(core::posix::wait::Flags::untraced);
371 EXPECT_EQ(core::posix::wait::Result::Status::stopped,
372 result.status);
373 EXPECT_EQ(core::posix::Signal::sig_stop,
374 result.detail.if_signaled.signal);
375 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_kill));
376 result = child.wait_for(core::posix::wait::Flags::untraced);
377 EXPECT_EQ(core::posix::wait::Result::Status::signaled,
378 result.status);
379 EXPECT_EQ(core::posix::Signal::sig_kill,
380 result.detail.if_signaled.signal);
381 }
382
383 namespace
384 {
385 struct ChildDeathObserverEventCollector
386 {
387 MOCK_METHOD1(on_child_died,void(const core::posix::Process&));
388 };
389 }
390
391 TEST_F(ForkedSpinningProcess, observing_child_processes_for_death_works_if_child_is_signalled_with_sigkill)
392 {
393 using namespace ::testing;
394
395 ChildDeathObserverEventCollector event_collector;
396
397 core::ScopedConnection sc
398 {
399 init.death_observer->child_died().connect([&event_collector](core::posix::ChildProcess cp)
400 {
401 event_collector.on_child_died(cp);
402 })
403 };
404
405 EXPECT_TRUE(init.death_observer->add(child));
406 EXPECT_CALL(event_collector, on_child_died(_))
407 .Times(1)
408 .WillOnce(
409 InvokeWithoutArgs(
410 init.signal_trap.get(),
411 &core::posix::SignalTrap::stop));
412
413 std::thread worker{[]() { init.signal_trap->run(); }};
414
415 child.send_signal_or_throw(core::posix::Signal::sig_kill);
416
417 if (worker.joinable())
418 worker.join();
419 }
420
421 TEST_F(ForkedSpinningProcess, observing_child_processes_for_death_works_if_child_is_signalled_with_sigterm)
422 {
423 using namespace ::testing;
424
425 ChildDeathObserverEventCollector signal_trap;
426
427 EXPECT_TRUE(init.death_observer->add(child));
428
429 core::ScopedConnection sc
430 {
431 init.death_observer->child_died().connect([&signal_trap](const core::posix::ChildProcess& child)
432 {
433 signal_trap.on_child_died(child);
434 })
435 };
436
437 EXPECT_CALL(signal_trap, on_child_died(_))
438 .Times(1)
439 .WillOnce(
440 InvokeWithoutArgs(
441 init.signal_trap.get(),
442 &core::posix::SignalTrap::stop));
443
444 std::thread worker{[]() { init.signal_trap->run(); }};
445
446 child.send_signal_or_throw(core::posix::Signal::sig_term);
447
448 if (worker.joinable())
449 worker.join();
450 }
451
452 TEST(ChildProcess, ensure_that_forked_children_are_cleaned_up)
453 {
454 static const unsigned int child_process_count = 100;
455 unsigned int counter = 1;
456
457 core::ScopedConnection sc
458 {
459 init.death_observer->child_died().connect([&counter](const core::posix::ChildProcess&)
460 {
461 counter++;
462
463 if (counter == child_process_count)
464 {
465 init.signal_trap->stop();
466 }
467 })
468 };
469
470 std::thread t([]() {init.signal_trap->run();});
471
472 for (unsigned int i = 0; i < child_process_count; i++)
473 {
474 auto child = core::posix::fork(
475 []() { return core::posix::exit::Status::success; },
476 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout);
477 init.death_observer->add(child);
478 // A bit ugly but we have to ensure that no signal is lost.
479 // And thus, we keep the process object alive.
480 std::this_thread::sleep_for(std::chrono::milliseconds{5});
481 }
482
483 if (t.joinable())
484 t.join();
485
486 EXPECT_EQ(child_process_count, counter);
487 }
488
489 TEST(StreamRedirect, redirecting_stdin_stdout_stderr_works)
490 {
491 core::posix::ChildProcess child = core::posix::fork(
492 []()
493 {
494 std::string line;
495 while(true)
496 {
497 std::cin >> line;
498 std::cout << line << std::endl;
499 std::cerr << line << std::endl;
500 }
501 return core::posix::exit::Status::failure;
502 },
503 core::posix::StandardStream::stdin | core::posix::StandardStream::stdout | core::posix::StandardStream::stderr);
504
505 ASSERT_TRUE(child.pid() > 0);
506
507 const std::string echo_value{"42"};
508 child.cin() << echo_value << std::endl;
509 std::string line;
510 EXPECT_NO_THROW(child.cout() >> line);
511 EXPECT_EQ(echo_value, line);
512 EXPECT_NO_THROW(child.cerr() >> line);
513 EXPECT_EQ(echo_value, line);
514 EXPECT_NO_THROW(child.send_signal_or_throw(core::posix::Signal::sig_kill));
515 child.wait_for(core::posix::wait::Flags::untraced);
516 }
517
518 TEST(Environment, iterating_the_environment_does_not_throw)
519 {
520 EXPECT_NO_THROW(core::posix::this_process::env::for_each(
521 [](const std::string& key, const std::string& value)
522 {
523 std::cout << key << " -> " << value << std::endl;
524 }););
525 }
526
527 TEST(Environment, specifying_default_value_for_get_returns_correct_result)
528 {
529 const std::string expected_value{"42"};
530 EXPECT_EQ(expected_value,
531 core::posix::this_process::env::get("totally_non_existant_key_in_env_blubb", expected_value));
532 }
533
534 TEST(Environment, for_each_returns_correct_results)
535 {
536 std::array<std::string, 3> env_keys = {"totally_non_existant_key_in_env_blubb0",
537 "totally_non_existant_key_in_env_blubb1",
538 "totally_non_existant_key_in_env_blubb2"};
539 std::array<std::string, 3> env_vars = {env_keys[0] + "=" + "hello",
540 env_keys[1] + "=" + "",
541 env_keys[2] + "=" + "string=hello"};
542 for( auto const& env_var : env_vars )
543 {
544 ::putenv(const_cast<char*>(env_var.c_str()));
545 }
546
547 core::posix::this_process::env::for_each([env_keys](const std::string& key, const std::string& value)
548 {
549 if (key == env_keys[0])
550 {
551 EXPECT_EQ("hello", value);
552 }
553 else if (key == env_keys[1])
554 {
555 EXPECT_EQ("", value);
556 }
557 else if (key == env_keys[2])
558 {
559 EXPECT_EQ("string=hello", value);
560 }
561 });
562 }
core::posix::this_process::env::get
CORE_POSIX_DLL_PUBLIC std::string get(const std::string &key, const std::string &default_value=std::string()) noexcept(true)
get queries the value of an environment variable.
Definition: this_process.cpp:84
core::posix::this_process::instance
CORE_POSIX_DLL_PUBLIC Process instance() noexcept(true)
Returns a Process instance corresponding to this process.
Definition: this_process.cpp:150
fork.h
core::posix::Process::process_group
virtual ProcessGroup process_group(std::error_code &se) const noexcept(true)
Queries the id of the process group this process belongs to.
Definition: process.cpp:74
core::posix::StandardStream::stdout
@ stdout
exec.h
TEST
TEST(PosixProcess, ctor_throws_for_invalid_pid)
Definition: posix_process_test.cpp:72
core::posix::ChildProcess::invalid
static ChildProcess invalid()
Creates an invalid ChildProcess.
Definition: child_process.cpp:325
core::posix::ChildProcess::wait_for
wait::Result wait_for(const wait::Flags &flags)
Wait for the child process to change state.
Definition: child_process.cpp:345
TEST_F
TEST_F(ForkedSpinningProcess, throwing_access_to_process_group_id_of_a_forked_process_works)
Definition: posix_process_test.cpp:113
core::posix::this_process::env::set_or_throw
CORE_POSIX_DLL_PUBLIC void set_or_throw(const std::string &key, const std::string &value)
set_or_throw will adjust the contents of the variable identified by key to the provided value.
Definition: this_process.cpp:119
core::posix::this_process::cerr
CORE_POSIX_DLL_PUBLIC std::ostream & cerr() noexcept(true)
Access this process's stderr.
Definition: this_process.cpp:171
process.h
core::posix::wait::Result::Status::exited
@ exited
The process exited normally.
core::posix::StandardStream::stdin
@ stdin
core::posix::exec
CORE_POSIX_DLL_PUBLIC ChildProcess exec(const std::string &fn, const std::vector< std::string > &argv, const std::map< std::string, std::string > &env, const StandardStream &flags)
exec execve's the executable with the provided arguments and environment.
Definition: exec.cpp:33
core::posix::fork
CORE_POSIX_DLL_PUBLIC ChildProcess fork(const std::function< posix::exit::Status()> &main, const StandardStream &flags)
fork forks a new process and executes the provided main function in the newly forked process.
Definition: fork.cpp:57
core::posix::ChildProcess
The Process class models a child process of this process.
Definition: child_process.h:44
core::posix::wait::Result::Status::signaled
@ signaled
The process was signalled and terminated.
core
Definition: child_process.h:32
core::posix::Process::pid
virtual pid_t pid() const
Query the pid of the process.
Definition: process.cpp:59
core::posix::this_process::cin
CORE_POSIX_DLL_PUBLIC std::istream & cin() noexcept(true)
Access this process's stdin.
Definition: this_process.cpp:161
signal.h
core::posix::this_process::cout
CORE_POSIX_DLL_PUBLIC std::ostream & cout() noexcept(true)
Access this process's stdout.
Definition: this_process.cpp:166
core::posix::this_process::env::for_each
CORE_POSIX_DLL_PUBLIC void for_each(const std::function< void(const std::string &, const std::string &)> &functor) noexcept(true)
for_each invokes a functor for every key-value pair in the environment.
Definition: this_process.cpp:55
core::posix::this_process::parent
CORE_POSIX_DLL_PUBLIC Process parent() noexcept(true)
Query the parent of the process.
Definition: this_process.cpp:156
EXPECT_ANY_THROW
EXPECT_ANY_THROW(auto death_observer=core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap(trap))
core::posix::StandardStream::stderr
@ stderr
core::posix::ChildProcess::cerr
std::istream & cerr()
Access this process's stderr.
Definition: child_process.cpp:382
core::posix::Process::invalid
static Process invalid()
Returns an invalid instance for testing purposes.
Definition: process.cpp:38
core::posix::Signalable::send_signal_or_throw
virtual void send_signal_or_throw(Signal signal)
Sends a signal to this signalable object.
Definition: signalable.cpp:34
core::posix::SignalTrap::stop
virtual void stop()=0
Stops execution of the signal trap.
core::posix::exit::Status::success
@ success
core::posix::this_process::env::unset_or_throw
CORE_POSIX_DLL_PUBLIC void unset_or_throw(const std::string &key)
unset_or_throw removes the variable with name key from the environment.
Definition: this_process.cpp:93
core::posix::ChildProcess::cin
std::ostream & cin()
Access this process's stdin.
Definition: child_process.cpp:387
core::posix::wait::Result::Status::stopped
@ stopped
The process was signalled and stopped.
core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap
static std::unique_ptr< DeathObserver > create_once_with_signal_trap(std::shared_ptr< SignalTrap > trap)
Creates the unique instance of class DeathObserver.
Definition: child_process.cpp:152
core::posix::trap_signals_for_all_subsequent_threads
CORE_POSIX_DLL_PUBLIC std::shared_ptr< SignalTrap > trap_signals_for_all_subsequent_threads(std::initializer_list< core::posix::Signal > blocked_signals)
Traps the specified signals for the current thread, and inherits the respective signal mask to all ch...
Definition: signal.cpp:210
core::posix::Process
The Process class models a process and possible operations on it.
Definition: process.h:45
core::posix::ChildProcess::cout
std::istream & cout()
Access this process's stdout.
Definition: child_process.cpp:392