#include <stdio.h>
#include <stdlib.h>
+#include <strings.h>
#include <string.h>
#include <limits.h> /* PATH_MAX */
#include <assert.h>
#include <node_io_watcher.h>
#include <node_net2.h>
#include <node_events.h>
-#include <node_dns.h>
-#include <node_net.h>
+#include <node_cares.h>
#include <node_file.h>
-#include <node_idle_watcher.h>
-#include <node_http.h>
+#if 0
+// not in use
+# include <node_idle_watcher.h>
+#endif
#include <node_http_parser.h>
-#include <node_signal_handler.h>
-#include <node_stat.h>
+#include <node_signal_watcher.h>
+#include <node_stat_watcher.h>
#include <node_timer.h>
#include <node_child_process.h>
#include <node_constants.h>
#include <node_stdio.h>
#include <node_natives.h>
#include <node_version.h>
+#ifdef HAVE_OPENSSL
+#include <node_crypto.h>
+#endif
+#include <node_script.h>
#include <v8-debug.h>
static Persistent<Object> process;
+static Persistent<String> errno_symbol;
+static Persistent<String> syscall_symbol;
+
static Persistent<String> dev_symbol;
static Persistent<String> ino_symbol;
static Persistent<String> mode_symbol;
static bool debug_wait_connect = false;
static int debug_port=5858;
+static ev_prepare next_tick_watcher;
+static ev_idle tick_spinner;
+static bool need_tick_cb;
+static Persistent<String> tick_callback_sym;
static ev_async eio_want_poll_notifier;
static ev_async eio_done_poll_notifier;
static ev_idle eio_poller;
-static ev_timer gc_timer;
-#define GC_INTERVAL 2.0
+// We need to notify V8 when we're idle so that it can run the garbage
+// collector. The interface to this is V8::IdleNotification(). It returns
+// true if the heap hasn't be fully compacted, and needs to be run again.
+// Returning false means that it doesn't have anymore work to do.
+//
+// A rather convoluted algorithm has been devised to determine when Node is
+// idle. You'll have to figure it out for yourself.
+static ev_check gc_check;
+static ev_idle gc_idle;
+static ev_timer gc_timer;
+bool need_gc;
+
+
+#define FAST_TICK 0.7
+#define GC_WAIT_TIME 5.
+#define RPM_SAMPLES 100
+#define TICK_TIME(n) tick_times[(tick_time_head - (n)) % RPM_SAMPLES]
+static ev_tstamp tick_times[RPM_SAMPLES];
+static int tick_time_head;
+
+static void StartGCTimer () {
+ if (!ev_is_active(&gc_timer)) {
+ ev_timer_start(EV_DEFAULT_UC_ &gc_timer);
+ ev_unref(EV_DEFAULT_UC);
+ }
+}
+static void StopGCTimer () {
+ if (ev_is_active(&gc_timer)) {
+ ev_ref(EV_DEFAULT_UC);
+ ev_timer_stop(EV_DEFAULT_UC_ &gc_timer);
+ }
+}
-// Node calls this every GC_INTERVAL seconds in order to try and call the
-// GC. This watcher is run with maximum priority, so ev_pending_count() == 0
-// is an effective measure of idleness.
-static void GCTimeout(EV_P_ ev_timer *watcher, int revents) {
- assert(watcher == &gc_timer);
- assert(revents == EV_TIMER);
- if (ev_pending_count(EV_DEFAULT_UC) == 0) V8::IdleNotification();
+static void Idle(EV_P_ ev_idle *watcher, int revents) {
+ assert(watcher == &gc_idle);
+ assert(revents == EV_IDLE);
+
+ //fprintf(stderr, "idle\n");
+
+ if (V8::IdleNotification()) {
+ ev_idle_stop(EV_A_ watcher);
+ StopGCTimer();
+ }
+}
+
+
+// Called directly after every call to select() (or epoll, or whatever)
+static void Check(EV_P_ ev_check *watcher, int revents) {
+ assert(watcher == &gc_check);
+ assert(revents == EV_CHECK);
+
+ tick_times[tick_time_head] = ev_now(EV_DEFAULT_UC);
+ tick_time_head = (tick_time_head + 1) % RPM_SAMPLES;
+
+ StartGCTimer();
+
+ for (int i = 0; i < (int)(GC_WAIT_TIME/FAST_TICK); i++) {
+ double d = TICK_TIME(i+1) - TICK_TIME(i+2);
+ //printf("d = %f\n", d);
+ // If in the last 5 ticks the difference between
+ // ticks was less than 0.7 seconds, then continue.
+ if (d < FAST_TICK) {
+ //printf("---\n");
+ return;
+ }
+ }
+
+ // Otherwise start the gc!
+
+ //fprintf(stderr, "start idle 2\n");
+ ev_idle_start(EV_A_ &gc_idle);
+}
+
+
+static Handle<Value> NeedTickCallback(const Arguments& args) {
+ HandleScope scope;
+ need_tick_cb = true;
+ ev_idle_start(EV_DEFAULT_UC_ &tick_spinner);
+ return Undefined();
+}
+
+
+static void Spin(EV_P_ ev_idle *watcher, int revents) {
+ assert(watcher == &tick_spinner);
+ assert(revents == EV_IDLE);
+}
+
+
+static void Tick(EV_P_ ev_prepare *watcher, int revents) {
+ assert(watcher == &next_tick_watcher);
+ assert(revents == EV_PREPARE);
+
+ // Avoid entering a V8 scope.
+ if (!need_tick_cb) return;
+
+ need_tick_cb = false;
+ ev_idle_stop(EV_DEFAULT_UC_ &tick_spinner);
+
+ HandleScope scope;
+
+ if (tick_callback_sym.IsEmpty()) {
+ // Lazily set the symbol
+ tick_callback_sym =
+ Persistent<String>::New(String::NewSymbol("_tickCallback"));
+ }
+
+ Local<Value> cb_v = process->Get(tick_callback_sym);
+ if (!cb_v->IsFunction()) return;
+ Local<Function> cb = Local<Function>::Cast(cb_v);
+
+ TryCatch try_catch;
+
+ cb->Call(process, 0, NULL);
+
+ if (try_catch.HasCaught()) {
+ FatalException(try_catch);
+ }
}
}
+static inline const char *errno_string(int errorno) {
+#define ERRNO_CASE(e) case e: return #e;
+ switch (errorno) {
+
+#ifdef EACCES
+ ERRNO_CASE(EACCES);
+#endif
+
+#ifdef EADDRINUSE
+ ERRNO_CASE(EADDRINUSE);
+#endif
+
+#ifdef EADDRNOTAVAIL
+ ERRNO_CASE(EADDRNOTAVAIL);
+#endif
+
+#ifdef EAFNOSUPPORT
+ ERRNO_CASE(EAFNOSUPPORT);
+#endif
+
+#ifdef EAGAIN
+ ERRNO_CASE(EAGAIN);
+#endif
+
+#ifdef EWOULDBLOCK
+# if EAGAIN != EWOULDBLOCK
+ ERRNO_CASE(EWOULDBLOCK);
+# endif
+#endif
+
+#ifdef EALREADY
+ ERRNO_CASE(EALREADY);
+#endif
+
+#ifdef EBADF
+ ERRNO_CASE(EBADF);
+#endif
+
+#ifdef EBADMSG
+ ERRNO_CASE(EBADMSG);
+#endif
+
+#ifdef EBUSY
+ ERRNO_CASE(EBUSY);
+#endif
+
+#ifdef ECANCELED
+ ERRNO_CASE(ECANCELED);
+#endif
+
+#ifdef ECHILD
+ ERRNO_CASE(ECHILD);
+#endif
+
+#ifdef ECONNABORTED
+ ERRNO_CASE(ECONNABORTED);
+#endif
+
+#ifdef ECONNREFUSED
+ ERRNO_CASE(ECONNREFUSED);
+#endif
+
+#ifdef ECONNRESET
+ ERRNO_CASE(ECONNRESET);
+#endif
+
+#ifdef EDEADLK
+ ERRNO_CASE(EDEADLK);
+#endif
+
+#ifdef EDESTADDRREQ
+ ERRNO_CASE(EDESTADDRREQ);
+#endif
+
+#ifdef EDOM
+ ERRNO_CASE(EDOM);
+#endif
+
+#ifdef EDQUOT
+ ERRNO_CASE(EDQUOT);
+#endif
+
+#ifdef EEXIST
+ ERRNO_CASE(EEXIST);
+#endif
+
+#ifdef EFAULT
+ ERRNO_CASE(EFAULT);
+#endif
+
+#ifdef EFBIG
+ ERRNO_CASE(EFBIG);
+#endif
+
+#ifdef EHOSTUNREACH
+ ERRNO_CASE(EHOSTUNREACH);
+#endif
+
+#ifdef EIDRM
+ ERRNO_CASE(EIDRM);
+#endif
+
+#ifdef EILSEQ
+ ERRNO_CASE(EILSEQ);
+#endif
+
+#ifdef EINPROGRESS
+ ERRNO_CASE(EINPROGRESS);
+#endif
+
+#ifdef EINTR
+ ERRNO_CASE(EINTR);
+#endif
+
+#ifdef EINVAL
+ ERRNO_CASE(EINVAL);
+#endif
+
+#ifdef EIO
+ ERRNO_CASE(EIO);
+#endif
+
+#ifdef EISCONN
+ ERRNO_CASE(EISCONN);
+#endif
+
+#ifdef EISDIR
+ ERRNO_CASE(EISDIR);
+#endif
+
+#ifdef ELOOP
+ ERRNO_CASE(ELOOP);
+#endif
+
+#ifdef EMFILE
+ ERRNO_CASE(EMFILE);
+#endif
+
+#ifdef EMLINK
+ ERRNO_CASE(EMLINK);
+#endif
+
+#ifdef EMSGSIZE
+ ERRNO_CASE(EMSGSIZE);
+#endif
+
+#ifdef EMULTIHOP
+ ERRNO_CASE(EMULTIHOP);
+#endif
+
+#ifdef ENAMETOOLONG
+ ERRNO_CASE(ENAMETOOLONG);
+#endif
+
+#ifdef ENETDOWN
+ ERRNO_CASE(ENETDOWN);
+#endif
+
+#ifdef ENETRESET
+ ERRNO_CASE(ENETRESET);
+#endif
+
+#ifdef ENETUNREACH
+ ERRNO_CASE(ENETUNREACH);
+#endif
+
+#ifdef ENFILE
+ ERRNO_CASE(ENFILE);
+#endif
+
+#ifdef ENOBUFS
+ ERRNO_CASE(ENOBUFS);
+#endif
+
+#ifdef ENODATA
+ ERRNO_CASE(ENODATA);
+#endif
+
+#ifdef ENODEV
+ ERRNO_CASE(ENODEV);
+#endif
+
+#ifdef ENOENT
+ ERRNO_CASE(ENOENT);
+#endif
+
+#ifdef ENOEXEC
+ ERRNO_CASE(ENOEXEC);
+#endif
+
+#ifdef ENOLINK
+ ERRNO_CASE(ENOLINK);
+#endif
+
+#ifdef ENOLCK
+# if ENOLINK != ENOLCK
+ ERRNO_CASE(ENOLCK);
+# endif
+#endif
+
+#ifdef ENOMEM
+ ERRNO_CASE(ENOMEM);
+#endif
+
+#ifdef ENOMSG
+ ERRNO_CASE(ENOMSG);
+#endif
+
+#ifdef ENOPROTOOPT
+ ERRNO_CASE(ENOPROTOOPT);
+#endif
+
+#ifdef ENOSPC
+ ERRNO_CASE(ENOSPC);
+#endif
+
+#ifdef ENOSR
+ ERRNO_CASE(ENOSR);
+#endif
+
+#ifdef ENOSTR
+ ERRNO_CASE(ENOSTR);
+#endif
+
+#ifdef ENOSYS
+ ERRNO_CASE(ENOSYS);
+#endif
+
+#ifdef ENOTCONN
+ ERRNO_CASE(ENOTCONN);
+#endif
+
+#ifdef ENOTDIR
+ ERRNO_CASE(ENOTDIR);
+#endif
+
+#ifdef ENOTEMPTY
+ ERRNO_CASE(ENOTEMPTY);
+#endif
+
+#ifdef ENOTSOCK
+ ERRNO_CASE(ENOTSOCK);
+#endif
+
+#ifdef ENOTSUP
+ ERRNO_CASE(ENOTSUP);
+#else
+# ifdef EOPNOTSUPP
+ ERRNO_CASE(EOPNOTSUPP);
+# endif
+#endif
+
+#ifdef ENOTTY
+ ERRNO_CASE(ENOTTY);
+#endif
+
+#ifdef ENXIO
+ ERRNO_CASE(ENXIO);
+#endif
+
+
+#ifdef EOVERFLOW
+ ERRNO_CASE(EOVERFLOW);
+#endif
+
+#ifdef EPERM
+ ERRNO_CASE(EPERM);
+#endif
+
+#ifdef EPIPE
+ ERRNO_CASE(EPIPE);
+#endif
+
+#ifdef EPROTO
+ ERRNO_CASE(EPROTO);
+#endif
+
+#ifdef EPROTONOSUPPORT
+ ERRNO_CASE(EPROTONOSUPPORT);
+#endif
+
+#ifdef EPROTOTYPE
+ ERRNO_CASE(EPROTOTYPE);
+#endif
+
+#ifdef ERANGE
+ ERRNO_CASE(ERANGE);
+#endif
+
+#ifdef EROFS
+ ERRNO_CASE(EROFS);
+#endif
+
+#ifdef ESPIPE
+ ERRNO_CASE(ESPIPE);
+#endif
+
+#ifdef ESRCH
+ ERRNO_CASE(ESRCH);
+#endif
+
+#ifdef ESTALE
+ ERRNO_CASE(ESTALE);
+#endif
+
+#ifdef ETIME
+ ERRNO_CASE(ETIME);
+#endif
+
+#ifdef ETIMEDOUT
+ ERRNO_CASE(ETIMEDOUT);
+#endif
+
+#ifdef ETXTBSY
+ ERRNO_CASE(ETXTBSY);
+#endif
+
+#ifdef EXDEV
+ ERRNO_CASE(EXDEV);
+#endif
+
+ default: return "";
+ }
+}
+
+const char *signo_string(int signo) {
+#define SIGNO_CASE(e) case e: return #e;
+ switch (signo) {
+
+#ifdef SIGHUP
+ SIGNO_CASE(SIGHUP);
+#endif
+
+#ifdef SIGINT
+ SIGNO_CASE(SIGINT);
+#endif
+
+#ifdef SIGQUIT
+ SIGNO_CASE(SIGQUIT);
+#endif
+
+#ifdef SIGILL
+ SIGNO_CASE(SIGILL);
+#endif
+
+#ifdef SIGTRAP
+ SIGNO_CASE(SIGTRAP);
+#endif
+
+#ifdef SIGABRT
+ SIGNO_CASE(SIGABRT);
+#endif
+
+#ifdef SIGIOT
+# if SIGABRT != SIGIOT
+ SIGNO_CASE(SIGIOT);
+# endif
+#endif
+
+#ifdef SIGBUS
+ SIGNO_CASE(SIGBUS);
+#endif
+
+#ifdef SIGFPE
+ SIGNO_CASE(SIGFPE);
+#endif
+
+#ifdef SIGKILL
+ SIGNO_CASE(SIGKILL);
+#endif
+
+#ifdef SIGUSR1
+ SIGNO_CASE(SIGUSR1);
+#endif
+
+#ifdef SIGSEGV
+ SIGNO_CASE(SIGSEGV);
+#endif
+
+#ifdef SIGUSR2
+ SIGNO_CASE(SIGUSR2);
+#endif
+
+#ifdef SIGPIPE
+ SIGNO_CASE(SIGPIPE);
+#endif
+
+#ifdef SIGALRM
+ SIGNO_CASE(SIGALRM);
+#endif
+
+ SIGNO_CASE(SIGTERM);
+ SIGNO_CASE(SIGCHLD);
+
+#ifdef SIGSTKFLT
+ SIGNO_CASE(SIGSTKFLT);
+#endif
+
+
+#ifdef SIGCONT
+ SIGNO_CASE(SIGCONT);
+#endif
+
+#ifdef SIGSTOP
+ SIGNO_CASE(SIGSTOP);
+#endif
+
+#ifdef SIGTSTP
+ SIGNO_CASE(SIGTSTP);
+#endif
+
+#ifdef SIGTTIN
+ SIGNO_CASE(SIGTTIN);
+#endif
+
+#ifdef SIGTTOU
+ SIGNO_CASE(SIGTTOU);
+#endif
+
+#ifdef SIGURG
+ SIGNO_CASE(SIGURG);
+#endif
+
+#ifdef SIGXCPU
+ SIGNO_CASE(SIGXCPU);
+#endif
+
+#ifdef SIGXFSZ
+ SIGNO_CASE(SIGXFSZ);
+#endif
+
+#ifdef SIGVTALRM
+ SIGNO_CASE(SIGVTALRM);
+#endif
+
+#ifdef SIGPROF
+ SIGNO_CASE(SIGPROF);
+#endif
+
+#ifdef SIGWINCH
+ SIGNO_CASE(SIGWINCH);
+#endif
+
+#ifdef SIGIO
+ SIGNO_CASE(SIGIO);
+#endif
+
+#ifdef SIGPOLL
+# if SIGPOLL != SIGIO
+ SIGNO_CASE(SIGPOLL);
+# endif
+#endif
+
+#ifdef SIGLOST
+ SIGNO_CASE(SIGLOST);
+#endif
+
+#ifdef SIGPWR
+ SIGNO_CASE(SIGPWR);
+#endif
+
+#ifdef SIGSYS
+ SIGNO_CASE(SIGSYS);
+#endif
+
+ default: return "";
+ }
+}
+
+
+Local<Value> ErrnoException(int errorno,
+ const char *syscall,
+ const char *msg) {
+ Local<String> estring = String::NewSymbol(errno_string(errorno));
+ if (!msg[0]) msg = strerror(errorno);
+ Local<String> message = String::NewSymbol(msg);
+
+ Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
+ Local<String> cons2 = String::Concat(cons1, message);
+
+ Local<Value> e = Exception::Error(cons2);
+
+ Local<Object> obj = e->ToObject();
+
+ if (errno_symbol.IsEmpty()) {
+ syscall_symbol = NODE_PSYMBOL("syscall");
+ errno_symbol = NODE_PSYMBOL("errno");
+ }
+
+ obj->Set(errno_symbol, Integer::New(errorno));
+ if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
+ return e;
+}
+
+
enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
HandleScope scope;
#endif
// Returns number of bytes written.
-ssize_t DecodeWrite(char *buf, size_t buflen,
+ssize_t DecodeWrite(char *buf,
+ size_t buflen,
v8::Handle<v8::Value> val,
enum encoding encoding) {
HandleScope scope;
Local<String> str = val->ToString();
if (encoding == UTF8) {
- str->WriteUtf8(buf, buflen);
+ str->WriteUtf8(buf, buflen, NULL, String::HINT_MANY_WRITES_EXPECTED);
return buflen;
}
if (encoding == ASCII) {
- str->WriteAscii(buf, 0, buflen);
+ str->WriteAscii(buf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
return buflen;
}
uint16_t * twobytebuf = new uint16_t[buflen];
- str->Write(twobytebuf, 0, buflen);
+ str->Write(twobytebuf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
for (size_t i = 0; i < buflen; i++) {
unsigned char *b = reinterpret_cast<unsigned char*>(&twobytebuf[i]);
stats->Set(rdev_symbol, Integer::New(s->st_rdev));
/* total size, in bytes */
- stats->Set(size_symbol, Integer::New(s->st_size));
+ stats->Set(size_symbol, Number::New(s->st_size));
/* blocksize for filesystem I/O */
stats->Set(blksize_symbol, Integer::New(s->st_blksize));
return *value ? *value : "<str conversion failed>";
}
-static void ReportException(TryCatch &try_catch, bool show_line = false) {
+static void ReportException(TryCatch &try_catch, bool show_line) {
Handle<Message> message = try_catch.Message();
Handle<Value> error = try_catch.Exception();
// Print line of source code.
String::Utf8Value sourceline(message->GetSourceLine());
const char* sourceline_string = ToCString(sourceline);
- fprintf(stderr, "%s\n", sourceline_string);
+
+ // HACK HACK HACK
+ //
+ // FIXME
+ //
+ // Because of how CommonJS modules work, all scripts are wrapped with a
+ // "function (function (exports, __filename, ...) {"
+ // to provide script local variables.
+ //
+ // When reporting errors on the first line of a script, this wrapper
+ // function is leaked to the user. This HACK is to remove it. The length
+ // of the wrapper is 62. That wrapper is defined in lib/module.js
+ //
+ // If that wrapper is ever changed, then this number also has to be
+ // updated. Or - someone could clean this up so that the two peices
+ // don't need to be changed.
+ //
+ // Even better would be to get support into V8 for wrappers that
+ // shouldn't be reported to users.
+ int offset = linenum == 1 ? 62 : 0;
+
+ fprintf(stderr, "%s\n", sourceline_string + offset);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
- for (int i = 0; i < start; i++) {
+ for (int i = offset; i < start; i++) {
fprintf(stderr, " ");
}
int end = message->GetEndColumn();
HandleScope scope;
TryCatch try_catch;
- Local<Script> script = Script::Compile(source, filename);
+ Local<v8::Script> script = v8::Script::Compile(source, filename);
if (script.IsEmpty()) {
- ReportException(try_catch);
+ ReportException(try_catch, true);
exit(1);
}
Local<Value> result = script->Run();
if (result.IsEmpty()) {
- ReportException(try_catch);
+ ReportException(try_catch, true);
exit(1);
}
static Handle<Value> Loop(const Arguments& args) {
HandleScope scope;
+ assert(args.Length() == 0);
// TODO Probably don't need to start this each time.
// Avoids failing on test/mjsunit/test-eio-race3.js though
static Handle<Value> Cwd(const Arguments& args) {
HandleScope scope;
+ assert(args.Length() == 0);
char output[PATH_MAX];
char *r = getcwd(output, PATH_MAX);
static Handle<Value> GetUid(const Arguments& args) {
HandleScope scope;
+ assert(args.Length() == 0);
int uid = getuid();
return scope.Close(Integer::New(uid));
}
static Handle<Value> GetGid(const Arguments& args) {
HandleScope scope;
+ assert(args.Length() == 0);
int gid = getgid();
return scope.Close(Integer::New(gid));
}
static Handle<Value> SetGid(const Arguments& args) {
HandleScope scope;
-
+
if (args.Length() < 1) {
return ThrowException(Exception::Error(
- String::New("setgid requires 1 argument")));
+ String::New("setgid requires 1 argument")));
}
Local<Integer> given_gid = args[0]->ToInteger();
return Undefined();
}
-Handle<Value>
-NowGetter (Local<String> property, const AccessorInfo& info)
-{
- HandleScope scope;
- return scope.Close(Integer::New(ev_now(EV_DEFAULT_UC)));
-}
-
v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
HandleScope scope;
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
+#include <paths.h>
#include <fcntl.h>
#include <unistd.h>
pid = getpid();
- kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open");
+ kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
if (kd == NULL) goto error;
kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
}
#endif // __linux__
+
+static void CheckStatus(EV_P_ ev_timer *watcher, int revents) {
+ assert(watcher == &gc_timer);
+ assert(revents == EV_TIMER);
+
+#if HAVE_GETMEM
+ // check memory
+ size_t rss, vsize;
+ if (!ev_is_active(&gc_idle) && getmem(&rss, &vsize) == 0) {
+ if (rss > 1024*1024*128) {
+ // larger than 128 megs, just start the idle watcher
+ ev_idle_start(EV_A_ &gc_idle);
+ return;
+ }
+ }
+#endif // HAVE_GETMEM
+
+ double d = ev_now(EV_DEFAULT_UC) - TICK_TIME(3);
+
+ //printfb("timer d = %f\n", d);
+
+ if (d >= GC_WAIT_TIME - 1.) {
+ //fprintf(stderr, "start idle\n");
+ ev_idle_start(EV_A_ &gc_idle);
+ }
+}
+
+
v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
HandleScope scope;
+ assert(args.Length() == 0);
#ifndef HAVE_GETMEM
return ThrowException(Exception::Error(String::New("Not support on your platform. (Talk to Ryan.)")));
return Undefined();
}
-// evalcx(code, sandbox={})
-// Executes code in a new context
-Handle<Value> EvalCX(const Arguments& args) {
- HandleScope scope;
-
- Local<String> code = args[0]->ToString();
- Local<Object> sandbox = args.Length() > 1 ? args[1]->ToObject()
- : Object::New();
- // Create the new context
- Persistent<Context> context = Context::New();
-
- // Copy objects from global context, to our brand new context
- Handle<Array> keys = sandbox->GetPropertyNames();
-
- int i;
- for (i = 0; i < keys->Length(); i++) {
- Handle<String> key = keys->Get(Integer::New(i))->ToString();
- Handle<Value> value = sandbox->Get(key);
- context->Global()->Set(key, value->ToObject()->Clone());
- }
-
- // Enter and compile script
- context->Enter();
-
- // Catch errors
- TryCatch try_catch;
-
- Local<Script> script = Script::Compile(code, String::New("evalcx"));
- Handle<Value> result;
-
- if (script.IsEmpty()) {
- result = ThrowException(try_catch.Exception());
- } else {
- result = script->Run();
- if (result.IsEmpty()) {
- result = ThrowException(try_catch.Exception());
- }
- }
-
- // Clean up, clean up, everybody everywhere!
- context->DetachGlobal();
- context->Exit();
- context.Dispose();
-
- return scope.Close(result);
-}
Handle<Value> Compile(const Arguments& args) {
HandleScope scope;
TryCatch try_catch;
- Local<Script> script = Script::Compile(source, filename);
+ Local<v8::Script> script = v8::Script::Compile(source, filename);
if (try_catch.HasCaught()) {
// Hack because I can't get a proper stacktrace on SyntaxError
ReportException(try_catch, true);
}
Local<Value> result = script->Run();
- if (try_catch.HasCaught()) return try_catch.ReThrow();
+ if (try_catch.HasCaught()) {
+ ReportException(try_catch, false);
+ exit(1);
+ }
return scope.Close(result);
}
// Check if uncaught_exception_counter indicates a recursion
if (uncaught_exception_counter > 0) {
- ReportException(try_catch);
+ ReportException(try_catch, true);
exit(1);
}
uint32_t length = listener_array->Length();
// Report and exit if process has no "uncaughtException" listener
if (length == 0) {
- ReportException(try_catch);
+ ReportException(try_catch, true);
exit(1);
}
static Handle<Value> CheckBreak(const Arguments& args) {
HandleScope scope;
+ assert(args.Length() == 0);
// TODO FIXME This function is a hack to wait until V8 is ready to accept
// commands. There seems to be a bug in EnableAgent( _ , _ , true) which
return Undefined();
}
+Persistent<Object> binding_cache;
+
+static Handle<Value> Binding(const Arguments& args) {
+ HandleScope scope;
+
+ Local<String> module = args[0]->ToString();
+ String::Utf8Value module_v(module);
+
+ if (binding_cache.IsEmpty()) {
+ binding_cache = Persistent<Object>::New(Object::New());
+ }
+
+ Local<Object> exports;
+
+ // TODO DRY THIS UP!
+
+ if (!strcmp(*module_v, "stdio")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ Stdio::Initialize(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "cares")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ Cares::Initialize(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "fs")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+
+ // Initialize the stats object
+ Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
+ stats_constructor_template = Persistent<FunctionTemplate>::New(stat_templ);
+ exports->Set(String::NewSymbol("Stats"),
+ stats_constructor_template->GetFunction());
+ StatWatcher::Initialize(exports);
+ File::Initialize(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "signal_watcher")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ SignalWatcher::Initialize(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "net")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ InitNet2(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "http_parser")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ InitHttpParser(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "child_process")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ ChildProcess::Initialize(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "buffer")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ Buffer::Initialize(exports);
+ binding_cache->Set(module, exports);
+ }
+ #ifdef HAVE_OPENSSL
+ } else if (!strcmp(*module_v, "crypto")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ InitCrypto(exports);
+ binding_cache->Set(module, exports);
+ }
+ #endif
+ } else if (!strcmp(*module_v, "evals")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ node::Script::Initialize(exports);
+ binding_cache->Set(module, exports);
+ }
+
+ } else if (!strcmp(*module_v, "natives")) {
+ if (binding_cache->Has(module)) {
+ exports = binding_cache->Get(module)->ToObject();
+ } else {
+ exports = Object::New();
+ // Explicitly define native sources.
+ // TODO DRY/automate this?
+ exports->Set(String::New("assert"), String::New(native_assert));
+ exports->Set(String::New("buffer"), String::New(native_buffer));
+ exports->Set(String::New("child_process"),String::New(native_child_process));
+ exports->Set(String::New("dns"), String::New(native_dns));
+ exports->Set(String::New("events"), String::New(native_events));
+ exports->Set(String::New("file"), String::New(native_file));
+ exports->Set(String::New("freelist"), String::New(native_freelist));
+ exports->Set(String::New("fs"), String::New(native_fs));
+ exports->Set(String::New("http"), String::New(native_http));
+ exports->Set(String::New("crypto"), String::New(native_crypto));
+ exports->Set(String::New("ini"), String::New(native_ini));
+ exports->Set(String::New("mjsunit"), String::New(native_mjsunit));
+ exports->Set(String::New("net"), String::New(native_net));
+ exports->Set(String::New("posix"), String::New(native_posix));
+ exports->Set(String::New("querystring"), String::New(native_querystring));
+ exports->Set(String::New("repl"), String::New(native_repl));
+ exports->Set(String::New("sys"), String::New(native_sys));
+ exports->Set(String::New("tcp"), String::New(native_tcp));
+ exports->Set(String::New("uri"), String::New(native_uri));
+ exports->Set(String::New("url"), String::New(native_url));
+ exports->Set(String::New("utils"), String::New(native_utils));
+ exports->Set(String::New("path"), String::New(native_path));
+ exports->Set(String::New("module"), String::New(native_module));
+ binding_cache->Set(module, exports);
+ }
+
+ } else {
+ return ThrowException(Exception::Error(String::New("No such module")));
+ }
+
+ return scope.Close(exports);
+}
+
static void Load(int argc, char *argv[]) {
HandleScope scope;
Local<FunctionTemplate> process_template = FunctionTemplate::New();
node::EventEmitter::Initialize(process_template);
- process_template->InstanceTemplate()->SetAccessor(String::NewSymbol("now"), NowGetter, NULL);
-
process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
// Add a reference to the global object
// define various internal methods
NODE_SET_METHOD(process, "loop", Loop);
NODE_SET_METHOD(process, "unloop", Unloop);
- NODE_SET_METHOD(process, "evalcx", EvalCX);
NODE_SET_METHOD(process, "compile", Compile);
NODE_SET_METHOD(process, "_byteLength", ByteLength);
+ NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
NODE_SET_METHOD(process, "reallyExit", Exit);
NODE_SET_METHOD(process, "chdir", Chdir);
NODE_SET_METHOD(process, "cwd", Cwd);
NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
NODE_SET_METHOD(process, "checkBreak", CheckBreak);
+ NODE_SET_METHOD(process, "binding", Binding);
+
// Assign the EventEmitter. It was created in main().
process->Set(String::NewSymbol("EventEmitter"),
EventEmitter::constructor_template->GetFunction());
- // Initialize the stats object
- Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
- stats_constructor_template = Persistent<FunctionTemplate>::New(stat_templ);
- process->Set(String::NewSymbol("Stats"),
- stats_constructor_template->GetFunction());
-
// Initialize the C++ modules..................filename of module
- Buffer::Initialize(process); // buffer.cc
IOWatcher::Initialize(process); // io_watcher.cc
- IdleWatcher::Initialize(process); // idle_watcher.cc
+ // Not in use at the moment.
+ //IdleWatcher::Initialize(process); // idle_watcher.cc
Timer::Initialize(process); // timer.cc
- Stat::Initialize(process); // stat.cc
- SignalHandler::Initialize(process); // signal_handler.cc
-
- InitNet2(process); // net2.cc
- InitHttpParser(process); // http_parser.cc
-
- Stdio::Initialize(process); // stdio.cc
- ChildProcess::Initialize(process); // child_process.cc
DefineConstants(process); // constants.cc
- // Create node.dns
- Local<Object> dns = Object::New();
- process->Set(String::NewSymbol("dns"), dns);
- DNS::Initialize(dns); // dns.cc
- Local<Object> fs = Object::New();
- process->Set(String::NewSymbol("fs"), fs);
- File::Initialize(fs); // file.cc
- // Create node.tcp. Note this separate from lib/tcp.js which is the public
- // frontend.
- Local<Object> tcp = Object::New();
- process->Set(String::New("tcp"), tcp);
- Server::Initialize(tcp); // tcp.cc
- Connection::Initialize(tcp); // tcp.cc
- // Create node.http. Note this separate from lib/http.js which is the
- // public frontend.
- Local<Object> http = Object::New();
- process->Set(String::New("http"), http);
- HTTPServer::Initialize(http); // http.cc
- HTTPConnection::Initialize(http); // http.cc
-
-
// Compile, execute the src/node.js file. (Which was included as static C
// string in node_natives.h. 'natve_node' is the string containing that
// The node.js file returns a function 'f'
-#ifndef NDEBUG
TryCatch try_catch;
-#endif
Local<Value> f_value = ExecuteString(String::New(native_node),
String::New("node.js"));
-#ifndef NDEBUG
if (try_catch.HasCaught()) {
- ReportException(try_catch);
+ ReportException(try_catch, true);
exit(10);
}
-#endif
assert(f_value->IsFunction());
Local<Function> f = Local<Function>::Cast(f_value);
f->Call(global, 1, args);
-#ifndef NDEBUG
if (try_catch.HasCaught()) {
- ReportException(try_catch);
+ ReportException(try_catch, true);
exit(11);
}
-#endif
}
static void PrintHelp();
exit(0);
} else if (strcmp(arg, "--vars") == 0) {
printf("NODE_PREFIX: %s\n", NODE_PREFIX);
- printf("NODE_LIBRARIES_PREFIX: %s/%s\n", NODE_PREFIX, "lib/node/libraries");
printf("NODE_CFLAGS: %s\n", NODE_CFLAGS);
exit(0);
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
return 1;
}
- // Ignore the SIGPIPE
- evcom_ignore_sigpipe();
+
+ // Ignore SIGPIPE
+ struct sigaction sa;
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sa, NULL);
+
// Initialize the default ev loop.
#ifdef __sun
ev_default_loop(EVFLAG_AUTO);
#endif
+ ev_prepare_init(&node::next_tick_watcher, node::Tick);
+ ev_prepare_start(EV_DEFAULT_UC_ &node::next_tick_watcher);
+ ev_unref(EV_DEFAULT_UC);
+
+ ev_idle_init(&node::tick_spinner, node::Spin);
- ev_timer_init(&node::gc_timer, node::GCTimeout, GC_INTERVAL, GC_INTERVAL);
- // Set the gc_timer to max priority so that it runs before all other
- // watchers. In this way it can check if the 'tick' has other pending
- // watchers by using ev_pending_count() - if it ran with lower priority
- // then the other watchers might run before it - not giving us good idea
- // of loop idleness.
- ev_set_priority(&node::gc_timer, EV_MAXPRI);
- ev_timer_start(EV_DEFAULT_UC_ &node::gc_timer);
+ ev_check_init(&node::gc_check, node::Check);
+ ev_check_start(EV_DEFAULT_UC_ &node::gc_check);
ev_unref(EV_DEFAULT_UC);
+ ev_idle_init(&node::gc_idle, node::Idle);
+ ev_timer_init(&node::gc_timer, node::CheckStatus, 5., 5.);
+
// Setup the EIO thread pool
{ // It requires 3, yes 3, watchers.