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