Browse Source

skelton of node.Process

v0.7.4-release
Ryan 16 years ago
parent
commit
83cb156b6f
  1. 2
      src/node.cc
  2. 225
      src/process.cc
  3. 45
      src/process.h
  4. 1
      wscript

2
src/node.cc

@ -4,6 +4,7 @@
#include "file.h" #include "file.h"
#include "http.h" #include "http.h"
#include "timer.h" #include "timer.h"
#include "process.h"
#include "constants.h" #include "constants.h"
#include "natives.h" #include "natives.h"
@ -302,6 +303,7 @@ Load (int argc, char *argv[])
NODE_SET_METHOD(node_obj, "reallyExit", node_exit); NODE_SET_METHOD(node_obj, "reallyExit", node_exit);
Timer::Initialize(node_obj); Timer::Initialize(node_obj);
Process::Initialize(node_obj);
DefineConstants(node_obj); DefineConstants(node_obj);

225
src/process.cc

@ -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);
}

45
src/process.h

@ -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

1
wscript

@ -158,6 +158,7 @@ def build(bld):
src/net.cc src/net.cc
src/file.cc src/file.cc
src/timer.cc src/timer.cc
src/process.cc
src/constants.cc src/constants.cc
""" """
node.includes = """ node.includes = """

Loading…
Cancel
Save