| // Copyright Joyent, Inc. and other Node contributors. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the |
| // "Software"), to deal in the Software without restriction, including |
| // without limitation the rights to use, copy, modify, merge, publish, |
| // distribute, sublicense, and/or sell copies of the Software, and to permit |
| // persons to whom the Software is furnished to do so, subject to the |
| // following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included |
| // in all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| #ifndef SRC_SPAWN_SYNC_H_ |
| #define SRC_SPAWN_SYNC_H_ |
| |
| #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
| |
| #include "node_buffer.h" |
| #include "uv.h" |
| #include "v8.h" |
| |
| namespace node { |
| |
| |
| |
| class SyncProcessOutputBuffer; |
| class SyncProcessStdioPipe; |
| class SyncProcessRunner; |
| |
| |
| class SyncProcessOutputBuffer { |
| static const unsigned int kBufferSize = 65536; |
| |
| public: |
| inline SyncProcessOutputBuffer() = default; |
| |
| inline void OnAlloc(size_t suggested_size, uv_buf_t* buf) const; |
| inline void OnRead(const uv_buf_t* buf, size_t nread); |
| |
| inline size_t Copy(char* dest) const; |
| |
| inline unsigned int available() const; |
| inline unsigned int used() const; |
| |
| inline SyncProcessOutputBuffer* next() const; |
| inline void set_next(SyncProcessOutputBuffer* next); |
| |
| private: |
| // Use unsigned int because that's what `uv_buf_init` takes. |
| mutable char data_[kBufferSize]; |
| unsigned int used_ = 0; |
| |
| SyncProcessOutputBuffer* next_ = nullptr; |
| }; |
| |
| |
| class SyncProcessStdioPipe { |
| enum Lifecycle { |
| kUninitialized = 0, |
| kInitialized, |
| kStarted, |
| kClosing, |
| kClosed |
| }; |
| |
| public: |
| SyncProcessStdioPipe(SyncProcessRunner* process_handler, |
| bool readable, |
| bool writable, |
| uv_buf_t input_buffer); |
| ~SyncProcessStdioPipe(); |
| |
| int Initialize(uv_loop_t* loop); |
| int Start(); |
| void Close(); |
| |
| v8::Local<v8::Object> GetOutputAsBuffer(Environment* env) const; |
| |
| inline bool readable() const; |
| inline bool writable() const; |
| inline uv_stdio_flags uv_flags() const; |
| |
| inline uv_pipe_t* uv_pipe() const; |
| inline uv_stream_t* uv_stream() const; |
| inline uv_handle_t* uv_handle() const; |
| |
| private: |
| inline size_t OutputLength() const; |
| inline void CopyOutput(char* dest) const; |
| |
| inline void OnAlloc(size_t suggested_size, uv_buf_t* buf); |
| inline void OnRead(const uv_buf_t* buf, ssize_t nread); |
| inline void OnWriteDone(int result); |
| inline void OnShutdownDone(int result); |
| inline void OnClose(); |
| |
| inline void SetError(int error); |
| |
| static void AllocCallback(uv_handle_t* handle, |
| size_t suggested_size, |
| uv_buf_t* buf); |
| static void ReadCallback(uv_stream_t* stream, |
| ssize_t nread, |
| const uv_buf_t* buf); |
| static void WriteCallback(uv_write_t* req, int result); |
| static void ShutdownCallback(uv_shutdown_t* req, int result); |
| static void CloseCallback(uv_handle_t* handle); |
| |
| SyncProcessRunner* process_handler_; |
| |
| bool readable_; |
| bool writable_; |
| uv_buf_t input_buffer_; |
| |
| SyncProcessOutputBuffer* first_output_buffer_; |
| SyncProcessOutputBuffer* last_output_buffer_; |
| |
| mutable uv_pipe_t uv_pipe_; |
| uv_write_t write_req_; |
| uv_shutdown_t shutdown_req_; |
| |
| Lifecycle lifecycle_; |
| }; |
| |
| |
| class SyncProcessRunner { |
| enum Lifecycle { |
| kUninitialized = 0, |
| kInitialized, |
| kHandlesClosed |
| }; |
| |
| public: |
| static void Initialize(v8::Local<v8::Object> target, |
| v8::Local<v8::Value> unused, |
| v8::Local<v8::Context> context, |
| void* priv); |
| static void Spawn(const v8::FunctionCallbackInfo<v8::Value>& args); |
| |
| private: |
| friend class SyncProcessStdioPipe; |
| |
| explicit SyncProcessRunner(Environment* env_); |
| ~SyncProcessRunner(); |
| |
| inline Environment* env() const; |
| |
| v8::MaybeLocal<v8::Object> Run(v8::Local<v8::Value> options); |
| v8::Maybe<bool> TryInitializeAndRunLoop(v8::Local<v8::Value> options); |
| void CloseHandlesAndDeleteLoop(); |
| |
| void CloseStdioPipes(); |
| void CloseKillTimer(); |
| |
| void Kill(); |
| void IncrementBufferSizeAndCheckOverflow(ssize_t length); |
| |
| void OnExit(int64_t exit_status, int term_signal); |
| void OnKillTimerTimeout(); |
| |
| int GetError(); |
| void SetError(int error); |
| void SetPipeError(int pipe_error); |
| |
| v8::Local<v8::Object> BuildResultObject(); |
| v8::Local<v8::Array> BuildOutputArray(); |
| |
| v8::Maybe<int> ParseOptions(v8::Local<v8::Value> js_value); |
| int ParseStdioOptions(v8::Local<v8::Value> js_value); |
| int ParseStdioOption(int child_fd, v8::Local<v8::Object> js_stdio_option); |
| |
| inline int AddStdioIgnore(uint32_t child_fd); |
| inline int AddStdioPipe(uint32_t child_fd, |
| bool readable, |
| bool writable, |
| uv_buf_t input_buffer); |
| inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd); |
| |
| static bool IsSet(v8::Local<v8::Value> value); |
| v8::Maybe<int> CopyJsString(v8::Local<v8::Value> js_value, |
| const char** target); |
| v8::Maybe<int> CopyJsStringArray(v8::Local<v8::Value> js_value, |
| char** target); |
| |
| static void ExitCallback(uv_process_t* handle, |
| int64_t exit_status, |
| int term_signal); |
| static void KillTimerCallback(uv_timer_t* handle); |
| static void KillTimerCloseCallback(uv_handle_t* handle); |
| |
| double max_buffer_; |
| uint64_t timeout_; |
| int kill_signal_; |
| |
| uv_loop_t* uv_loop_; |
| |
| uint32_t stdio_count_; |
| uv_stdio_container_t* uv_stdio_containers_; |
| std::vector<std::unique_ptr<SyncProcessStdioPipe>> stdio_pipes_; |
| bool stdio_pipes_initialized_; |
| |
| uv_process_options_t uv_process_options_; |
| const char* file_buffer_; |
| char* args_buffer_; |
| char* env_buffer_; |
| const char* cwd_buffer_; |
| |
| uv_process_t uv_process_; |
| bool killed_; |
| |
| size_t buffered_output_size_; |
| int64_t exit_status_; |
| int term_signal_; |
| |
| uv_timer_t uv_timer_; |
| bool kill_timer_initialized_; |
| |
| // Errors that happen in one of the pipe handlers are stored in the |
| // `pipe_error` field. They are treated as "low-priority", only to be |
| // reported if no more serious errors happened. |
| int error_; |
| int pipe_error_; |
| |
| Lifecycle lifecycle_; |
| |
| Environment* env_; |
| }; |
| |
| } // namespace node |
| |
| #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
| |
| #endif // SRC_SPAWN_SYNC_H_ |