MySQL 8.0.29
Source Code Documentation
process_launcher.h
Go to the documentation of this file.
1/* Copyright (c) 2018, 2021, 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 <stdexcept>
30#include <string>
31#include <system_error>
32#include <utility>
33#include <vector>
34
35#ifdef _WIN32
36#define _CRT_SECURE_NO_WARNINGS 1
37#ifdef UNICODE
38# #undef UNICODE
39#endif
40#include <windows.h>
41#else
42#include <unistd.h>
43#endif
44
45#include "harness_export.h"
46
47namespace mysql_harness {
48#ifdef _WIN32
49namespace win32 {
50// reverse of CommandLineToArgv()
51HARNESS_EXPORT std::string cmdline_quote_arg(const std::string &arg);
52HARNESS_EXPORT std::string cmdline_from_args(
53 const std::string &executable_path, const std::vector<std::string> &args);
54} // namespace win32
55#endif
56
57/** an alive, spawned process
58 *
59 * @todo
60 * refactor ProcessLauchner and SpawnedProcess into:
61 * - ProcessLauncher having only the spawn/launch() method and no state
62 * - Process as a thin wrapper around 'pid' and operators on it
63 * - SpawnedProcess being a Process with stdin/stdout/stderr
64 * - a way to declare ownership over the 'pid' (if owned, kill pid in
65 * destructor) For now, this mostly exists to make the move-constructor of
66 * ProcessLauncher easier to implement.
67 */
68class HARNESS_EXPORT SpawnedProcess {
69 public:
70 SpawnedProcess(std::string pexecutable_path, std::vector<std::string> pargs,
71 std::vector<std::pair<std::string, std::string>> penv_vars,
72 bool predirect_stderr = true)
73 : executable_path{std::move(pexecutable_path)},
74 args{std::move(pargs)},
75 env_vars{std::move(penv_vars)},
76#ifdef _WIN32
77 child_in_rd{INVALID_HANDLE_VALUE},
78 child_in_wr{INVALID_HANDLE_VALUE},
79 child_out_rd{INVALID_HANDLE_VALUE},
80 child_out_wr{INVALID_HANDLE_VALUE},
81 pi{},
82 si{},
83#else
84 childpid{-1},
85 fd_in{-1, -1},
86 fd_out{-1, -1},
87#endif
88 redirect_stderr{predirect_stderr} {
89 }
90
91 SpawnedProcess(const SpawnedProcess &) = default;
92
93 virtual ~SpawnedProcess() = default;
94
95 std::string get_cmd_line() const;
96
97 protected:
98 const std::string executable_path;
99 const std::vector<std::string> args;
100 const std::vector<std::pair<std::string, std::string>> env_vars;
101#ifdef _WIN32
102 HANDLE child_in_rd;
103 HANDLE child_in_wr;
104 HANDLE child_out_rd;
105 HANDLE child_out_wr;
106 PROCESS_INFORMATION pi;
107 STARTUPINFO si;
108#else
109 pid_t childpid;
110 int fd_in[2];
111 int fd_out[2];
112#endif
114};
115
116// Launches a process as child of current process and exposes the stdin &
117// stdout of the child process (implemented thru pipelines) so the client of
118// this class can read from the child's stdout and write to the child's
119// stdin. For usage, see unit tests.
120//
121class HARNESS_EXPORT ProcessLauncher : public SpawnedProcess {
122#ifdef _WIN32
123 /*
124 * After ProcessLauncher sends all data to remote process, it closes the
125 * handle to notify the remote process that no more data will be sent.
126 *
127 * Since you cannot close the same handle more than once, store
128 * information if handle should be closed in child_in_wr_closed.
129 */
130 bool child_in_wr_closed = false;
131#endif
132
133 public:
134 /**
135 * Creates a new process and launch it.
136 * If redirect_stderr is true, the child's stderr is redirected to the
137 * same stream than child's stdout.
138 */
139 ProcessLauncher(std::string pexecutable_path, std::vector<std::string> pargs,
140 std::vector<std::pair<std::string, std::string>> penv_vars,
141 bool predirect_stderr = true)
142 : SpawnedProcess(std::move(pexecutable_path), std::move(pargs),
143 std::move(penv_vars), predirect_stderr),
144 is_alive{false} {}
145
146 // copying a Process results in multiple destructors trying
147 // to kill the same alive process. Disable it.
150
152 : SpawnedProcess(rhs), is_alive(std::move(rhs.is_alive)) {
153 // make sure destructor on the other object doesn't try to kill
154 // the process-id we just moved
155
156 rhs.is_alive = false;
157 }
158
159 ~ProcessLauncher() override;
160
161 /** Launches the child process, and makes pipes available for read/write.
162 */
163 void start();
164
165 /**
166 * Read up to a 'count' bytes from the stdout of the child process.
167 * This method blocks until the amount of bytes is read or specified
168 * timeout expires.
169 * @param buf already allocated buffer where the read data will be stored.
170 * @param count the maximum amount of bytes to read.
171 * @param timeout timeout (in milliseconds) for the read to complete
172 * @return the real number of bytes read.
173 * Returns an shcore::Exception in case of error when reading.
174 */
175 int read(char *buf, size_t count, std::chrono::milliseconds timeout);
176
177 /**
178 * Writes several butes into stdin of child process.
179 * Returns an shcore::Exception in case of error when writing.
180 */
181 int write(const char *buf, size_t count);
182
183 /**
184 * Kills the child process and returns process' exit code.
185 */
186 int kill();
187
188 /**
189 * Returns the child process handle.
190 * In Linux this needs to be cast to pid_t, in Windows to cast to HANDLE.
191 */
192 uint64_t get_pid() const;
193
194 /**
195 * Wait for the child process to exists and returns its exit code.
196 * If the child process is already dead, wait() just returns.
197 * Returns the exit code of the process.
198 */
199 int wait(std::chrono::milliseconds timeout = std::chrono::milliseconds(1000));
200
201 /**
202 * Closes pipe to process' STDIN in order to notify the process that all
203 * data was sent.
204 */
205 void end_of_write();
206
207 enum class ShutdownEvent {
208 TERM, // clean shutdown (ie. SIGTERM on Unix)
209 KILL // immediate (and abrupt) shutdown (ie. SIGKILL on Unix)
210 };
211 /**
212 * Sends a shutdown event to child process (SIGTERM on Unix, Ctrl+C on
213 * Win)
214 *
215 * @param event type of shutdown event
216 * @return std::error_code indicating success/failure
217 */
218 std::error_code send_shutdown_event(
219 ShutdownEvent event = ShutdownEvent::TERM) const noexcept;
220
221 private:
222 /**
223 * Closes child process and returns process' exit code.
224 *
225 * @throws std::system_error if sending signal to child process fails
226 * @throws std::runtime_error if waiting for process to change state fails
227 *
228 * @return process exit code.
229 */
230 int close();
231
232 std::mutex fd_in_mtx_;
233 std::mutex fd_out_mtx_;
234
236};
237
238} // end of namespace mysql_harness
239
240#endif // _PROCESS_LAUNCHER_H_
Definition: process_launcher.h:121
bool is_alive
Definition: process_launcher.h:235
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:139
ProcessLauncher(ProcessLauncher &&rhs)
Definition: process_launcher.h:151
std::mutex fd_out_mtx_
Definition: process_launcher.h:233
ProcessLauncher operator=(const ProcessLauncher &)=delete
std::mutex fd_in_mtx_
Definition: process_launcher.h:232
ShutdownEvent
Definition: process_launcher.h:207
ProcessLauncher(const ProcessLauncher &)=delete
an alive, spawned process
Definition: process_launcher.h:68
virtual ~SpawnedProcess()=default
const std::vector< std::pair< std::string, std::string > > env_vars
Definition: process_launcher.h:100
SpawnedProcess(const SpawnedProcess &)=default
bool redirect_stderr
Definition: process_launcher.h:113
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:70
pid_t childpid
Definition: process_launcher.h:109
const std::string executable_path
Definition: process_launcher.h:98
const std::vector< std::string > args
Definition: process_launcher.h:99
static void start(mysql_harness::PluginFuncEnv *env)
Definition: http_auth_backend_plugin.cc:168
static int count
Definition: myisam_ftdump.cc:42
Definition: buf0block_hint.cc:29
static bool timeout(bool(*wait_condition)())
Timeout function.
Definition: log0meb.cc:493
Definition: common.h:41
stdx::expected< size_t, std::error_code > wait(int epfd, epoll_event *fd_events, size_t num_fd_events, std::chrono::milliseconds timeout)
Definition: linux_epoll.h:82
stdx::expected< void, std::error_code > close(file_handle_type native_handle)
close file handle.
Definition: file.h:238
Definition: varlen_sort.h:183
std::vector< T, ut::allocator< T > > vector
Specialization of vector which uses allocator.
Definition: ut0new.h:2853
required string event
Definition: replication_group_member_actions.proto:31
@ KILL
Definition: task.h:231
#define HANDLE
Definition: violite.h:158