// Copyright 2009 Ryan Dahl #ifndef NODE_CHILD_PROCESS_H_ #define NODE_CHILD_PROCESS_H_ #include #include #include #include #ifdef __MINGW32__ # include // HANDLE type #endif // ChildProcess is a thin wrapper around ev_child. It has the extra // functionality that it can spawn a child process with pipes connected to // its stdin, stdout, stderr. This class is not meant to be exposed to but // wrapped up in a more friendly EventEmitter with streams for each of the // pipes. // // When the child process exits (when the parent receives SIGCHLD) the // callback child.onexit will be called. namespace node { class ChildProcess : ObjectWrap { public: static void Initialize(v8::Handle target); protected: static v8::Handle New(const v8::Arguments& args); static v8::Handle Spawn(const v8::Arguments& args); static v8::Handle Kill(const v8::Arguments& args); ChildProcess() : ObjectWrap() { #ifdef __POSIX__ ev_init(&child_watcher_, ChildProcess::on_chld); child_watcher_.data = this; #endif // __POSIX__ pid_ = -1; #ifdef __MINGW32__ InitializeCriticalSection(&info_lock_); kill_me_ = false; did_start_ = false; exit_signal_ = 0; #endif // __MINGW32__ } ~ChildProcess() { #ifdef __POSIX__ Stop(); #endif // __POSIX__ } // Returns 0 on success. stdio_fds will contain file desciptors for stdin, // stdout, and stderr of the subprocess. stdin is writable; the other two // are readable. // The user of this class has responsibility to close these pipes after // the child process exits. int Spawn(const char *file, char *const argv[], const char *cwd, char **env, int stdio_fds[3], int custom_fds[3], bool do_setsid, int custom_uid, char *custom_uname, int custom_gid, char *custom_gname); // Simple syscall wrapper. Does not disable the watcher. onexit will be // called still. int Kill(int sig); private: void OnExit(int code); #ifdef __POSIX__ // Shouldn't this just move to node_child_process.cc? void Stop(void); static void on_chld(EV_P_ ev_child *watcher, int revents) { ChildProcess *child = static_cast(watcher->data); assert(revents == EV_CHILD); assert(child->pid_ == watcher->rpid); assert(&child->child_watcher_ == watcher); child->OnExit(watcher->rstatus); } ev_child child_watcher_; pid_t pid_; #endif // __POSIX__ #ifdef __MINGW32__ static int do_spawn(eio_req *req); static int after_spawn(eio_req *req); static void watch(ChildProcess *child); static void CALLBACK watch_wait_callback(void *data, BOOLEAN didTimeout); static void notify_spawn_failure(ChildProcess *child); static void notify_exit(EV_P_ ev_async *ev, int revent); static int do_kill(ChildProcess *child, int sig);static void close_stdio_handles(ChildProcess *child); int pid_; int exit_signal_; WCHAR *application_; WCHAR *arguments_; WCHAR *env_win_; WCHAR *cwd_; const WCHAR *path_; const WCHAR *path_ext_; HANDLE stdio_handles_[3]; bool got_custom_fds_[3]; CRITICAL_SECTION info_lock_; bool did_start_; bool kill_me_; HANDLE wait_handle_; HANDLE process_handle_; #endif // __MINGW32__ }; } // namespace node #endif // NODE_CHILD_PROCESS_H_