MySQL 8.3.0
Source Code Documentation
process_launcher.h
Go to the documentation of this file.
1/* Copyright (c) 2018, 2023, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23#ifndef _PROCESS_LAUNCHER_H_
24#define _PROCESS_LAUNCHER_H_
25
26#include <chrono>
27#include <cstdint>
28#include <mutex>
29#include <ostream>
30#include <stdexcept>
31#include <string>
32#include <system_error>
33#include <utility>
34#include <vector>
35
36#ifdef _WIN32
37#define _CRT_SECURE_NO_WARNINGS 1
38#ifdef UNICODE
39# #undef UNICODE
40#endif
41#include <windows.h>
42#else
43#include <unistd.h>
44#endif
45
46#include "harness_export.h"
47
48#include "exit_status.h"
50
51namespace mysql_harness {
52#ifdef _WIN32
53namespace win32 {
54// reverse of CommandLineToArgv()
55HARNESS_EXPORT std::string cmdline_quote_arg(const std::string &arg);
56HARNESS_EXPORT std::string cmdline_from_args(
57 const std::string &executable_path, const std::vector<std::string> &args);
58} // namespace win32
59#endif
60
61/** an alive, spawned process
62 *
63 * @todo
64 * refactor ProcessLauchner and SpawnedProcess into:
65 * - ProcessLauncher having only the spawn/launch() method and no state
66 * - Process as a thin wrapper around 'pid' and operators on it
67 * - SpawnedProcess being a Process with stdin/stdout/stderr
68 * - a way to declare ownership over the 'pid' (if owned, kill pid in
69 * destructor) For now, this mostly exists to make the move-constructor of
70 * ProcessLauncher easier to implement.
71 */
72class HARNESS_EXPORT SpawnedProcess {
73 public:
74 SpawnedProcess(std::string pexecutable_path, std::vector<std::string> pargs,
75 std::vector<std::pair<std::string, std::string>> penv_vars,
76 bool predirect_stderr = true)
77 : executable_path{std::move(pexecutable_path)},
78 args{std::move(pargs)},
79 env_vars{std::move(penv_vars)},
80#ifdef _WIN32
81 child_in_rd{INVALID_HANDLE_VALUE},
82 child_in_wr{INVALID_HANDLE_VALUE},
83 child_out_rd{INVALID_HANDLE_VALUE},
84 child_out_wr{INVALID_HANDLE_VALUE},
85 pi{},
86 si{},
87#else
88 childpid{-1},
89 fd_in{-1, -1},
90 fd_out{-1, -1},
91#endif
92 redirect_stderr{predirect_stderr} {
93 }
94
95 SpawnedProcess(const SpawnedProcess &) = default;
96
97 virtual ~SpawnedProcess() = default;
98
99#ifdef _WIN32
100 using handle_type = HANDLE;
101 using id_type = DWORD;
102#else
103 using handle_type = pid_t;
104 using id_type = pid_t;
105#endif
106
107 std::string get_cmd_line() const;
108
109 std::string executable() const { return executable_path; }
110
111 protected:
112 const std::string executable_path;
113 const std::vector<std::string> args;
114 const std::vector<std::pair<std::string, std::string>> env_vars;
115#ifdef _WIN32
116 HANDLE child_in_rd;
117 HANDLE child_in_wr;
118 HANDLE child_out_rd;
119 HANDLE child_out_wr;
120 PROCESS_INFORMATION pi;
121 STARTUPINFO si;
122#else
123 pid_t childpid;
124 int fd_in[2];
125 int fd_out[2];
126#endif
128};
129
130// Launches a process as child of current process and exposes the stdin &
131// stdout of the child process (implemented thru pipelines) so the client of
132// this class can read from the child's stdout and write to the child's
133// stdin. For usage, see unit tests.
134//
135class HARNESS_EXPORT ProcessLauncher : public SpawnedProcess {
136#ifdef _WIN32
137 /*
138 * After ProcessLauncher sends all data to remote process, it closes the
139 * handle to notify the remote process that no more data will be sent.
140 *
141 * Since you cannot close the same handle more than once, store
142 * information if handle should be closed in child_in_wr_closed.
143 */
144 bool child_in_wr_closed = false;
145#endif
146
147 public:
149
150 /**
151 * Creates a new process and launch it.
152 * If redirect_stderr is true, the child's stderr is redirected to the
153 * same stream than child's stdout.
154 */
155 ProcessLauncher(std::string pexecutable_path, std::vector<std::string> pargs,
156 std::vector<std::pair<std::string, std::string>> penv_vars,
157 bool predirect_stderr = true)
158 : SpawnedProcess(std::move(pexecutable_path), std::move(pargs),
159 std::move(penv_vars), predirect_stderr),
160 is_alive{false} {}
161
162 // copying a Process results in multiple destructors trying
163 // to kill the same alive process. Disable it.
166
168 : SpawnedProcess(rhs), is_alive(std::move(rhs.is_alive)) {
169 // make sure destructor on the other object doesn't try to kill
170 // the process-id we just moved
171
172 rhs.is_alive = false;
173 }
174
175 ~ProcessLauncher() override;
176
177 /** Launches the child process, and makes pipes available for read/write.
178 */
179 void start();
180
181 /**
182 * Read up to a 'count' bytes from the stdout of the child process.
183 * This method blocks until the amount of bytes is read or specified
184 * timeout expires.
185 * @param buf already allocated buffer where the read data will be stored.
186 * @param count the maximum amount of bytes to read.
187 * @param timeout timeout (in milliseconds) for the read to complete
188 * @return the real number of bytes read.
189 * Returns an shcore::Exception in case of error when reading.
190 */
191 int read(char *buf, size_t count, std::chrono::milliseconds timeout);
192
193 /**
194 * Writes several butes into stdin of child process.
195 * Returns an shcore::Exception in case of error when writing.
196 */
197 int write(const char *buf, size_t count);
198
199 /**
200 * Kills the child process and returns process' exit code.
201 */
202 exit_status_type kill();
203
206
207 /**
208 * Returns the child process id.
209 */
210 process_id_type get_pid() const;
211
212 /**
213 * Returns the child process handle.
214 */
215 process_handle_type get_process_handle() const;
216
217 /**
218 * get exit-code.
219 */
221
222 /**
223 * Wait for the child process to exists and returns its exit code.
224 * If the child process is already dead, wait() just returns.
225 *
226 * @returns the exit code of the process.
227 * @throws std::runtime_error if process exited with a signal
228 */
229
230 int wait(std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));
231
232 exit_status_type native_wait(
233 std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));
234
235 /**
236 * Closes pipe to process' STDIN in order to notify the process that all
237 * data was sent.
238 */
239 void end_of_write();
240
241 enum class ShutdownEvent {
242 TERM, // clean shutdown (ie. SIGTERM on Unix)
243 KILL, // immediate (and abrupt) shutdown (ie. SIGKILL on Unix)
244 ABRT // try to generate a stacktrace
245 };
246 /**
247 * Sends a shutdown event to child process (SIGTERM on Unix, Ctrl+C on
248 * Win)
249 *
250 * @param event type of shutdown event
251 * @return std::error_code indicating success/failure
252 */
253 std::error_code send_shutdown_event(
254 ShutdownEvent event = ShutdownEvent::TERM) const noexcept;
255
256 private:
257 /**
258 * Closes child process and returns process' exit code.
259 *
260 * @throws std::system_error if sending signal to child process fails
261 * @throws std::runtime_error if waiting for process to change state fails
262 *
263 * @return process exit code.
264 */
265 exit_status_type close();
266
267 std::mutex fd_in_mtx_;
268 std::mutex fd_out_mtx_;
269
271};
272
273} // end of namespace mysql_harness
274
275#endif // _PROCESS_LAUNCHER_H_
exit status of processes.
Definition: exit_status.h:47
Definition: process_launcher.h:135
bool is_alive
Definition: process_launcher.h:270
ProcessLauncher(std::string pexecutable_path, std::vector< std::string > pargs, std::vector< std::pair< std::string, std::string > > penv_vars, bool predirect_stderr=true)
Creates a new process and launch it.
Definition: process_launcher.h:155
SpawnedProcess::id_type process_id_type
Definition: process_launcher.h:205
ProcessLauncher(ProcessLauncher &&rhs)
Definition: process_launcher.h:167
std::mutex fd_out_mtx_
Definition: process_launcher.h:268
ProcessLauncher operator=(const ProcessLauncher &)=delete
std::mutex fd_in_mtx_
Definition: process_launcher.h:267
ShutdownEvent
Definition: process_launcher.h:241
SpawnedProcess::handle_type process_handle_type
Definition: process_launcher.h:204
ProcessLauncher(const ProcessLauncher &)=delete
an alive, spawned process
Definition: process_launcher.h:72
virtual ~SpawnedProcess()=default
const std::vector< std::pair< std::string, std::string > > env_vars
Definition: process_launcher.h:114
SpawnedProcess(const SpawnedProcess &)=default
bool redirect_stderr
Definition: process_launcher.h:127
pid_t id_type
Definition: process_launcher.h:104
pid_t handle_type
Definition: process_launcher.h:103
SpawnedProcess(std::string pexecutable_path, std::vector< std::string > pargs, std::vector< std::pair< std::string, std::string > > penv_vars, bool predirect_stderr=true)
Definition: process_launcher.h:74
pid_t childpid
Definition: process_launcher.h:123
std::string executable() const
Definition: process_launcher.h:109
const std::string executable_path
Definition: process_launcher.h:112
const std::vector< std::string > args
Definition: process_launcher.h:113
Definition: expected.h:943
static void start(mysql_harness::PluginFuncEnv *env)
Definition: http_auth_backend_plugin.cc:176
static int count
Definition: myisam_ftdump.cc:44
Definition: buf0block_hint.cc:29
static bool timeout(bool(*wait_condition)())
Timeout function.
Definition: log0meb.cc:497
static int wait(mysql_cond_t *that, mysql_mutex_t *mutex_arg, const char *, unsigned int)
Definition: mysql_cond_v1_native.cc:62
Definition: common.h:41
stdx::expected< void, std::error_code > close(file_handle_type native_handle)
close file handle.
Definition: file.h:238
Definition: varlen_sort.h:174
std::vector< T, ut::allocator< T > > vector
Specialization of vector which uses allocator.
Definition: ut0new.h:2873
required string event
Definition: replication_group_member_actions.proto:31
@ KILL
Definition: task.h:231
#define HANDLE
Definition: violite.h:158