MySQL 8.4.0
Source Code Documentation
process_launcher.h
Go to the documentation of this file.
1/* Copyright (c) 2018, 2024, 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();
181
182 /**
183 * Read up to a 'count' bytes from the stdout of the child process.
184 * This method blocks until the amount of bytes is read or specified
185 * timeout expires.
186 * @param buf already allocated buffer where the read data will be stored.
187 * @param count the maximum amount of bytes to read.
188 * @param timeout timeout (in milliseconds) for the read to complete
189 * @return the real number of bytes read.
190 * Returns an shcore::Exception in case of error when reading.
191 */
192 int read(char *buf, size_t count, std::chrono::milliseconds timeout);
193
194 /**
195 * Writes several butes into stdin of child process.
196 * Returns an shcore::Exception in case of error when writing.
197 */
198 int write(const char *buf, size_t count);
199
200 /**
201 * Kills the child process and returns process' exit code.
202 */
203 exit_status_type kill();
204
207
208 /**
209 * Returns the child process id.
210 */
211 process_id_type get_pid() const;
212
213 /**
214 * Returns the child process handle.
215 */
216 process_handle_type get_process_handle() const;
217
218 /**
219 * get exit-code.
220 */
222
223 /**
224 * Wait for the child process to exists and returns its exit code.
225 * If the child process is already dead, wait() just returns.
226 *
227 * @returns the exit code of the process.
228 * @throws std::runtime_error if process exited with a signal
229 */
230
231 int wait(std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));
232
233 exit_status_type native_wait(
234 std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));
235
236 /**
237 * Closes pipe to process' STDIN in order to notify the process that all
238 * data was sent.
239 */
240 void end_of_write();
241
242 enum class ShutdownEvent {
243 TERM, // clean shutdown (ie. SIGTERM on Unix)
244 KILL, // immediate (and abrupt) shutdown (ie. SIGKILL on Unix)
245 ABRT // try to generate a stacktrace
246 };
247 /**
248 * Sends a shutdown event to child process (SIGTERM on Unix, Ctrl+C on
249 * Win)
250 *
251 * @param event type of shutdown event
252 * @return std::error_code indicating success/failure
253 */
254 std::error_code send_shutdown_event(
255 ShutdownEvent event = ShutdownEvent::TERM) const noexcept;
256
257 private:
258 /**
259 * Closes child process and returns process' exit code.
260 *
261 * @throws std::system_error if sending signal to child process fails
262 * @throws std::runtime_error if waiting for process to change state fails
263 *
264 * @return process exit code.
265 */
266 exit_status_type close();
267
268 std::mutex fd_in_mtx_;
269 std::mutex fd_out_mtx_;
270
272};
273
274} // end of namespace mysql_harness
275
276#endif // _PROCESS_LAUNCHER_H_
exit status of processes.
Definition: exit_status.h:48
Definition: process_launcher.h:136
bool is_alive
Definition: process_launcher.h:271
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:206
ProcessLauncher(ProcessLauncher &&rhs)
Definition: process_launcher.h:168
std::mutex fd_out_mtx_
Definition: process_launcher.h:269
ProcessLauncher operator=(const ProcessLauncher &)=delete
std::mutex fd_in_mtx_
Definition: process_launcher.h:268
ShutdownEvent
Definition: process_launcher.h:242
SpawnedProcess::handle_type process_handle_type
Definition: process_launcher.h:205
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:284
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
static int wait(mysql_cond_t *that, mysql_mutex_t *mutex_arg, const char *, unsigned int)
Definition: mysql_cond_v1_native.cc:63
Definition: common.h:42
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:2874
required string event
Definition: replication_group_member_actions.proto:32
@ KILL
Definition: task.h:232
#define HANDLE
Definition: violite.h:159