System EV compatibility fix : use EV_DEFAULT_UC
[platform/upstream/nodejs.git] / src / node.cc
index 709e7bb..d0e934d 100644 (file)
@@ -5,6 +5,7 @@
 
 #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>
 
@@ -43,6 +49,9 @@ namespace node {
 
 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;
@@ -71,22 +80,133 @@ static bool use_debug_agent = false;
 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);
+  }
 }
 
 
@@ -145,6 +265,501 @@ static void EIODonePoll(void) {
 }
 
 
+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;
 
@@ -218,7 +833,8 @@ ssize_t DecodeBytes(v8::Handle<v8::Value> val, enum encoding encoding) {
 #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;
@@ -239,12 +855,12 @@ ssize_t DecodeWrite(char *buf, size_t buflen,
   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;
   }
 
@@ -254,7 +870,7 @@ ssize_t DecodeWrite(char *buf, size_t 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]);
@@ -313,7 +929,7 @@ Local<Object> BuildStatsObject(struct stat * s) {
   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));
@@ -339,7 +955,7 @@ const char* ToCString(const v8::String::Utf8Value& value) {
   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();
@@ -360,10 +976,31 @@ static void ReportException(TryCatch &try_catch, bool show_line = false) {
     // 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();
@@ -387,15 +1024,15 @@ Local<Value> ExecuteString(Local<String> source, Local<Value> filename) {
   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);
   }
 
@@ -416,6 +1053,7 @@ static Handle<Value> ByteLength(const Arguments& args) {
 
 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
@@ -459,6 +1097,7 @@ static Handle<Value> Chdir(const Arguments& args) {
 
 static Handle<Value> Cwd(const Arguments& args) {
   HandleScope scope;
+  assert(args.Length() == 0);
 
   char output[PATH_MAX];
   char *r = getcwd(output, PATH_MAX);
@@ -490,12 +1129,14 @@ static Handle<Value> Umask(const Arguments& args){
 
 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));
 }
@@ -503,10 +1144,10 @@ static Handle<Value> GetGid(const Arguments& args) {
 
 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();
@@ -535,13 +1176,6 @@ static Handle<Value> SetUid(const Arguments& args) {
   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;
@@ -602,6 +1236,7 @@ int getmem(size_t *rss, size_t *vsize) {
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #include <sys/user.h>
+#include <paths.h>
 #include <fcntl.h>
 #include <unistd.h>
 
@@ -614,7 +1249,7 @@ int getmem(size_t *rss, size_t *vsize) {
 
   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);
@@ -746,8 +1381,37 @@ error:
 }
 #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.)")));
@@ -859,52 +1523,6 @@ Handle<Value> DLOpen(const v8::Arguments& args) {
   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;
@@ -919,7 +1537,7 @@ Handle<Value> Compile(const Arguments& args) {
 
   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);
@@ -927,7 +1545,10 @@ Handle<Value> Compile(const Arguments& args) {
   }
 
   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);
 }
@@ -948,7 +1569,7 @@ void FatalException(TryCatch &try_catch) {
 
   // Check if uncaught_exception_counter indicates a recursion
   if (uncaught_exception_counter > 0) {
-    ReportException(try_catch);
+    ReportException(try_catch, true);
     exit(1);
   }
 
@@ -974,7 +1595,7 @@ void FatalException(TryCatch &try_catch) {
   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);
   }
 
@@ -1016,6 +1637,7 @@ static void DebugMessageDispatch(void) {
 
 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
@@ -1053,6 +1675,159 @@ static Handle<Value> CheckBreak(const Arguments& args) {
   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;
@@ -1060,8 +1835,6 @@ static void Load(int argc, char *argv[]) {
   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
@@ -1113,9 +1886,9 @@ static void Load(int argc, char *argv[]) {
   // 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);
@@ -1131,52 +1904,19 @@ static void Load(int argc, char *argv[]) {
   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
@@ -1184,18 +1924,14 @@ static void Load(int argc, char *argv[]) {
 
   // 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);
 
@@ -1211,12 +1947,10 @@ static void Load(int argc, char *argv[]) {
 
   f->Call(global, 1, args);
 
-#ifndef NDEBUG
   if (try_catch.HasCaught())  {
-    ReportException(try_catch);
+    ReportException(try_catch, true);
     exit(11);
   }
-#endif
 }
 
 static void PrintHelp();
@@ -1283,7 +2017,6 @@ static void ParseArgs(int *argc, char **argv) {
       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) {
@@ -1316,8 +2049,13 @@ int main(int argc, char *argv[]) {
     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
@@ -1328,17 +2066,19 @@ int main(int argc, char *argv[]) {
   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.