uvw  1.15.0
process.hpp
1 #pragma once
2 
3 
4 #include <algorithm>
5 #include <utility>
6 #include <memory>
7 #include <string>
8 #include <vector>
9 #include <uv.h>
10 #include "handle.hpp"
11 #include "stream.hpp"
12 #include "util.hpp"
13 #include "loop.hpp"
14 
15 
16 namespace uvw {
17 
18 
19 namespace details {
20 
21 
22 enum class UVProcessFlags: std::underlying_type_t<uv_process_flags> {
23  SETUID = UV_PROCESS_SETUID,
24  SETGID = UV_PROCESS_SETGID,
25  WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
26  DETACHED = UV_PROCESS_DETACHED,
27  WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE,
28  WINDOWS_HIDE_CONSOLE = UV_PROCESS_WINDOWS_HIDE_CONSOLE,
29  WINDOWS_HIDE_GUI = UV_PROCESS_WINDOWS_HIDE_GUI
30 };
31 
32 
33 enum class UVStdIOFlags: std::underlying_type_t<uv_stdio_flags> {
34  IGNORE_STREAM = UV_IGNORE,
35  CREATE_PIPE = UV_CREATE_PIPE,
36  INHERIT_FD = UV_INHERIT_FD,
37  INHERIT_STREAM = UV_INHERIT_STREAM,
38  READABLE_PIPE = UV_READABLE_PIPE,
39  WRITABLE_PIPE = UV_WRITABLE_PIPE,
40  OVERLAPPED_PIPE = UV_OVERLAPPED_PIPE
41 };
42 
43 
44 }
45 
46 
52 struct ExitEvent {
53  explicit ExitEvent(int64_t code, int sig) noexcept
54  : status{code}, signal{sig}
55  {}
56 
57  int64_t status;
58  int signal;
59 };
60 
67 class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
68  static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) {
69  ProcessHandle &process = *(static_cast<ProcessHandle*>(handle->data));
70  process.publish(ExitEvent{exitStatus, termSignal});
71  }
72 
73 public:
74  using Process = details::UVProcessFlags;
75  using StdIO = details::UVStdIOFlags;
76 
77  ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref)
78  : Handle{ca, std::move(ref)}
79  {}
80 
95  static void disableStdIOInheritance() noexcept {
96  uv_disable_stdio_inheritance();
97  }
98 
105  static bool kill(int pid, int signum) noexcept {
106  return (0 == uv_kill(pid, signum));
107  }
108 
113  bool init() {
114  // deferred initialization: libuv initializes process handles only when
115  // uv_spawn is invoked and uvw stays true to the underlying library
116  return true;
117  }
118 
133  void spawn(const char *file, char **args, char **env = nullptr) {
134  uv_process_options_t po;
135 
136  po.exit_cb = &exitCallback;
137  po.file = file;
138  po.args = args;
139  po.env = env;
140  po.cwd = poCwd.empty() ? nullptr : poCwd.data();
141  po.flags = poFlags;
142  po.uid = poUid;
143  po.gid = poGid;
144 
145  std::vector<uv_stdio_container_t> poStdio;
146  poStdio.reserve(poFdStdio.size() + poStreamStdio.size());
147  poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());
148  poStdio.insert(poStdio.end(), poStreamStdio.cbegin(), poStreamStdio.cend());
149 
150  po.stdio_count = static_cast<decltype(po.stdio_count)>(poStdio.size());
151  po.stdio = poStdio.data();
152 
153  // fake initialization so as to have leak invoked
154  // see init member function for more details
155  initialize([](auto...){ return 0; });
156 
157  invoke(&uv_spawn, parent(), get(), &po);
158  }
159 
164  void kill(int signum) {
165  invoke(&uv_process_kill, get(), signum);
166  }
167 
175  int pid() noexcept {
176  return get()->pid;
177  }
178 
184  ProcessHandle & cwd(std::string path) noexcept {
185  poCwd = path;
186  return *this;
187  }
188 
209  ProcessHandle & flags(Flags<Process> flags) noexcept {
210  poFlags = flags;
211  return *this;
212  }
213 
235  template<typename T, typename U>
237  uv_stdio_container_t container;
238  Flags<StdIO>::Type fgs = flags;
239  container.flags = static_cast<uv_stdio_flags>(fgs);
240  container.data.stream = get<uv_stream_t>(stream);
241  poStreamStdio.push_back(std::move(container));
242  return *this;
243  }
244 
272  auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});
273 
274  auto actual = FileHandle::Type{fd};
275 
276  auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container){
277  return container.data.fd == actual;
278  });
279 
280  if(it == poFdStdio.cend()) {
281  uv_stdio_container_t container;
282  container.flags = fgs;
283  container.data.fd = actual;
284  poFdStdio.push_back(std::move(container));
285  } else {
286  it->flags = fgs;
287  it->data.fd = actual;
288  }
289 
290  return *this;
291  }
292 
299  poUid = id;
300  return *this;
301  }
302 
309  poGid = id;
310  return *this;
311  }
312 
313 private:
314  std::string poCwd;
315  Flags<Process> poFlags;
316  std::vector<uv_stdio_container_t> poFdStdio;
317  std::vector<uv_stdio_container_t> poStreamStdio;
318  Uid poUid;
319  Gid poGid;
320 };
321 
322 
323 }
ProcessHandle & stdio(FileHandle fd, Flags< StdIO > flags)
Makes a file descriptor available to the child process.
Definition: process.hpp:271
ProcessHandle & cwd(std::string path) noexcept
Sets the current working directory for the subprocess.
Definition: process.hpp:184
int64_t status
Definition: process.hpp:57
details::UVTypeWrapper< uv_file > FileHandle
Definition: util.hpp:199
bool init()
Initializes the handle.
Definition: process.hpp:113
void spawn(const char *file, char **args, char **env=nullptr)
spawn Starts the process.
Definition: process.hpp:133
ProcessHandle & stdio(StreamHandle< T, U > &stream, Flags< StdIO > flags)
Makes a stdio handle available to the child process.
Definition: process.hpp:236
Handle base class.
Definition: handle.hpp:29
static void disableStdIOInheritance() noexcept
Disables inheritance for file descriptors/handles.
Definition: process.hpp:95
The StreamHandle handle.
Definition: stream.hpp:130
The ProcessHandle handle.
Definition: process.hpp:67
uv_gid_t Gid
Definition: util.hpp:211
uv_uid_t Uid
Definition: util.hpp:210
int pid() noexcept
Gets the PID of the spawned process.
Definition: process.hpp:175
ProcessHandle & flags(Flags< Process > flags) noexcept
Sets flags that control how spawn() behaves.
Definition: process.hpp:209
static bool kill(int pid, int signum) noexcept
kill Sends the specified signal to the given PID.
Definition: process.hpp:105
ProcessHandle & uid(Uid id)
Sets the child process&#39; user id.
Definition: process.hpp:298
ExitEvent event.
Definition: process.hpp:52
ProcessHandle & gid(Gid id)
Sets the child process&#39; group id.
Definition: process.hpp:308
void kill(int signum)
Sends the specified signal to the internal process handle.
Definition: process.hpp:164
uvw default namespace.
Definition: async.hpp:11