process-cpp: /build/process-cpp/src/process-cpp-3.0.1/src/core/posix/fork.cpp Source File

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

fork.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/exit.h>
20 #include <core/posix/fork.h>
21
22 #include "backtrace.h"
23
24 #include <iomanip>
25 #include <iostream>
26 #include <system_error>
27
28 #include <unistd.h>
29
30 namespace
31 {
32 void redirect_stream_to_fd(int fd, int stream)
33 {
34 auto rc = ::dup2(fd, stream);
35 if (rc == -1)
36 throw std::system_error(errno, std::system_category());
37 }
38
39 void print_backtrace(std::ostream& out, const std::string& line_prefix)
40 {
41 core::posix::backtrace::visit_with_handler([&out, line_prefix](const core::posix::backtrace::Frame& frame)
42 {
43 out << line_prefix << std::dec << std::setw(2) << frame.depth() << "@" << std::hex << std::setw(14) << frame.frame_pointer() << ": "
44 << (frame.symbol().is_cxx() ? frame.symbol().demangled() : frame.symbol().raw()) << std::endl;
45 return true;
46 });
47 }
48 }
49
50 namespace core
51 {
52 namespace posix
53 {
54
55 bool is_child(pid_t pid) { return pid == 0; }
56
57 ChildProcess fork(const std::function<posix::exit::Status()>& main,
58 const StandardStream& flags)
59 {
60 ChildProcess::Pipe stdin_pipe{ChildProcess::Pipe::invalid()};
61 ChildProcess::Pipe stdout_pipe{ChildProcess::Pipe::invalid()};
62 ChildProcess::Pipe stderr_pipe{ChildProcess::Pipe::invalid()};
63
64 if ((flags & StandardStream::stdin) != StandardStream::empty)
65 stdin_pipe = ChildProcess::Pipe();
66 if ((flags & StandardStream::stdout) != StandardStream::empty)
67 stdout_pipe = ChildProcess::Pipe();
68 if ((flags & StandardStream::stderr) != StandardStream::empty)
69 stderr_pipe = ChildProcess::Pipe();
70
71 pid_t pid = ::fork();
72
73 if (pid == -1)
74 throw std::system_error(errno, std::system_category());
75
76 if (is_child(pid))
77 {
78 posix::exit::Status result = posix::exit::Status::failure;
79
80 try
81 {
82 stdin_pipe.close_write_fd();
83 stdout_pipe.close_read_fd();
84 stderr_pipe.close_read_fd();
85 // We replace stdin and stdout of the child process first:
86 if ((flags & StandardStream::stdin) != StandardStream::empty)
87 redirect_stream_to_fd(stdin_pipe.read_fd(), STDIN_FILENO);
88 if ((flags & StandardStream::stdout) != StandardStream::empty)
89 redirect_stream_to_fd(stdout_pipe.write_fd(), STDOUT_FILENO);
90 if ((flags & StandardStream::stderr) != StandardStream::empty)
91 redirect_stream_to_fd(stderr_pipe.write_fd(), STDERR_FILENO);
92
93 result = main();
94 } catch(const std::exception& e)
95 {
96 std::cerr << "core::posix::fork(): An unhandled std::exception occured in the child process:" << std::endl
97 << " what(): " << e.what() << std::endl;
98 print_backtrace(std::cerr, " ");
99 } catch(...)
100 {
101 std::cerr << "core::posix::fork(): An unhandled exception occured in the child process." << std::endl;
102 print_backtrace(std::cerr, " ");
103 }
104
105 // We have to ensure that we exit here. Otherwise, we run into
106 // all sorts of weird issues.
107 ::exit(static_cast<int>(result));
108 }
109
110 // We are in the parent process, and create a process object
111 // corresponding to the newly forked process.
112 stdin_pipe.close_read_fd();
113 stdout_pipe.close_write_fd();
114 stderr_pipe.close_write_fd();
115
116 return ChildProcess(pid,
117 stdin_pipe,
118 stdout_pipe,
119 stderr_pipe);
120 }
121
122 ChildProcess vfork(const std::function<posix::exit::Status()>& main,
123 const StandardStream& flags)
124 {
125 ChildProcess::Pipe stdin_pipe, stdout_pipe, stderr_pipe;
126
127 pid_t pid = ::vfork();
128
129 if (pid == -1)
130 throw std::system_error(errno, std::system_category());
131
132 if (is_child(pid))
133 {
134 posix::exit::Status result = posix::exit::Status::failure;
135
136 try
137 {
138 // We replace stdin and stdout of the child process first:
139 stdin_pipe.close_write_fd();
140 stdout_pipe.close_read_fd();
141 stderr_pipe.close_read_fd();
142 // We replace stdin and stdout of the child process first:
143 if ((flags & StandardStream::stdin) != StandardStream::empty)
144 redirect_stream_to_fd(stdin_pipe.read_fd(), STDIN_FILENO);
145 if ((flags & StandardStream::stdout) != StandardStream::empty)
146 redirect_stream_to_fd(stdout_pipe.write_fd(), STDOUT_FILENO);
147 if ((flags & StandardStream::stderr) != StandardStream::empty)
148 redirect_stream_to_fd(stderr_pipe.write_fd(), STDERR_FILENO);
149
150 result = main();
151 } catch(const std::exception& e)
152 {
153 std::cerr << "core::posix::fork(): An unhandled std::exception occured in the child process:" << std::endl
154 << " what(): " << e.what() << std::endl;
155 print_backtrace(std::cerr, " ");
156 } catch(...)
157 {
158 std::cerr << "core::posix::fork(): An unhandled exception occured in the child process." << std::endl;
159 print_backtrace(std::cerr, " ");
160 }
161
162 // We have to ensure that we exit here. Otherwise, we run into
163 // all sorts of weird issues.
164 ::exit(static_cast<int>(result));
165 }
166
167 // We are in the parent process, and create a process object
168 // corresponding to the newly forked process.
169 // Close the parent's pipe end
170 stdin_pipe.close_read_fd();
171 stdout_pipe.close_write_fd();
172 stderr_pipe.close_write_fd();
173
174 return ChildProcess(pid,
175 stdin_pipe,
176 stdout_pipe,
177 stderr_pipe);
178 }
179 }
180 }
core::posix::backtrace::Frame
The Frame class models an individual frame of a backtrace.
Definition: backtrace.h:38
core::posix::is_child
bool is_child(pid_t pid)
Definition: fork.cpp:55
core::posix::vfork
CORE_POSIX_DLL_PUBLIC ChildProcess vfork(const std::function< posix::exit::Status()> &main, const StandardStream &flags)
fork vforks a new process and executes the provided main function in the newly forked process.
Definition: fork.cpp:122
core::posix::StandardStream
StandardStream
The StandardStream enum wraps the POSIX standard streams.
Definition: standard_stream.h:34
fork.h
core::posix::backtrace::Frame::Symbol::raw
virtual std::string raw() const =0
raw The raw symbolic representation of a frame pointer.
exit.h
core::posix::backtrace::Frame::depth
virtual std::size_t depth() const =0
depth returns the depth of this frame in the overall backtrace.
backtrace.h
core::posix::StandardStream::stdout
@ stdout
core::posix::exit::Status
Status
The Status enum wrap's the posix exit status.
Definition: exit.h:34
main
int main(int argc, char *argv[])
Definition: CMakeCCompilerId.c:665
core::posix::this_process::cerr
CORE_POSIX_DLL_PUBLIC std::ostream & cerr() noexcept(true)
Access this process's stderr.
Definition: this_process.cpp:171
core::posix::backtrace::Frame::Symbol::is_cxx
virtual bool is_cxx() const =0
is_cxx checks whether the symbol refers to a mangled C++ symbol.
core::posix::StandardStream::stdin
@ stdin
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::backtrace::Frame::frame_pointer
virtual void * frame_pointer() const =0
frame_pointer returns the the raw frame pointer of this frame.
core
Definition: child_process.h:32
core::posix::backtrace::Frame::symbol
virtual const Symbol & symbol() const =0
symbol returns the symbolic representation of this frame.
core::posix::StandardStream::stderr
@ stderr
core::posix::exit::Status::success
@ success
core::posix::backtrace::visit_with_handler
void visit_with_handler(const FrameHandler &handler)
visit_with_handler iterates the backtrace of the calling program, invoking the handler for every fram...
Definition: backtrace.cpp:125
core::posix::backtrace::Frame::Symbol::demangled
virtual std::string demangled() const =0
demangled returns the demangled C++ symbol name or raw.