/src/node/src/spawn_sync.h
Line | Count | Source |
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 | | class ExternalReferenceRegistry; |
34 | | class SyncProcessOutputBuffer; |
35 | | class SyncProcessStdioPipe; |
36 | | class SyncProcessRunner; |
37 | | |
38 | | |
39 | | class SyncProcessOutputBuffer { |
40 | | static const unsigned int kBufferSize = 65536; |
41 | | |
42 | | public: |
43 | 0 | inline SyncProcessOutputBuffer() = default; |
44 | | |
45 | | inline void OnAlloc(size_t suggested_size, uv_buf_t* buf) const; |
46 | | inline void OnRead(const uv_buf_t* buf, size_t nread); |
47 | | |
48 | | inline size_t Copy(char* dest) const; |
49 | | |
50 | | inline unsigned int available() const; |
51 | | inline unsigned int used() const; |
52 | | |
53 | | inline SyncProcessOutputBuffer* next() const; |
54 | | inline void set_next(SyncProcessOutputBuffer* next); |
55 | | |
56 | | private: |
57 | | // Use unsigned int because that's what `uv_buf_init` takes. |
58 | | mutable char data_[kBufferSize]; |
59 | | unsigned int used_ = 0; |
60 | | |
61 | | SyncProcessOutputBuffer* next_ = nullptr; |
62 | | }; |
63 | | |
64 | | |
65 | | class SyncProcessStdioPipe { |
66 | | enum Lifecycle { |
67 | | kUninitialized = 0, |
68 | | kInitialized, |
69 | | kStarted, |
70 | | kClosing, |
71 | | kClosed |
72 | | }; |
73 | | |
74 | | public: |
75 | | SyncProcessStdioPipe(SyncProcessRunner* process_handler, |
76 | | bool readable, |
77 | | bool writable, |
78 | | uv_buf_t input_buffer); |
79 | | ~SyncProcessStdioPipe(); |
80 | | |
81 | | int Initialize(uv_loop_t* loop); |
82 | | int Start(); |
83 | | void Close(); |
84 | | |
85 | | v8::MaybeLocal<v8::Object> GetOutputAsBuffer(Environment* env) const; |
86 | | |
87 | | inline bool readable() const; |
88 | | inline bool writable() const; |
89 | | inline uv_stdio_flags uv_flags() const; |
90 | | |
91 | | inline uv_pipe_t* uv_pipe() const; |
92 | | inline uv_stream_t* uv_stream() const; |
93 | | inline uv_handle_t* uv_handle() const; |
94 | | |
95 | | private: |
96 | | inline size_t OutputLength() const; |
97 | | inline void CopyOutput(char* dest) const; |
98 | | |
99 | | inline void OnAlloc(size_t suggested_size, uv_buf_t* buf); |
100 | | inline void OnRead(const uv_buf_t* buf, ssize_t nread); |
101 | | inline void OnWriteDone(int result); |
102 | | inline void OnShutdownDone(int result); |
103 | | inline void OnClose(); |
104 | | |
105 | | inline void SetError(int error); |
106 | | |
107 | | static void AllocCallback(uv_handle_t* handle, |
108 | | size_t suggested_size, |
109 | | uv_buf_t* buf); |
110 | | static void ReadCallback(uv_stream_t* stream, |
111 | | ssize_t nread, |
112 | | const uv_buf_t* buf); |
113 | | static void WriteCallback(uv_write_t* req, int result); |
114 | | static void ShutdownCallback(uv_shutdown_t* req, int result); |
115 | | static void CloseCallback(uv_handle_t* handle); |
116 | | |
117 | | SyncProcessRunner* process_handler_; |
118 | | |
119 | | bool readable_; |
120 | | bool writable_; |
121 | | uv_buf_t input_buffer_; |
122 | | |
123 | | SyncProcessOutputBuffer* first_output_buffer_; |
124 | | SyncProcessOutputBuffer* last_output_buffer_; |
125 | | |
126 | | mutable uv_pipe_t uv_pipe_; |
127 | | uv_write_t write_req_; |
128 | | uv_shutdown_t shutdown_req_; |
129 | | |
130 | | Lifecycle lifecycle_; |
131 | | }; |
132 | | |
133 | | |
134 | | class SyncProcessRunner { |
135 | | enum Lifecycle { |
136 | | kUninitialized = 0, |
137 | | kInitialized, |
138 | | kHandlesClosed |
139 | | }; |
140 | | |
141 | | public: |
142 | | static void RegisterExternalReferences(ExternalReferenceRegistry* registry); |
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<void> 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::MaybeLocal<v8::Object> BuildResultObject(); |
175 | | v8::MaybeLocal<v8::Array> BuildOutputArray(); |
176 | | |
177 | | v8::Maybe<int> ParseOptions(v8::Local<v8::Value> js_value); |
178 | | v8::Maybe<int> ParseStdioOptions(v8::Local<v8::Value> js_value); |
179 | | v8::Maybe<int> ParseStdioOption(int child_fd, |
180 | | v8::Local<v8::Object> js_stdio_option); |
181 | | |
182 | | inline int AddStdioIgnore(uint32_t child_fd); |
183 | | inline int AddStdioPipe(uint32_t child_fd, |
184 | | bool readable, |
185 | | bool writable, |
186 | | uv_buf_t input_buffer); |
187 | | inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd); |
188 | | |
189 | | static bool IsSet(v8::Local<v8::Value> value); |
190 | | v8::Maybe<int> CopyJsString(v8::Local<v8::Value> js_value, |
191 | | const char** target); |
192 | | v8::Maybe<int> CopyJsStringArray(v8::Local<v8::Value> js_value, |
193 | | char** target); |
194 | | |
195 | | static void ExitCallback(uv_process_t* handle, |
196 | | int64_t exit_status, |
197 | | int term_signal); |
198 | | static void KillTimerCallback(uv_timer_t* handle); |
199 | | static void KillTimerCloseCallback(uv_handle_t* handle); |
200 | | |
201 | | double max_buffer_; |
202 | | uint64_t timeout_; |
203 | | int kill_signal_; |
204 | | |
205 | | uv_loop_t* uv_loop_; |
206 | | |
207 | | uint32_t stdio_count_; |
208 | | std::vector<uv_stdio_container_t> uv_stdio_containers_; |
209 | | std::vector<std::unique_ptr<SyncProcessStdioPipe>> stdio_pipes_; |
210 | | bool stdio_pipes_initialized_; |
211 | | |
212 | | uv_process_options_t uv_process_options_; |
213 | | std::unique_ptr<const char[]> file_buffer_; |
214 | | std::unique_ptr<char[]> args_buffer_; |
215 | | std::unique_ptr<char[]> env_buffer_; |
216 | | std::unique_ptr<const char[]> cwd_buffer_; |
217 | | |
218 | | uv_process_t uv_process_; |
219 | | bool killed_; |
220 | | |
221 | | size_t buffered_output_size_; |
222 | | int64_t exit_status_; |
223 | | int term_signal_; |
224 | | |
225 | | uv_timer_t uv_timer_; |
226 | | bool kill_timer_initialized_; |
227 | | |
228 | | // Errors that happen in one of the pipe handlers are stored in the |
229 | | // `pipe_error` field. They are treated as "low-priority", only to be |
230 | | // reported if no more serious errors happened. |
231 | | int error_; |
232 | | int pipe_error_; |
233 | | |
234 | | Lifecycle lifecycle_; |
235 | | |
236 | | Environment* env_; |
237 | | }; |
238 | | |
239 | | } // namespace node |
240 | | |
241 | | #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
242 | | |
243 | | #endif // SRC_SPAWN_SYNC_H_ |