Turi Create  4.0
process.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef PROCESS_HPP
7 #define PROCESS_HPP
8 
9 #ifndef STDIN_FILENO
10 #define STDIN_FILENO 0
11 #endif
12 #ifndef STDOUT_FILENO
13 #define STDOUT_FILENO 1
14 #endif
15 #ifndef STDERR_FILENO
16 #define STDERR_FILENO 2
17 #endif
18 
19 #include <string>
20 #include <vector>
21 #include <core/util/syserr_reporting.hpp>
22 
23 #ifdef _WIN32
24 #include <cross_platform/windows_wrapper.hpp>
25 #endif
26 #ifdef __APPLE__
27 #include <sys/types.h>
28 #endif
29 namespace turi
30 {
31 
32 /**
33  * \defgroup process_management Process Management
34  * \brief Cross platform (Windows, Mac, Linux) sub-process management.
35  */
36 
37 /**
38  * \ingroup process_management
39  * \class process
40  * Cross platform process launching, and management.
41  */
42 class process {
43  public:
44  process() {};
45  ~process();
46 
47  /**
48  * A "generic" process launcher.
49  *
50  * Launched the command with the given arguments as a separate child process.
51  *
52  * This function does not throw.
53  */
54  bool launch(const std::string &cmd,
55  const std::vector<std::string> &args);
56 
57  /**
58  * A generic implementation of popen in read mode.
59  *
60  * This means that whatever the child writes on the given file descriptor
61  * (target_child_write_fd) can be read by calling read_from_child. On Unix systems,
62  * this could be any file descriptor inherited by the child from the parent.
63  * On Windows, we only accept STDOUT_FILENO and STDERR_FILENO.
64  *
65  * NOTE: The STD*_FILENO constants are Unix specific, but defined in this
66  * header for convenience.
67  *
68  * For instance,
69  * if target_child_write_fd == STDOUT_FILENO, when child writes to STDOUT,
70  * the parent can use read_from_child to read it.
71  *
72  * if target_child_write_fd == STDERR_FILENO, when child writes to STDERR,
73  * the parent can use read_from_child to read it.
74  *
75  * if open_write_pipe == true, write_to_child can be used.
76  *
77  * This function does not throw.
78  */
79  bool popen(const std::string &cmd,
80  const std::vector<std::string> &args,
81  int target_child_write_fd,
82  bool open_write_pipe=false);
83  /**
84  * If we've set up a way to read from the child, use this to read.
85  *
86  * Returns -1 on error, otherwise bytes received
87  *
88  * Throws if a way to read was not set up or if process was not launched.
89  */
90  ssize_t read_from_child(void *buf, size_t count);
91 
92  std::string read_from_child();
93 
94  /**
95  * Writes to the child's stdin.
96  *
97  * Returns false on error.
98  *
99  * Throws if a way to read was not set up or if process was not launched.
100  */
101  bool write_to_child(const void *buf, size_t count);
102 
103  /**
104  * Kill the launched process
105  *
106  * Throws if process was never launched.
107  */
108  bool kill(bool async=true);
109 
110  /**
111  * Check if the process launched is running.
112  *
113  * Throws if process was never launched.
114  */
115  bool exists();
116 
117  /**
118  * Return the process's return code if it has exited.
119  *
120  * Returns INT_MIN if the process is still running.
121  * Returns INT_MAX if getting the error code failed for some other reason.
122  */
123  int get_return_code();
124 
125  void close_read_pipe();
126 
127  size_t get_pid();
128 
129  /**
130  * Sets O_NONBLOCK on the process if the argument is true.
131  */
132  void set_nonblocking(bool nonblocking);
133 
134  /**
135  * Mark that this process should be automatically reaped.
136  * In which case, get_return_code() will not work.
137  */
138  void autoreap();
139  private:
140  //***Methods
141  process(process const&) = delete;
142  process& operator=(process const&) = delete;
143 
144 #ifdef _WIN32
145  //***Methods
146  //***Variables
147 
148  // Handle needed to interact with the process
149  HANDLE m_proc_handle = NULL;
150 
151  // Handle needed for parent to read from child
152  HANDLE m_read_handle = NULL;
153 
154  // Handle needed for child to write to parent
155  HANDLE m_write_handle = NULL;
156 
157  // Duplicate of handle so child can pipe stderr and stdout to console.
158  HANDLE m_stderr_handle = NULL;
159  HANDLE m_stdout_handle = NULL;
160 
161  DWORD m_pid = DWORD(-1);
162 
163  BOOL m_launched = FALSE;
164 
165  BOOL m_launched_with_popen = FALSE;
166 #else
167 
168  //***Variables
169  // Handle needed to read/write to this process
170  int m_read_handle = -1;
171  int m_write_handle = -1;
172 
173  pid_t m_pid = 0;
174 
175  bool m_launched = false;
176 
177  bool m_launched_with_popen = false;
178 #endif
179 };
180 
181 } // namespace turi
182 #endif //PROCESS_HPP
ssize_t read_from_child(void *buf, size_t count)
int get_return_code()
bool launch(const std::string &cmd, const std::vector< std::string > &args)
bool write_to_child(const void *buf, size_t count)
void set_nonblocking(bool nonblocking)
bool kill(bool async=true)
bool popen(const std::string &cmd, const std::vector< std::string > &args, int target_child_write_fd, bool open_write_pipe=false)