mirror of https://github.com/lukechilds/node.git
Browse Source
This implements a nested event loop that makes it possible to control a child process, while blocking the main loop until the process exits.v0.11.12-release
Bert Belder
11 years ago
4 changed files with 1311 additions and 0 deletions
File diff suppressed because it is too large
@ -0,0 +1,247 @@ |
|||||
|
// 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_ |
||||
|
|
||||
|
#include "node.h" |
||||
|
#include "node_buffer.h" |
||||
|
|
||||
|
namespace node { |
||||
|
|
||||
|
using v8::Array; |
||||
|
using v8::Context; |
||||
|
using v8::FunctionCallbackInfo; |
||||
|
using v8::Handle; |
||||
|
using v8::HandleScope; |
||||
|
using v8::Integer; |
||||
|
using v8::Isolate; |
||||
|
using v8::Local; |
||||
|
using v8::Null; |
||||
|
using v8::Number; |
||||
|
using v8::Object; |
||||
|
using v8::String; |
||||
|
using v8::Value; |
||||
|
|
||||
|
|
||||
|
class SyncProcessOutputBuffer; |
||||
|
class SyncProcessStdioPipe; |
||||
|
class SyncProcessRunner; |
||||
|
|
||||
|
|
||||
|
class SyncProcessOutputBuffer { |
||||
|
static const unsigned int kBufferSize = 65536; |
||||
|
|
||||
|
public: |
||||
|
inline SyncProcessOutputBuffer(); |
||||
|
|
||||
|
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_; |
||||
|
|
||||
|
SyncProcessOutputBuffer* next_; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
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(); |
||||
|
|
||||
|
Local<Object> GetOutputAsBuffer() 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(Handle<Object> target, |
||||
|
Handle<Value> unused, |
||||
|
Handle<Context> context); |
||||
|
static void Spawn(const FunctionCallbackInfo<Value>& args); |
||||
|
|
||||
|
private: |
||||
|
friend class SyncProcessStdioPipe; |
||||
|
|
||||
|
explicit SyncProcessRunner(Environment* env_); |
||||
|
~SyncProcessRunner(); |
||||
|
|
||||
|
inline Environment* env() const; |
||||
|
|
||||
|
Local<Object> Run(Local<Value> options); |
||||
|
void TryInitializeAndRunLoop(Local<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 status); |
||||
|
|
||||
|
int GetError(); |
||||
|
void SetError(int error); |
||||
|
void SetPipeError(int pipe_error); |
||||
|
|
||||
|
Local<Object> BuildResultObject(); |
||||
|
Local<Array> BuildOutputArray(); |
||||
|
|
||||
|
int ParseOptions(Local<Value> js_value); |
||||
|
int ParseStdioOptions(Local<Value> js_value); |
||||
|
int ParseStdioOption(int child_fd, Local<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(Local<Value> value); |
||||
|
template <typename t> static bool CheckRange(Local<Value> js_value); |
||||
|
static int CopyJsString(Local<Value> js_value, const char** target); |
||||
|
static int CopyJsStringArray(Local<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, int status); |
||||
|
static void KillTimerCloseCallback(uv_handle_t* handle); |
||||
|
|
||||
|
size_t max_buffer_; |
||||
|
uint64_t timeout_; |
||||
|
int kill_signal_; |
||||
|
|
||||
|
uv_loop_t* uv_loop_; |
||||
|
|
||||
|
uint32_t stdio_count_; |
||||
|
uv_stdio_container_t* uv_stdio_containers_; |
||||
|
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_; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
#endif // SRC_SPAWN_SYNC_H_
|
Loading…
Reference in new issue