mirror of https://github.com/lukechilds/node.git
Ryan
16 years ago
4 changed files with 273 additions and 0 deletions
@ -0,0 +1,225 @@ |
|||||
|
#include "node.h" |
||||
|
#include "process.h" |
||||
|
|
||||
|
#include <assert.h> |
||||
|
#include <unistd.h> |
||||
|
#include <fcntl.h> |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
using namespace v8; |
||||
|
using namespace node; |
||||
|
|
||||
|
Persistent<FunctionTemplate> Process::constructor_template; |
||||
|
|
||||
|
void |
||||
|
Process::Initialize (Handle<Object> target) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
Local<FunctionTemplate> t = FunctionTemplate::New(Process::New); |
||||
|
constructor_template = Persistent<FunctionTemplate>::New(t); |
||||
|
constructor_template->InstanceTemplate()->SetInternalFieldCount(1); |
||||
|
|
||||
|
#if 0 |
||||
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "start", Timer::Start); |
||||
|
NODE_SET_PROTOTYPE_METHOD(constructor_template, "stop", Timer::Stop); |
||||
|
#endif |
||||
|
|
||||
|
target->Set(String::NewSymbol("Process"), constructor_template->GetFunction()); |
||||
|
} |
||||
|
|
||||
|
Handle<Value> |
||||
|
Process::New (const Arguments& args) |
||||
|
{ |
||||
|
if (args.Length() == 0) return Undefined(); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
String::Utf8Value command(args[0]->ToString()); |
||||
|
|
||||
|
Process *p = new Process(args.Holder()); |
||||
|
ObjectWrap::InformV8ofAllocation(p); |
||||
|
|
||||
|
int r = p->Spawn(*command); |
||||
|
if (r != 0) { |
||||
|
return ThrowException(String::New("Error spawning")); |
||||
|
} |
||||
|
|
||||
|
return args.This(); |
||||
|
} |
||||
|
|
||||
|
Process::Process (Handle<Object> handle) |
||||
|
: ObjectWrap(handle) |
||||
|
{ |
||||
|
ev_init(&stdout_watcher_, Process::OnOutput); |
||||
|
stdout_watcher_.data = this; |
||||
|
|
||||
|
ev_init(&stderr_watcher_, Process::OnError); |
||||
|
stderr_watcher_.data = this; |
||||
|
|
||||
|
ev_init(&stdin_watcher_, Process::OnWritable); |
||||
|
stdin_watcher_.data = this; |
||||
|
|
||||
|
ev_init(&child_watcher_, Process::OnCHLD); |
||||
|
child_watcher_.data = this; |
||||
|
|
||||
|
stdout_pipe_[0] = -1; |
||||
|
stdout_pipe_[1] = -1; |
||||
|
stderr_pipe_[0] = -1; |
||||
|
stderr_pipe_[1] = -1; |
||||
|
stdin_pipe_[0] = -1; |
||||
|
stdin_pipe_[1] = -1; |
||||
|
|
||||
|
pid_ = 0; |
||||
|
} |
||||
|
|
||||
|
Process::~Process () |
||||
|
{ |
||||
|
Shutdown(); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Process::Shutdown () |
||||
|
{ |
||||
|
if (stdout_pipe_[0] >= 0) close(stdout_pipe_[0]); |
||||
|
if (stdout_pipe_[1] >= 0) close(stdout_pipe_[1]); |
||||
|
|
||||
|
if (stderr_pipe_[0] >= 0) close(stderr_pipe_[0]); |
||||
|
if (stderr_pipe_[1] >= 0) close(stderr_pipe_[1]); |
||||
|
|
||||
|
if (stdin_pipe_[0] >= 0) close(stdin_pipe_[0]); |
||||
|
if (stdin_pipe_[1] >= 0) close(stdin_pipe_[1]); |
||||
|
|
||||
|
stdout_pipe_[0] = -1; |
||||
|
stdout_pipe_[1] = -1; |
||||
|
stderr_pipe_[0] = -1; |
||||
|
stderr_pipe_[1] = -1; |
||||
|
stdin_pipe_[0] = -1; |
||||
|
stdin_pipe_[1] = -1; |
||||
|
|
||||
|
ev_io_stop(EV_DEFAULT_UC_ &stdout_watcher_); |
||||
|
ev_io_stop(EV_DEFAULT_UC_ &stderr_watcher_); |
||||
|
ev_io_stop(EV_DEFAULT_UC_ &stdin_watcher_); |
||||
|
|
||||
|
ev_child_stop(EV_DEFAULT_UC_ &child_watcher_); |
||||
|
/* XXX Kill the PID? */ |
||||
|
pid_ = 0; |
||||
|
|
||||
|
Detach(); |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
SetNonBlocking (int fd) |
||||
|
{ |
||||
|
int flags = fcntl(fd, F_GETFL, 0); |
||||
|
int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); |
||||
|
if (r != 0) { |
||||
|
perror("SetNonBlocking()"); |
||||
|
} |
||||
|
return r; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
Process::Spawn (const char *command) |
||||
|
{ |
||||
|
assert(pid_ == 0); |
||||
|
assert(stdout_pipe_[0] == -1); |
||||
|
assert(stdout_pipe_[1] == -1); |
||||
|
assert(stderr_pipe_[0] == -1); |
||||
|
assert(stderr_pipe_[1] == -1); |
||||
|
assert(stdin_pipe_[0] == -1); |
||||
|
assert(stdin_pipe_[1] == -1); |
||||
|
|
||||
|
/* An implementation of popen(), basically */ |
||||
|
if (pipe(stdout_pipe_) < 0) { |
||||
|
perror("pipe()"); |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
if (pipe(stderr_pipe_) < 0) { |
||||
|
perror("pipe()"); |
||||
|
return -2; |
||||
|
} |
||||
|
|
||||
|
if (pipe(stdin_pipe_) < 0) { |
||||
|
perror("pipe()"); |
||||
|
return -3; |
||||
|
} |
||||
|
|
||||
|
switch (pid_ = vfork()) { |
||||
|
case -1: // Error.
|
||||
|
Shutdown(); |
||||
|
return -4; |
||||
|
|
||||
|
case 0: // Child.
|
||||
|
close(stdout_pipe_[0]); // close read end
|
||||
|
dup2(stdout_pipe_[1], STDOUT_FILENO); |
||||
|
|
||||
|
close(stderr_pipe_[0]); // close read end
|
||||
|
dup2(stderr_pipe_[1], STDERR_FILENO); |
||||
|
|
||||
|
close(stdin_pipe_[1]); // close write end
|
||||
|
dup2(stdin_pipe_[0], STDIN_FILENO); |
||||
|
|
||||
|
execl("/bin/sh", "-c", command, (char *)NULL); |
||||
|
_exit(127); |
||||
|
} |
||||
|
|
||||
|
// Parent.
|
||||
|
|
||||
|
ev_child_set(&child_watcher_, pid_, 0); |
||||
|
ev_child_start(EV_DEFAULT_UC_ &child_watcher_); |
||||
|
|
||||
|
SetNonBlocking(stdout_pipe_[0]); |
||||
|
SetNonBlocking(stderr_pipe_[0]); |
||||
|
SetNonBlocking(stdin_pipe_[1]); |
||||
|
|
||||
|
ev_io_set(&stdout_watcher_, stdout_pipe_[0], EV_READ); |
||||
|
ev_io_set(&stderr_watcher_, stderr_pipe_[0], EV_READ); |
||||
|
ev_io_set(&stdin_watcher_, stdin_pipe_[1], EV_WRITE); |
||||
|
|
||||
|
ev_io_start(EV_DEFAULT_UC_ &stdout_watcher_); |
||||
|
ev_io_start(EV_DEFAULT_UC_ &stderr_watcher_); |
||||
|
ev_io_start(EV_DEFAULT_UC_ &stdin_watcher_); |
||||
|
|
||||
|
close(stdout_pipe_[1]); // close write end
|
||||
|
close(stderr_pipe_[1]); // close write end
|
||||
|
close(stdin_pipe_[0]); // close read end
|
||||
|
|
||||
|
stdout_pipe_[1] = -1; |
||||
|
stderr_pipe_[1] = -1; |
||||
|
stdin_pipe_[0] = -1; |
||||
|
|
||||
|
Attach(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Process::OnOutput (EV_P_ ev_io *watcher, int revents) |
||||
|
{ |
||||
|
Process *process = static_cast<Process*>(watcher->data); |
||||
|
assert(revents == EV_READ); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Process::OnError (EV_P_ ev_io *watcher, int revents) |
||||
|
{ |
||||
|
Process *process = static_cast<Process*>(watcher->data); |
||||
|
assert(revents == EV_READ); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Process::OnWritable (EV_P_ ev_io *watcher, int revents) |
||||
|
{ |
||||
|
Process *process = static_cast<Process*>(watcher->data); |
||||
|
assert(revents == EV_WRITE); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
Process::OnCHLD (EV_P_ ev_child *watcher, int revents) |
||||
|
{ |
||||
|
ev_child_stop(EV_A_ watcher); |
||||
|
Process *process = static_cast<Process*>(watcher->data); |
||||
|
assert(revents == EV_CHILD); |
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
#ifndef node_process_h |
||||
|
#define node_process_h |
||||
|
|
||||
|
#include "node.h" |
||||
|
#include <v8.h> |
||||
|
#include <ev.h> |
||||
|
|
||||
|
namespace node { |
||||
|
|
||||
|
class Process : ObjectWrap { |
||||
|
public: |
||||
|
static void Initialize (v8::Handle<v8::Object> target); |
||||
|
|
||||
|
virtual size_t size (void) { return sizeof(Process); } |
||||
|
|
||||
|
protected: |
||||
|
static v8::Persistent<v8::FunctionTemplate> constructor_template; |
||||
|
static v8::Handle<v8::Value> New (const v8::Arguments& args); |
||||
|
|
||||
|
Process(v8::Handle<v8::Object> handle); |
||||
|
~Process(); |
||||
|
|
||||
|
void Shutdown (); |
||||
|
int Spawn (const char *command); |
||||
|
|
||||
|
private: |
||||
|
static void OnOutput (EV_P_ ev_io *watcher, int revents); |
||||
|
static void OnError (EV_P_ ev_io *watcher, int revents); |
||||
|
static void OnWritable (EV_P_ ev_io *watcher, int revents); |
||||
|
static void OnCHLD (EV_P_ ev_child *watcher, int revents); |
||||
|
|
||||
|
ev_io stdout_watcher_; |
||||
|
ev_io stderr_watcher_; |
||||
|
ev_io stdin_watcher_; |
||||
|
ev_child child_watcher_; |
||||
|
|
||||
|
int stdout_pipe_[2]; |
||||
|
int stderr_pipe_[2]; |
||||
|
int stdin_pipe_[2]; |
||||
|
|
||||
|
pid_t pid_; |
||||
|
}; |
||||
|
|
||||
|
} // namespace node
|
||||
|
#endif // node_process_h
|
Loading…
Reference in new issue