1 |
|
|
// Copyright Joyent, Inc. and other Node contributors. |
2 |
|
|
// |
3 |
|
|
// Permission is hereby granted, free of charge, to any person obtaining a |
4 |
|
|
// copy of this software and associated documentation files (the |
5 |
|
|
// "Software"), to deal in the Software without restriction, including |
6 |
|
|
// without limitation the rights to use, copy, modify, merge, publish, |
7 |
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
8 |
|
|
// persons to whom the Software is furnished to do so, subject to the |
9 |
|
|
// following conditions: |
10 |
|
|
// |
11 |
|
|
// The above copyright notice and this permission notice shall be included |
12 |
|
|
// in all copies or substantial portions of the Software. |
13 |
|
|
// |
14 |
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
15 |
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
16 |
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
17 |
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
18 |
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
19 |
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
20 |
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
21 |
|
|
|
22 |
|
|
#ifndef SRC_SPAWN_SYNC_H_ |
23 |
|
|
#define SRC_SPAWN_SYNC_H_ |
24 |
|
|
|
25 |
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
26 |
|
|
|
27 |
|
|
#include "node_buffer.h" |
28 |
|
|
#include "uv.h" |
29 |
|
|
#include "v8.h" |
30 |
|
|
|
31 |
|
|
namespace node { |
32 |
|
|
|
33 |
|
|
|
34 |
|
|
|
35 |
|
|
class SyncProcessOutputBuffer; |
36 |
|
|
class SyncProcessStdioPipe; |
37 |
|
|
class SyncProcessRunner; |
38 |
|
|
|
39 |
|
|
|
40 |
|
|
class SyncProcessOutputBuffer { |
41 |
|
|
static const unsigned int kBufferSize = 65536; |
42 |
|
|
|
43 |
|
|
public: |
44 |
|
1639 |
inline SyncProcessOutputBuffer() = default; |
45 |
|
|
|
46 |
|
|
inline void OnAlloc(size_t suggested_size, uv_buf_t* buf) const; |
47 |
|
|
inline void OnRead(const uv_buf_t* buf, size_t nread); |
48 |
|
|
|
49 |
|
|
inline size_t Copy(char* dest) const; |
50 |
|
|
|
51 |
|
|
inline unsigned int available() const; |
52 |
|
|
inline unsigned int used() const; |
53 |
|
|
|
54 |
|
|
inline SyncProcessOutputBuffer* next() const; |
55 |
|
|
inline void set_next(SyncProcessOutputBuffer* next); |
56 |
|
|
|
57 |
|
|
private: |
58 |
|
|
// Use unsigned int because that's what `uv_buf_init` takes. |
59 |
|
|
mutable char data_[kBufferSize]; |
60 |
|
|
unsigned int used_ = 0; |
61 |
|
|
|
62 |
|
|
SyncProcessOutputBuffer* next_ = nullptr; |
63 |
|
|
}; |
64 |
|
|
|
65 |
|
|
|
66 |
|
|
class SyncProcessStdioPipe { |
67 |
|
|
enum Lifecycle { |
68 |
|
|
kUninitialized = 0, |
69 |
|
|
kInitialized, |
70 |
|
|
kStarted, |
71 |
|
|
kClosing, |
72 |
|
|
kClosed |
73 |
|
|
}; |
74 |
|
|
|
75 |
|
|
public: |
76 |
|
|
SyncProcessStdioPipe(SyncProcessRunner* process_handler, |
77 |
|
|
bool readable, |
78 |
|
|
bool writable, |
79 |
|
|
uv_buf_t input_buffer); |
80 |
|
|
~SyncProcessStdioPipe(); |
81 |
|
|
|
82 |
|
|
int Initialize(uv_loop_t* loop); |
83 |
|
|
int Start(); |
84 |
|
|
void Close(); |
85 |
|
|
|
86 |
|
|
v8::Local<v8::Object> GetOutputAsBuffer(Environment* env) const; |
87 |
|
|
|
88 |
|
|
inline bool readable() const; |
89 |
|
|
inline bool writable() const; |
90 |
|
|
inline uv_stdio_flags uv_flags() const; |
91 |
|
|
|
92 |
|
|
inline uv_pipe_t* uv_pipe() const; |
93 |
|
|
inline uv_stream_t* uv_stream() const; |
94 |
|
|
inline uv_handle_t* uv_handle() const; |
95 |
|
|
|
96 |
|
|
private: |
97 |
|
|
inline size_t OutputLength() const; |
98 |
|
|
inline void CopyOutput(char* dest) const; |
99 |
|
|
|
100 |
|
|
inline void OnAlloc(size_t suggested_size, uv_buf_t* buf); |
101 |
|
|
inline void OnRead(const uv_buf_t* buf, ssize_t nread); |
102 |
|
|
inline void OnWriteDone(int result); |
103 |
|
|
inline void OnShutdownDone(int result); |
104 |
|
|
inline void OnClose(); |
105 |
|
|
|
106 |
|
|
inline void SetError(int error); |
107 |
|
|
|
108 |
|
|
static void AllocCallback(uv_handle_t* handle, |
109 |
|
|
size_t suggested_size, |
110 |
|
|
uv_buf_t* buf); |
111 |
|
|
static void ReadCallback(uv_stream_t* stream, |
112 |
|
|
ssize_t nread, |
113 |
|
|
const uv_buf_t* buf); |
114 |
|
|
static void WriteCallback(uv_write_t* req, int result); |
115 |
|
|
static void ShutdownCallback(uv_shutdown_t* req, int result); |
116 |
|
|
static void CloseCallback(uv_handle_t* handle); |
117 |
|
|
|
118 |
|
|
SyncProcessRunner* process_handler_; |
119 |
|
|
|
120 |
|
|
bool readable_; |
121 |
|
|
bool writable_; |
122 |
|
|
uv_buf_t input_buffer_; |
123 |
|
|
|
124 |
|
|
SyncProcessOutputBuffer* first_output_buffer_; |
125 |
|
|
SyncProcessOutputBuffer* last_output_buffer_; |
126 |
|
|
|
127 |
|
|
mutable uv_pipe_t uv_pipe_; |
128 |
|
|
uv_write_t write_req_; |
129 |
|
|
uv_shutdown_t shutdown_req_; |
130 |
|
|
|
131 |
|
|
Lifecycle lifecycle_; |
132 |
|
|
}; |
133 |
|
|
|
134 |
|
|
|
135 |
|
|
class SyncProcessRunner { |
136 |
|
|
enum Lifecycle { |
137 |
|
|
kUninitialized = 0, |
138 |
|
|
kInitialized, |
139 |
|
|
kHandlesClosed |
140 |
|
|
}; |
141 |
|
|
|
142 |
|
|
public: |
143 |
|
|
static void Initialize(v8::Local<v8::Object> target, |
144 |
|
|
v8::Local<v8::Value> unused, |
145 |
|
|
v8::Local<v8::Context> context, |
146 |
|
|
void* priv); |
147 |
|
|
static void Spawn(const v8::FunctionCallbackInfo<v8::Value>& args); |
148 |
|
|
|
149 |
|
|
private: |
150 |
|
|
friend class SyncProcessStdioPipe; |
151 |
|
|
|
152 |
|
|
explicit SyncProcessRunner(Environment* env_); |
153 |
|
|
~SyncProcessRunner(); |
154 |
|
|
|
155 |
|
|
inline Environment* env() const; |
156 |
|
|
|
157 |
|
|
v8::MaybeLocal<v8::Object> Run(v8::Local<v8::Value> options); |
158 |
|
|
v8::Maybe<bool> TryInitializeAndRunLoop(v8::Local<v8::Value> options); |
159 |
|
|
void CloseHandlesAndDeleteLoop(); |
160 |
|
|
|
161 |
|
|
void CloseStdioPipes(); |
162 |
|
|
void CloseKillTimer(); |
163 |
|
|
|
164 |
|
|
void Kill(); |
165 |
|
|
void IncrementBufferSizeAndCheckOverflow(ssize_t length); |
166 |
|
|
|
167 |
|
|
void OnExit(int64_t exit_status, int term_signal); |
168 |
|
|
void OnKillTimerTimeout(); |
169 |
|
|
|
170 |
|
|
int GetError(); |
171 |
|
|
void SetError(int error); |
172 |
|
|
void SetPipeError(int pipe_error); |
173 |
|
|
|
174 |
|
|
v8::Local<v8::Object> BuildResultObject(); |
175 |
|
|
v8::Local<v8::Array> BuildOutputArray(); |
176 |
|
|
|
177 |
|
|
v8::Maybe<int> ParseOptions(v8::Local<v8::Value> js_value); |
178 |
|
|
int ParseStdioOptions(v8::Local<v8::Value> js_value); |
179 |
|
|
int ParseStdioOption(int child_fd, v8::Local<v8::Object> js_stdio_option); |
180 |
|
|
|
181 |
|
|
inline int AddStdioIgnore(uint32_t child_fd); |
182 |
|
|
inline int AddStdioPipe(uint32_t child_fd, |
183 |
|
|
bool readable, |
184 |
|
|
bool writable, |
185 |
|
|
uv_buf_t input_buffer); |
186 |
|
|
inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd); |
187 |
|
|
|
188 |
|
|
static bool IsSet(v8::Local<v8::Value> value); |
189 |
|
|
v8::Maybe<int> CopyJsString(v8::Local<v8::Value> js_value, |
190 |
|
|
const char** target); |
191 |
|
|
v8::Maybe<int> CopyJsStringArray(v8::Local<v8::Value> js_value, |
192 |
|
|
char** target); |
193 |
|
|
|
194 |
|
|
static void ExitCallback(uv_process_t* handle, |
195 |
|
|
int64_t exit_status, |
196 |
|
|
int term_signal); |
197 |
|
|
static void KillTimerCallback(uv_timer_t* handle); |
198 |
|
|
static void KillTimerCloseCallback(uv_handle_t* handle); |
199 |
|
|
|
200 |
|
|
double max_buffer_; |
201 |
|
|
uint64_t timeout_; |
202 |
|
|
int kill_signal_; |
203 |
|
|
|
204 |
|
|
uv_loop_t* uv_loop_; |
205 |
|
|
|
206 |
|
|
uint32_t stdio_count_; |
207 |
|
|
uv_stdio_container_t* uv_stdio_containers_; |
208 |
|
|
std::vector<std::unique_ptr<SyncProcessStdioPipe>> stdio_pipes_; |
209 |
|
|
bool stdio_pipes_initialized_; |
210 |
|
|
|
211 |
|
|
uv_process_options_t uv_process_options_; |
212 |
|
|
const char* file_buffer_; |
213 |
|
|
char* args_buffer_; |
214 |
|
|
char* env_buffer_; |
215 |
|
|
const char* cwd_buffer_; |
216 |
|
|
|
217 |
|
|
uv_process_t uv_process_; |
218 |
|
|
bool killed_; |
219 |
|
|
|
220 |
|
|
size_t buffered_output_size_; |
221 |
|
|
int64_t exit_status_; |
222 |
|
|
int term_signal_; |
223 |
|
|
|
224 |
|
|
uv_timer_t uv_timer_; |
225 |
|
|
bool kill_timer_initialized_; |
226 |
|
|
|
227 |
|
|
// Errors that happen in one of the pipe handlers are stored in the |
228 |
|
|
// `pipe_error` field. They are treated as "low-priority", only to be |
229 |
|
|
// reported if no more serious errors happened. |
230 |
|
|
int error_; |
231 |
|
|
int pipe_error_; |
232 |
|
|
|
233 |
|
|
Lifecycle lifecycle_; |
234 |
|
|
|
235 |
|
|
Environment* env_; |
236 |
|
|
}; |
237 |
|
|
|
238 |
|
|
} // namespace node |
239 |
|
|
|
240 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
241 |
|
|
|
242 |
|
|
#endif // SRC_SPAWN_SYNC_H_ |