Script class with eval-function-family in binding('evals') plus tests.
[platform/upstream/nodejs.git] / src / node.cc
1 // Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
2 #include <node.h>
3
4 #include <locale.h>
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <limits.h> /* PATH_MAX */
10 #include <assert.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <dlfcn.h> /* dlopen(), dlsym() */
14 #include <sys/types.h>
15 #include <unistd.h> /* setuid, getuid */
16
17 #include <node_buffer.h>
18 #include <node_io_watcher.h>
19 #include <node_net2.h>
20 #include <node_events.h>
21 #include <node_cares.h>
22 #include <node_net.h>
23 #include <node_file.h>
24 #if 0
25 // not in use
26 # include <node_idle_watcher.h>
27 #endif
28 #include <node_http.h>
29 #include <node_http_parser.h>
30 #include <node_signal_watcher.h>
31 #include <node_stat_watcher.h>
32 #include <node_timer.h>
33 #include <node_child_process.h>
34 #include <node_constants.h>
35 #include <node_stdio.h>
36 #include <node_natives.h>
37 #include <node_version.h>
38 #ifdef HAVE_OPENSSL
39 #include <node_crypto.h>
40 #endif
41 #include <node_script.h>
42
43 #include <v8-debug.h>
44
45 using namespace v8;
46
47 extern char **environ;
48
49 namespace node {
50
51 static Persistent<Object> process;
52
53 static Persistent<String> dev_symbol;
54 static Persistent<String> ino_symbol;
55 static Persistent<String> mode_symbol;
56 static Persistent<String> nlink_symbol;
57 static Persistent<String> uid_symbol;
58 static Persistent<String> gid_symbol;
59 static Persistent<String> rdev_symbol;
60 static Persistent<String> size_symbol;
61 static Persistent<String> blksize_symbol;
62 static Persistent<String> blocks_symbol;
63 static Persistent<String> atime_symbol;
64 static Persistent<String> mtime_symbol;
65 static Persistent<String> ctime_symbol;
66
67 static Persistent<String> rss_symbol;
68 static Persistent<String> vsize_symbol;
69 static Persistent<String> heap_total_symbol;
70 static Persistent<String> heap_used_symbol;
71
72 static Persistent<String> listeners_symbol;
73 static Persistent<String> uncaught_exception_symbol;
74 static Persistent<String> emit_symbol;
75
76 static int option_end_index = 0;
77 static bool use_debug_agent = false;
78 static bool debug_wait_connect = false;
79 static int debug_port=5858;
80
81 static ev_prepare next_tick_watcher;
82 static ev_idle tick_spinner;
83 static bool need_tick_cb;
84 static Persistent<String> tick_callback_sym;
85
86 static ev_async eio_want_poll_notifier;
87 static ev_async eio_done_poll_notifier;
88 static ev_idle  eio_poller;
89
90 // We need to notify V8 when we're idle so that it can run the garbage
91 // collector. The interface to this is V8::IdleNotification(). It returns
92 // true if the heap hasn't be fully compacted, and needs to be run again.
93 // Returning false means that it doesn't have anymore work to do.
94 //
95 // We try to wait for a period of GC_INTERVAL (2 seconds) of idleness, where
96 // idleness means that no libev watchers have been executed. Since
97 // everything in node uses libev watchers, this is a pretty good measure of
98 // idleness. This is done with gc_check, which records the timestamp
99 // last_active on every tick of the event loop, and with gc_timer which
100 // executes every few seconds to measure if
101 //   last_active + GC_INTERVAL < ev_now()
102 // If we do find a period of idleness, then we start the gc_idle timer which
103 // will very repaidly call IdleNotification until the heap is fully
104 // compacted.
105 static ev_tstamp last_active;
106 static ev_timer  gc_timer;
107 static ev_check gc_check;
108 static ev_idle  gc_idle;
109 #define GC_INTERVAL 1.0
110
111 static void gc_timer_start () {
112   if (!ev_is_active(&gc_timer)) {
113     ev_timer_start(EV_DEFAULT_UC_ &gc_timer);
114     ev_unref(EV_DEFAULT_UC);
115   }
116 }
117
118 static void gc_timer_stop () {
119   if (ev_is_active(&gc_timer)) {
120     ev_ref(EV_DEFAULT_UC);
121     ev_timer_stop(EV_DEFAULT_UC_ &gc_timer);
122   }
123 }
124
125
126 static void CheckIdleness(EV_P_ ev_timer *watcher, int revents) {
127   assert(watcher == &gc_timer);
128   assert(revents == EV_TIMER);
129
130   //fprintf(stderr, "check idle\n");
131
132   ev_tstamp idle_time = ev_now(EV_DEFAULT_UC) - last_active;
133
134   if (idle_time > GC_INTERVAL) {
135     if (!V8::IdleNotification()) {
136       ev_idle_start(EV_DEFAULT_UC_ &gc_idle);
137     }
138     gc_timer_stop();
139   }
140 }
141
142
143 static void NotifyIdleness(EV_P_ ev_idle *watcher, int revents) {
144   assert(watcher == &gc_idle);
145   assert(revents == EV_IDLE);
146
147   //fprintf(stderr, "notify idle\n");
148
149   if (V8::IdleNotification()) {
150     ev_idle_stop(EV_A_ watcher);
151     gc_timer_stop();
152   }
153 }
154
155
156 static void Activity(EV_P_ ev_check *watcher, int revents) {
157   assert(watcher == &gc_check);
158   assert(revents == EV_CHECK);
159
160   int pending = ev_pending_count(EV_DEFAULT_UC);
161
162   // Don't count GC watchers as activity.
163
164   if (ev_is_pending(&gc_timer)) pending--;
165   if (ev_is_pending(&gc_idle)) pending--;
166   if (ev_is_pending(&gc_check)) pending--;
167
168   assert(pending >= 0);
169
170   //fprintf(stderr, "activity, pending: %d\n", pending);
171
172   if (pending) {
173     last_active = ev_now(EV_DEFAULT_UC);
174     ev_idle_stop(EV_DEFAULT_UC_ &gc_idle);
175     gc_timer_start();
176   }
177 }
178
179
180 static Handle<Value> NeedTickCallback(const Arguments& args) {
181   HandleScope scope;
182   need_tick_cb = true;
183   ev_idle_start(EV_DEFAULT_UC_ &tick_spinner);
184   return Undefined();
185 }
186
187
188 static void Spin(EV_P_ ev_idle *watcher, int revents) {
189   assert(watcher == &tick_spinner);
190   assert(revents == EV_IDLE);
191 }
192
193
194 static void Tick(EV_P_ ev_prepare *watcher, int revents) {
195   assert(watcher == &next_tick_watcher);
196   assert(revents == EV_PREPARE);
197
198   // Avoid entering a V8 scope.
199   if (!need_tick_cb) return;
200
201   need_tick_cb = false;
202   ev_idle_stop(EV_DEFAULT_UC_ &tick_spinner);
203
204   HandleScope scope;
205
206   if (tick_callback_sym.IsEmpty()) {
207     // Lazily set the symbol
208     tick_callback_sym =
209       Persistent<String>::New(String::NewSymbol("_tickCallback"));
210   }
211
212   Local<Value> cb_v = process->Get(tick_callback_sym);
213   if (!cb_v->IsFunction()) return;
214   Local<Function> cb = Local<Function>::Cast(cb_v);
215
216   TryCatch try_catch;
217
218   cb->Call(process, 0, NULL);
219
220   if (try_catch.HasCaught()) {
221     FatalException(try_catch);
222   }
223 }
224
225
226 static void DoPoll(EV_P_ ev_idle *watcher, int revents) {
227   assert(watcher == &eio_poller);
228   assert(revents == EV_IDLE);
229
230   //printf("eio_poller\n");
231
232   if (eio_poll() != -1) {
233     //printf("eio_poller stop\n");
234     ev_idle_stop(EV_DEFAULT_UC_ watcher);
235   }
236 }
237
238
239 // Called from the main thread.
240 static void WantPollNotifier(EV_P_ ev_async *watcher, int revents) {
241   assert(watcher == &eio_want_poll_notifier);
242   assert(revents == EV_ASYNC);
243
244   //printf("want poll notifier\n");
245
246   if (eio_poll() == -1) {
247     //printf("eio_poller start\n");
248     ev_idle_start(EV_DEFAULT_UC_ &eio_poller);
249   }
250 }
251
252
253 static void DonePollNotifier(EV_P_ ev_async *watcher, int revents) {
254   assert(watcher == &eio_done_poll_notifier);
255   assert(revents == EV_ASYNC);
256
257   //printf("done poll notifier\n");
258
259   if (eio_poll() != -1) {
260     //printf("eio_poller stop\n");
261     ev_idle_stop(EV_DEFAULT_UC_ &eio_poller);
262   }
263 }
264
265
266 // EIOWantPoll() is called from the EIO thread pool each time an EIO
267 // request (that is, one of the node.fs.* functions) has completed.
268 static void EIOWantPoll(void) {
269   // Signal the main thread that eio_poll need to be processed.
270   ev_async_send(EV_DEFAULT_UC_ &eio_want_poll_notifier);
271 }
272
273
274 static void EIODonePoll(void) {
275   // Signal the main thread that we should stop calling eio_poll().
276   // from the idle watcher.
277   ev_async_send(EV_DEFAULT_UC_ &eio_done_poll_notifier);
278 }
279
280
281 enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
282   HandleScope scope;
283
284   if (!encoding_v->IsString()) return _default;
285
286   String::Utf8Value encoding(encoding_v->ToString());
287
288   if (strcasecmp(*encoding, "utf8") == 0) {
289     return UTF8;
290   } else if (strcasecmp(*encoding, "utf-8") == 0) {
291     return UTF8;
292   } else if (strcasecmp(*encoding, "ascii") == 0) {
293     return ASCII;
294   } else if (strcasecmp(*encoding, "binary") == 0) {
295     return BINARY;
296   } else if (strcasecmp(*encoding, "raw") == 0) {
297     fprintf(stderr, "'raw' (array of integers) has been removed. "
298                     "Use 'binary'.\n");
299     return BINARY;
300   } else if (strcasecmp(*encoding, "raws") == 0) {
301     fprintf(stderr, "'raws' encoding has been renamed to 'binary'. "
302                     "Please update your code.\n");
303     return BINARY;
304   } else {
305     return _default;
306   }
307 }
308
309 Local<Value> Encode(const void *buf, size_t len, enum encoding encoding) {
310   HandleScope scope;
311
312   if (!len) return scope.Close(String::Empty());
313
314   if (encoding == BINARY) {
315     const unsigned char *cbuf = static_cast<const unsigned char*>(buf);
316     uint16_t * twobytebuf = new uint16_t[len];
317     for (size_t i = 0; i < len; i++) {
318       // XXX is the following line platform independent?
319       twobytebuf[i] = cbuf[i];
320     }
321     Local<String> chunk = String::New(twobytebuf, len);
322     delete [] twobytebuf; // TODO use ExternalTwoByteString?
323     return scope.Close(chunk);
324   }
325
326   // utf8 or ascii encoding
327   Local<String> chunk = String::New((const char*)buf, len);
328   return scope.Close(chunk);
329 }
330
331 // Returns -1 if the handle was not valid for decoding
332 ssize_t DecodeBytes(v8::Handle<v8::Value> val, enum encoding encoding) {
333   HandleScope scope;
334
335   if (val->IsArray()) {
336     fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
337                     "Use 'binary'.\n");
338     assert(0);
339     return -1;
340   }
341
342   Local<String> str = val->ToString();
343
344   if (encoding == UTF8) return str->Utf8Length();
345
346   return str->Length();
347 }
348
349 #ifndef MIN
350 # define MIN(a, b) ((a) < (b) ? (a) : (b))
351 #endif
352
353 // Returns number of bytes written.
354 ssize_t DecodeWrite(char *buf,
355                     size_t buflen,
356                     v8::Handle<v8::Value> val,
357                     enum encoding encoding) {
358   HandleScope scope;
359
360   // XXX
361   // A lot of improvement can be made here. See:
362   // http://code.google.com/p/v8/issues/detail?id=270
363   // http://groups.google.com/group/v8-dev/browse_thread/thread/dba28a81d9215291/ece2b50a3b4022c
364   // http://groups.google.com/group/v8-users/browse_thread/thread/1f83b0ba1f0a611
365
366   if (val->IsArray()) {
367     fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
368                     "Use 'binary'.\n");
369     assert(0);
370     return -1;
371   }
372
373   Local<String> str = val->ToString();
374
375   if (encoding == UTF8) {
376     str->WriteUtf8(buf, buflen, NULL, String::HINT_MANY_WRITES_EXPECTED);
377     return buflen;
378   }
379
380   if (encoding == ASCII) {
381     str->WriteAscii(buf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
382     return buflen;
383   }
384
385   // THIS IS AWFUL!!! FIXME
386
387   assert(encoding == BINARY);
388
389   uint16_t * twobytebuf = new uint16_t[buflen];
390
391   str->Write(twobytebuf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
392
393   for (size_t i = 0; i < buflen; i++) {
394     unsigned char *b = reinterpret_cast<unsigned char*>(&twobytebuf[i]);
395     assert(b[1] == 0);
396     buf[i] = b[0];
397   }
398
399   delete [] twobytebuf;
400
401   return buflen;
402 }
403
404 static Persistent<FunctionTemplate> stats_constructor_template;
405
406 Local<Object> BuildStatsObject(struct stat * s) {
407   HandleScope scope;
408
409   if (dev_symbol.IsEmpty()) {
410     dev_symbol = NODE_PSYMBOL("dev");
411     ino_symbol = NODE_PSYMBOL("ino");
412     mode_symbol = NODE_PSYMBOL("mode");
413     nlink_symbol = NODE_PSYMBOL("nlink");
414     uid_symbol = NODE_PSYMBOL("uid");
415     gid_symbol = NODE_PSYMBOL("gid");
416     rdev_symbol = NODE_PSYMBOL("rdev");
417     size_symbol = NODE_PSYMBOL("size");
418     blksize_symbol = NODE_PSYMBOL("blksize");
419     blocks_symbol = NODE_PSYMBOL("blocks");
420     atime_symbol = NODE_PSYMBOL("atime");
421     mtime_symbol = NODE_PSYMBOL("mtime");
422     ctime_symbol = NODE_PSYMBOL("ctime");
423   }
424
425   Local<Object> stats =
426     stats_constructor_template->GetFunction()->NewInstance();
427
428   /* ID of device containing file */
429   stats->Set(dev_symbol, Integer::New(s->st_dev));
430
431   /* inode number */
432   stats->Set(ino_symbol, Integer::New(s->st_ino));
433
434   /* protection */
435   stats->Set(mode_symbol, Integer::New(s->st_mode));
436
437   /* number of hard links */
438   stats->Set(nlink_symbol, Integer::New(s->st_nlink));
439
440   /* user ID of owner */
441   stats->Set(uid_symbol, Integer::New(s->st_uid));
442
443   /* group ID of owner */
444   stats->Set(gid_symbol, Integer::New(s->st_gid));
445
446   /* device ID (if special file) */
447   stats->Set(rdev_symbol, Integer::New(s->st_rdev));
448
449   /* total size, in bytes */
450   stats->Set(size_symbol, Integer::New(s->st_size));
451
452   /* blocksize for filesystem I/O */
453   stats->Set(blksize_symbol, Integer::New(s->st_blksize));
454
455   /* number of blocks allocated */
456   stats->Set(blocks_symbol, Integer::New(s->st_blocks));
457
458   /* time of last access */
459   stats->Set(atime_symbol, NODE_UNIXTIME_V8(s->st_atime));
460
461   /* time of last modification */
462   stats->Set(mtime_symbol, NODE_UNIXTIME_V8(s->st_mtime));
463
464   /* time of last status change */
465   stats->Set(ctime_symbol, NODE_UNIXTIME_V8(s->st_ctime));
466
467   return scope.Close(stats);
468 }
469
470
471 // Extracts a C str from a V8 Utf8Value.
472 const char* ToCString(const v8::String::Utf8Value& value) {
473   return *value ? *value : "<str conversion failed>";
474 }
475
476 static void ReportException(TryCatch &try_catch, bool show_line = false) {
477   Handle<Message> message = try_catch.Message();
478
479   Handle<Value> error = try_catch.Exception();
480   Handle<String> stack;
481
482   if (error->IsObject()) {
483     Handle<Object> obj = Handle<Object>::Cast(error);
484     Handle<Value> raw_stack = obj->Get(String::New("stack"));
485     if (raw_stack->IsString()) stack = Handle<String>::Cast(raw_stack);
486   }
487
488   if (show_line && !message.IsEmpty()) {
489     // Print (filename):(line number): (message).
490     String::Utf8Value filename(message->GetScriptResourceName());
491     const char* filename_string = ToCString(filename);
492     int linenum = message->GetLineNumber();
493     fprintf(stderr, "%s:%i\n", filename_string, linenum);
494     // Print line of source code.
495     String::Utf8Value sourceline(message->GetSourceLine());
496     const char* sourceline_string = ToCString(sourceline);
497     fprintf(stderr, "%s\n", sourceline_string);
498     // Print wavy underline (GetUnderline is deprecated).
499     int start = message->GetStartColumn();
500     for (int i = 0; i < start; i++) {
501       fprintf(stderr, " ");
502     }
503     int end = message->GetEndColumn();
504     for (int i = start; i < end; i++) {
505       fprintf(stderr, "^");
506     }
507     fprintf(stderr, "\n");
508   }
509
510   if (stack.IsEmpty()) {
511     message->PrintCurrentStackTrace(stderr);
512   } else {
513     String::Utf8Value trace(stack);
514     fprintf(stderr, "%s\n", *trace);
515   }
516   fflush(stderr);
517 }
518
519 // Executes a str within the current v8 context.
520 Local<Value> ExecuteString(Local<String> source, Local<Value> filename) {
521   HandleScope scope;
522   TryCatch try_catch;
523
524   Local<v8::Script> script = v8::Script::Compile(source, filename);
525   if (script.IsEmpty()) {
526     ReportException(try_catch);
527     exit(1);
528   }
529
530   Local<Value> result = script->Run();
531   if (result.IsEmpty()) {
532     ReportException(try_catch);
533     exit(1);
534   }
535
536   return scope.Close(result);
537 }
538
539 static Handle<Value> ByteLength(const Arguments& args) {
540   HandleScope scope;
541
542   if (args.Length() < 1 || !args[0]->IsString()) {
543     return ThrowException(Exception::Error(String::New("Bad argument.")));
544   }
545
546   Local<Integer> length = Integer::New(DecodeBytes(args[0], ParseEncoding(args[1], UTF8)));
547
548   return scope.Close(length);
549 }
550
551 static Handle<Value> Loop(const Arguments& args) {
552   HandleScope scope;
553   assert(args.Length() == 0);
554
555   // TODO Probably don't need to start this each time.
556   // Avoids failing on test/mjsunit/test-eio-race3.js though
557   ev_idle_start(EV_DEFAULT_UC_ &eio_poller);
558
559   ev_loop(EV_DEFAULT_UC_ 0);
560   return Undefined();
561 }
562
563 static Handle<Value> Unloop(const Arguments& args) {
564   fprintf(stderr, "Deprecation: Don't use process.unloop(). It will be removed soon.\n");
565   HandleScope scope;
566   int how = EVUNLOOP_ONE;
567   if (args[0]->IsString()) {
568     String::Utf8Value how_s(args[0]->ToString());
569     if (0 == strcmp(*how_s, "all")) {
570       how = EVUNLOOP_ALL;
571     }
572   }
573   ev_unloop(EV_DEFAULT_ how);
574   return Undefined();
575 }
576
577 static Handle<Value> Chdir(const Arguments& args) {
578   HandleScope scope;
579
580   if (args.Length() != 1 || !args[0]->IsString()) {
581     return ThrowException(Exception::Error(String::New("Bad argument.")));
582   }
583
584   String::Utf8Value path(args[0]->ToString());
585
586   int r = chdir(*path);
587
588   if (r != 0) {
589     return ThrowException(Exception::Error(String::New(strerror(errno))));
590   }
591
592   return Undefined();
593 }
594
595 static Handle<Value> Cwd(const Arguments& args) {
596   HandleScope scope;
597   assert(args.Length() == 0);
598
599   char output[PATH_MAX];
600   char *r = getcwd(output, PATH_MAX);
601   if (r == NULL) {
602     return ThrowException(Exception::Error(String::New(strerror(errno))));
603   }
604   Local<String> cwd = String::New(output);
605
606   return scope.Close(cwd);
607 }
608
609 static Handle<Value> Umask(const Arguments& args){
610   HandleScope scope;
611   unsigned int old;
612   if(args.Length() < 1) {
613     old = umask(0);
614     umask((mode_t)old);
615   }
616   else if(!args[0]->IsInt32()) {
617     return ThrowException(Exception::TypeError(
618           String::New("argument must be an integer.")));
619   }
620   else {
621     old = umask((mode_t)args[0]->Uint32Value());
622   }
623   return scope.Close(Uint32::New(old));
624 }
625
626
627 static Handle<Value> GetUid(const Arguments& args) {
628   HandleScope scope;
629   assert(args.Length() == 0);
630   int uid = getuid();
631   return scope.Close(Integer::New(uid));
632 }
633
634 static Handle<Value> GetGid(const Arguments& args) {
635   HandleScope scope;
636   assert(args.Length() == 0);
637   int gid = getgid();
638   return scope.Close(Integer::New(gid));
639 }
640
641
642 static Handle<Value> SetGid(const Arguments& args) {
643   HandleScope scope;
644
645   if (args.Length() < 1) {
646     return ThrowException(Exception::Error(
647       String::New("setgid requires 1 argument")));
648   }
649
650   Local<Integer> given_gid = args[0]->ToInteger();
651   int gid = given_gid->Int32Value();
652   int result;
653   if ((result = setgid(gid)) != 0) {
654     return ThrowException(Exception::Error(String::New(strerror(errno))));
655   }
656   return Undefined();
657 }
658
659 static Handle<Value> SetUid(const Arguments& args) {
660   HandleScope scope;
661
662   if (args.Length() < 1) {
663     return ThrowException(Exception::Error(
664           String::New("setuid requires 1 argument")));
665   }
666
667   Local<Integer> given_uid = args[0]->ToInteger();
668   int uid = given_uid->Int32Value();
669   int result;
670   if ((result = setuid(uid)) != 0) {
671     return ThrowException(Exception::Error(String::New(strerror(errno))));
672   }
673   return Undefined();
674 }
675
676
677 v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
678   HandleScope scope;
679   fflush(stderr);
680   Stdio::Flush();
681   exit(args[0]->IntegerValue());
682   return Undefined();
683 }
684
685 #ifdef __sun
686 #define HAVE_GETMEM 1
687 #include <unistd.h> /* getpagesize() */
688
689 #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
690 #define PROCFS_FILE_OFFSET_BITS_HACK 1
691 #undef _FILE_OFFSET_BITS
692 #else
693 #define PROCFS_FILE_OFFSET_BITS_HACK 0
694 #endif
695
696 #include <procfs.h>
697
698 #if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
699 #define _FILE_OFFSET_BITS 64
700 #endif
701
702 int getmem(size_t *rss, size_t *vsize) {
703   pid_t pid = getpid();
704
705   size_t page_size = getpagesize();
706   char pidpath[1024];
707   sprintf(pidpath, "/proc/%d/psinfo", pid);
708
709   psinfo_t psinfo;
710   FILE *f = fopen(pidpath, "r");
711   if (!f) return -1;
712
713   if (fread(&psinfo, sizeof(psinfo_t), 1, f) != 1) {
714     fclose (f);
715     return -1;
716   }
717
718   /* XXX correct? */
719
720   *vsize = (size_t) psinfo.pr_size * page_size;
721   *rss = (size_t) psinfo.pr_rssize * 1024;
722
723   fclose (f);
724
725   return 0;
726 }
727 #endif
728
729
730 #ifdef __FreeBSD__
731 #define HAVE_GETMEM 1
732 #include <kvm.h>
733 #include <sys/param.h>
734 #include <sys/sysctl.h>
735 #include <sys/user.h>
736 #include <paths.h>
737 #include <fcntl.h>
738 #include <unistd.h>
739
740 int getmem(size_t *rss, size_t *vsize) {
741   kvm_t *kd = NULL;
742   struct kinfo_proc *kinfo = NULL;
743   pid_t pid;
744   int nprocs;
745   size_t page_size = getpagesize();
746
747   pid = getpid();
748
749   kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
750   if (kd == NULL) goto error;
751
752   kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
753   if (kinfo == NULL) goto error;
754
755   *rss = kinfo->ki_rssize * page_size;
756   *vsize = kinfo->ki_size;
757
758   kvm_close(kd);
759
760   return 0;
761
762 error:
763   if (kd) kvm_close(kd);
764   return -1;
765 }
766 #endif  // __FreeBSD__
767
768
769 #ifdef __APPLE__
770 #define HAVE_GETMEM 1
771 /* Researched by Tim Becker and Michael Knight
772  * http://blog.kuriositaet.de/?p=257
773  */
774
775 #include <mach/task.h>
776 #include <mach/mach_init.h>
777
778 int getmem(size_t *rss, size_t *vsize) {
779   struct task_basic_info t_info;
780   mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
781
782   int r = task_info(mach_task_self(),
783                     TASK_BASIC_INFO,
784                     (task_info_t)&t_info,
785                     &t_info_count);
786
787   if (r != KERN_SUCCESS) return -1;
788
789   *rss = t_info.resident_size;
790   *vsize  = t_info.virtual_size;
791
792   return 0;
793 }
794 #endif  // __APPLE__
795
796 #ifdef __linux__
797 # define HAVE_GETMEM 1
798 # include <sys/param.h> /* for MAXPATHLEN */
799
800 int getmem(size_t *rss, size_t *vsize) {
801   FILE *f = fopen("/proc/self/stat", "r");
802   if (!f) return -1;
803
804   int itmp;
805   char ctmp;
806   char buffer[MAXPATHLEN];
807   size_t page_size = getpagesize();
808
809   /* PID */
810   if (fscanf(f, "%d ", &itmp) == 0) goto error;
811   /* Exec file */
812   if (fscanf (f, "%s ", &buffer[0]) == 0) goto error;
813   /* State */
814   if (fscanf (f, "%c ", &ctmp) == 0) goto error;
815   /* Parent process */
816   if (fscanf (f, "%d ", &itmp) == 0) goto error;
817   /* Process group */
818   if (fscanf (f, "%d ", &itmp) == 0) goto error;
819   /* Session id */
820   if (fscanf (f, "%d ", &itmp) == 0) goto error;
821   /* TTY */
822   if (fscanf (f, "%d ", &itmp) == 0) goto error;
823   /* TTY owner process group */
824   if (fscanf (f, "%d ", &itmp) == 0) goto error;
825   /* Flags */
826   if (fscanf (f, "%u ", &itmp) == 0) goto error;
827   /* Minor faults (no memory page) */
828   if (fscanf (f, "%u ", &itmp) == 0) goto error;
829   /* Minor faults, children */
830   if (fscanf (f, "%u ", &itmp) == 0) goto error;
831   /* Major faults (memory page faults) */
832   if (fscanf (f, "%u ", &itmp) == 0) goto error;
833   /* Major faults, children */
834   if (fscanf (f, "%u ", &itmp) == 0) goto error;
835   /* utime */
836   if (fscanf (f, "%d ", &itmp) == 0) goto error;
837   /* stime */
838   if (fscanf (f, "%d ", &itmp) == 0) goto error;
839   /* utime, children */
840   if (fscanf (f, "%d ", &itmp) == 0) goto error;
841   /* stime, children */
842   if (fscanf (f, "%d ", &itmp) == 0) goto error;
843   /* jiffies remaining in current time slice */
844   if (fscanf (f, "%d ", &itmp) == 0) goto error;
845   /* 'nice' value */
846   if (fscanf (f, "%d ", &itmp) == 0) goto error;
847   /* jiffies until next timeout */
848   if (fscanf (f, "%u ", &itmp) == 0) goto error;
849   /* jiffies until next SIGALRM */
850   if (fscanf (f, "%u ", &itmp) == 0) goto error;
851   /* start time (jiffies since system boot) */
852   if (fscanf (f, "%d ", &itmp) == 0) goto error;
853
854   /* Virtual memory size */
855   if (fscanf (f, "%u ", &itmp) == 0) goto error;
856   *vsize = (size_t) itmp;
857
858   /* Resident set size */
859   if (fscanf (f, "%u ", &itmp) == 0) goto error;
860   *rss = (size_t) itmp * page_size;
861
862   /* rlim */
863   if (fscanf (f, "%u ", &itmp) == 0) goto error;
864   /* Start of text */
865   if (fscanf (f, "%u ", &itmp) == 0) goto error;
866   /* End of text */
867   if (fscanf (f, "%u ", &itmp) == 0) goto error;
868   /* Start of stack */
869   if (fscanf (f, "%u ", &itmp) == 0) goto error;
870
871   fclose (f);
872
873   return 0;
874
875 error:
876   fclose (f);
877   return -1;
878 }
879 #endif  // __linux__
880
881 v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
882   HandleScope scope;
883   assert(args.Length() == 0);
884
885 #ifndef HAVE_GETMEM
886   return ThrowException(Exception::Error(String::New("Not support on your platform. (Talk to Ryan.)")));
887 #else
888   size_t rss, vsize;
889
890   int r = getmem(&rss, &vsize);
891
892   if (r != 0) {
893     return ThrowException(Exception::Error(String::New(strerror(errno))));
894   }
895
896   Local<Object> info = Object::New();
897
898   if (rss_symbol.IsEmpty()) {
899     rss_symbol = NODE_PSYMBOL("rss");
900     vsize_symbol = NODE_PSYMBOL("vsize");
901     heap_total_symbol = NODE_PSYMBOL("heapTotal");
902     heap_used_symbol = NODE_PSYMBOL("heapUsed");
903   }
904
905   info->Set(rss_symbol, Integer::NewFromUnsigned(rss));
906   info->Set(vsize_symbol, Integer::NewFromUnsigned(vsize));
907
908   // V8 memory usage
909   HeapStatistics v8_heap_stats;
910   V8::GetHeapStatistics(&v8_heap_stats);
911   info->Set(heap_total_symbol,
912             Integer::NewFromUnsigned(v8_heap_stats.total_heap_size()));
913   info->Set(heap_used_symbol,
914             Integer::NewFromUnsigned(v8_heap_stats.used_heap_size()));
915
916   return scope.Close(info);
917 #endif
918 }
919
920
921 v8::Handle<v8::Value> Kill(const v8::Arguments& args) {
922   HandleScope scope;
923
924   if (args.Length() < 1 || !args[0]->IsNumber()) {
925     return ThrowException(Exception::Error(String::New("Bad argument.")));
926   }
927
928   pid_t pid = args[0]->IntegerValue();
929
930   int sig = SIGTERM;
931
932   if (args.Length() >= 2) {
933     if (args[1]->IsNumber()) {
934       sig = args[1]->Int32Value();
935     } else if (args[1]->IsString()) {
936       Local<String> signame = args[1]->ToString();
937
938       Local<Value> sig_v = process->Get(signame);
939       if (!sig_v->IsNumber()) {
940         return ThrowException(Exception::Error(String::New("Unknown signal")));
941       }
942       sig = sig_v->Int32Value();
943     }
944   }
945
946   int r = kill(pid, sig);
947
948   if (r != 0) {
949     return ThrowException(Exception::Error(String::New(strerror(errno))));
950   }
951
952   return Undefined();
953 }
954
955 typedef void (*extInit)(Handle<Object> exports);
956
957 // DLOpen is node.dlopen(). Used to load 'module.node' dynamically shared
958 // objects.
959 Handle<Value> DLOpen(const v8::Arguments& args) {
960   HandleScope scope;
961
962   if (args.Length() < 2) return Undefined();
963
964   String::Utf8Value filename(args[0]->ToString()); // Cast
965   Local<Object> target = args[1]->ToObject(); // Cast
966
967   // Actually call dlopen().
968   // FIXME: This is a blocking function and should be called asynchronously!
969   // This function should be moved to file.cc and use libeio to make this
970   // system call.
971   void *handle = dlopen(*filename, RTLD_LAZY);
972
973   // Handle errors.
974   if (handle == NULL) {
975     Local<Value> exception = Exception::Error(String::New(dlerror()));
976     return ThrowException(exception);
977   }
978
979   // Get the init() function from the dynamically shared object.
980   void *init_handle = dlsym(handle, "init");
981   // Error out if not found.
982   if (init_handle == NULL) {
983     Local<Value> exception =
984       Exception::Error(String::New("No 'init' symbol found in module."));
985     return ThrowException(exception);
986   }
987   extInit init = (extInit)(init_handle); // Cast
988
989   // Execute the C++ module
990   init(target);
991
992   return Undefined();
993 }
994
995 // evalcx(code, sandbox={})
996 // Executes code in a new context
997 Handle<Value> EvalCX(const Arguments& args) {
998   HandleScope scope;
999
1000   Local<String> code = args[0]->ToString();
1001   Local<Object> sandbox = args.Length() > 1 ? args[1]->ToObject()
1002                                             : Object::New();
1003   Local<String> filename = args.Length() > 2 ? args[2]->ToString()
1004                                              : String::New("evalcx");
1005   // Create the new context
1006   Persistent<Context> context = Context::New();
1007
1008   // Enter and compile script
1009   context->Enter();
1010
1011   // Copy objects from global context, to our brand new context
1012   Handle<Array> keys = sandbox->GetPropertyNames();
1013
1014   unsigned int i;
1015   for (i = 0; i < keys->Length(); i++) {
1016     Handle<String> key = keys->Get(Integer::New(i))->ToString();
1017     Handle<Value> value = sandbox->Get(key);
1018     context->Global()->Set(key, value);
1019   }
1020
1021   // Catch errors
1022   TryCatch try_catch;
1023
1024   Local<v8::Script> script = v8::Script::Compile(code, filename);
1025   Handle<Value> result;
1026
1027   if (script.IsEmpty()) {
1028     result = ThrowException(try_catch.Exception());
1029   } else {
1030     result = script->Run();
1031     if (result.IsEmpty()) {
1032       result = ThrowException(try_catch.Exception());
1033     } else {
1034       // success! copy changes back onto the sandbox object.
1035       keys = context->Global()->GetPropertyNames();
1036       for (i = 0; i < keys->Length(); i++) {
1037         Handle<String> key = keys->Get(Integer::New(i))->ToString();
1038         Handle<Value> value = context->Global()->Get(key);
1039         sandbox->Set(key, value);
1040       }
1041     }
1042   }
1043
1044   // Clean up, clean up, everybody everywhere!
1045   context->DetachGlobal();
1046   context->Exit();
1047   context.Dispose();
1048
1049   return scope.Close(result);
1050 }
1051
1052 Handle<Value> Compile(const Arguments& args) {
1053   HandleScope scope;
1054
1055   if (args.Length() < 2) {
1056     return ThrowException(Exception::TypeError(
1057           String::New("needs two arguments.")));
1058   }
1059
1060   Local<String> source = args[0]->ToString();
1061   Local<String> filename = args[1]->ToString();
1062
1063   TryCatch try_catch;
1064
1065   Local<v8::Script> script = v8::Script::Compile(source, filename);
1066   if (try_catch.HasCaught()) {
1067     // Hack because I can't get a proper stacktrace on SyntaxError
1068     ReportException(try_catch, true);
1069     exit(1);
1070   }
1071
1072   Local<Value> result = script->Run();
1073   if (try_catch.HasCaught()) return try_catch.ReThrow();
1074
1075   return scope.Close(result);
1076 }
1077
1078 static void OnFatalError(const char* location, const char* message) {
1079   if (location) {
1080     fprintf(stderr, "FATAL ERROR: %s %s\n", location, message);
1081   } else {
1082     fprintf(stderr, "FATAL ERROR: %s\n", message);
1083   }
1084   exit(1);
1085 }
1086
1087 static int uncaught_exception_counter = 0;
1088
1089 void FatalException(TryCatch &try_catch) {
1090   HandleScope scope;
1091
1092   // Check if uncaught_exception_counter indicates a recursion
1093   if (uncaught_exception_counter > 0) {
1094     ReportException(try_catch);
1095     exit(1);
1096   }
1097
1098   if (listeners_symbol.IsEmpty()) {
1099     listeners_symbol = NODE_PSYMBOL("listeners");
1100     uncaught_exception_symbol = NODE_PSYMBOL("uncaughtException");
1101     emit_symbol = NODE_PSYMBOL("emit");
1102   }
1103
1104   Local<Value> listeners_v = process->Get(listeners_symbol);
1105   assert(listeners_v->IsFunction());
1106
1107   Local<Function> listeners = Local<Function>::Cast(listeners_v);
1108
1109   Local<String> uncaught_exception_symbol_l = Local<String>::New(uncaught_exception_symbol);
1110   Local<Value> argv[1] = { uncaught_exception_symbol_l  };
1111   Local<Value> ret = listeners->Call(process, 1, argv);
1112
1113   assert(ret->IsArray());
1114
1115   Local<Array> listener_array = Local<Array>::Cast(ret);
1116
1117   uint32_t length = listener_array->Length();
1118   // Report and exit if process has no "uncaughtException" listener
1119   if (length == 0) {
1120     ReportException(try_catch);
1121     exit(1);
1122   }
1123
1124   // Otherwise fire the process "uncaughtException" event
1125   Local<Value> emit_v = process->Get(emit_symbol);
1126   assert(emit_v->IsFunction());
1127
1128   Local<Function> emit = Local<Function>::Cast(emit_v);
1129
1130   Local<Value> error = try_catch.Exception();
1131   Local<Value> event_argv[2] = { uncaught_exception_symbol_l, error };
1132
1133   uncaught_exception_counter++;
1134   emit->Call(process, 2, event_argv);
1135   // Decrement so we know if the next exception is a recursion or not
1136   uncaught_exception_counter--;
1137 }
1138
1139
1140 static ev_async debug_watcher;
1141 volatile static bool debugger_msg_pending = false;
1142
1143 static void DebugMessageCallback(EV_P_ ev_async *watcher, int revents) {
1144   HandleScope scope;
1145   assert(watcher == &debug_watcher);
1146   assert(revents == EV_ASYNC);
1147   Debug::ProcessDebugMessages();
1148 }
1149
1150 static void DebugMessageDispatch(void) {
1151   // This function is called from V8's debug thread when a debug TCP client
1152   // has sent a message.
1153
1154   // Send a signal to our main thread saying that it should enter V8 to
1155   // handle the message.
1156   debugger_msg_pending = true;
1157   ev_async_send(EV_DEFAULT_UC_ &debug_watcher);
1158 }
1159
1160 static Handle<Value> CheckBreak(const Arguments& args) {
1161   HandleScope scope;
1162   assert(args.Length() == 0);
1163
1164   // TODO FIXME This function is a hack to wait until V8 is ready to accept
1165   // commands. There seems to be a bug in EnableAgent( _ , _ , true) which
1166   // makes it unusable here. Ideally we'd be able to bind EnableAgent and
1167   // get it to halt until Eclipse connects.
1168
1169   if (!debug_wait_connect)
1170     return Undefined();
1171
1172   printf("Waiting for remote debugger connection...\n");
1173
1174   const int halfSecond = 50;
1175   const int tenMs=10000;
1176   debugger_msg_pending = false;
1177   for (;;) {
1178     if (debugger_msg_pending) {
1179       Debug::DebugBreak();
1180       Debug::ProcessDebugMessages();
1181       debugger_msg_pending = false;
1182
1183       // wait for 500 msec of silence from remote debugger
1184       int cnt = halfSecond;
1185         while (cnt --) {
1186         debugger_msg_pending = false;
1187         usleep(tenMs);
1188         if (debugger_msg_pending) {
1189           debugger_msg_pending = false;
1190           cnt = halfSecond;
1191         }
1192       }
1193       break;
1194     }
1195     usleep(tenMs);
1196   }
1197   return Undefined();
1198 }
1199
1200 Persistent<Object> binding_cache;
1201
1202 static Handle<Value> Binding(const Arguments& args) {
1203   HandleScope scope;
1204
1205   Local<String> module = args[0]->ToString();
1206   String::Utf8Value module_v(module);
1207
1208   if (binding_cache.IsEmpty()) {
1209     binding_cache = Persistent<Object>::New(Object::New());
1210   }
1211
1212   Local<Object> exports;
1213
1214   // TODO DRY THIS UP!
1215
1216   if (!strcmp(*module_v, "stdio")) {
1217     if (binding_cache->Has(module)) {
1218       exports = binding_cache->Get(module)->ToObject();
1219     } else {
1220       exports = Object::New();
1221       Stdio::Initialize(exports);
1222       binding_cache->Set(module, exports);
1223     }
1224
1225   } else if (!strcmp(*module_v, "http")) {
1226     if (binding_cache->Has(module)) {
1227       exports = binding_cache->Get(module)->ToObject();
1228     } else {
1229       // Warning: When calling requireBinding('http') from javascript then
1230       // be sure that you call requireBinding('tcp') before it.
1231       assert(binding_cache->Has(String::New("tcp")));
1232       exports = Object::New();
1233       HTTPServer::Initialize(exports);
1234       HTTPConnection::Initialize(exports);
1235       binding_cache->Set(module, exports);
1236     }
1237
1238   } else if (!strcmp(*module_v, "tcp")) {
1239     if (binding_cache->Has(module)) {
1240       exports = binding_cache->Get(module)->ToObject();
1241     } else {
1242       exports = Object::New();
1243       Server::Initialize(exports);
1244       Connection::Initialize(exports);
1245       binding_cache->Set(module, exports);
1246     }
1247
1248   } else if (!strcmp(*module_v, "cares")) {
1249     if (binding_cache->Has(module)) {
1250       exports = binding_cache->Get(module)->ToObject();
1251     } else {
1252       exports = Object::New();
1253       Cares::Initialize(exports);
1254       binding_cache->Set(module, exports);
1255     }
1256
1257   } else if (!strcmp(*module_v, "fs")) {
1258     if (binding_cache->Has(module)) {
1259       exports = binding_cache->Get(module)->ToObject();
1260     } else {
1261       exports = Object::New();
1262
1263       // Initialize the stats object
1264       Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
1265       stats_constructor_template = Persistent<FunctionTemplate>::New(stat_templ);
1266       exports->Set(String::NewSymbol("Stats"),
1267                    stats_constructor_template->GetFunction());
1268       StatWatcher::Initialize(exports);
1269       File::Initialize(exports);
1270       binding_cache->Set(module, exports);
1271     }
1272
1273   } else if (!strcmp(*module_v, "signal_watcher")) {
1274     if (binding_cache->Has(module)) {
1275       exports = binding_cache->Get(module)->ToObject();
1276     } else {
1277       exports = Object::New();
1278       SignalWatcher::Initialize(exports);
1279       binding_cache->Set(module, exports);
1280     }
1281
1282   } else if (!strcmp(*module_v, "net")) {
1283     if (binding_cache->Has(module)) {
1284       exports = binding_cache->Get(module)->ToObject();
1285     } else {
1286       exports = Object::New();
1287       InitNet2(exports);
1288       binding_cache->Set(module, exports);
1289     }
1290
1291   } else if (!strcmp(*module_v, "http_parser")) {
1292     if (binding_cache->Has(module)) {
1293       exports = binding_cache->Get(module)->ToObject();
1294     } else {
1295       exports = Object::New();
1296       InitHttpParser(exports);
1297       binding_cache->Set(module, exports);
1298     }
1299
1300   } else if (!strcmp(*module_v, "child_process")) {
1301     if (binding_cache->Has(module)) {
1302       exports = binding_cache->Get(module)->ToObject();
1303     } else {
1304       exports = Object::New();
1305       ChildProcess::Initialize(exports);
1306       binding_cache->Set(module, exports);
1307     }
1308
1309   } else if (!strcmp(*module_v, "buffer")) {
1310     if (binding_cache->Has(module)) {
1311       exports = binding_cache->Get(module)->ToObject();
1312     } else {
1313       exports = Object::New();
1314       Buffer::Initialize(exports);
1315       binding_cache->Set(module, exports);
1316     }
1317   #ifdef HAVE_OPENSSL
1318   } else if (!strcmp(*module_v, "crypto")) {
1319     if (binding_cache->Has(module)) {
1320       exports = binding_cache->Get(module)->ToObject();
1321     } else {
1322       exports = Object::New();
1323       InitCrypto(exports);
1324       binding_cache->Set(module, exports);
1325     }
1326   #endif
1327   } else if (!strcmp(*module_v, "evals")) {
1328     if (binding_cache->Has(module)) {
1329       exports = binding_cache->Get(module)->ToObject();
1330     } else {
1331       exports = Object::New();
1332       node::Script::Initialize(exports);
1333       binding_cache->Set(module, exports);
1334     }
1335
1336   } else if (!strcmp(*module_v, "natives")) {
1337     if (binding_cache->Has(module)) {
1338       exports = binding_cache->Get(module)->ToObject();
1339     } else {
1340       exports = Object::New();
1341       // Explicitly define native sources.
1342       // TODO DRY/automate this?
1343       exports->Set(String::New("assert"),       String::New(native_assert));
1344       exports->Set(String::New("buffer"),       String::New(native_buffer));
1345       exports->Set(String::New("child_process"),String::New(native_child_process));
1346       exports->Set(String::New("dns"),          String::New(native_dns));
1347       exports->Set(String::New("events"),       String::New(native_events));
1348       exports->Set(String::New("file"),         String::New(native_file));
1349       exports->Set(String::New("freelist"),     String::New(native_freelist));
1350       exports->Set(String::New("fs"),           String::New(native_fs));
1351       exports->Set(String::New("http"),         String::New(native_http));
1352       exports->Set(String::New("http_old"),     String::New(native_http_old));
1353       exports->Set(String::New("crypto"),       String::New(native_crypto));
1354       exports->Set(String::New("ini"),          String::New(native_ini));
1355       exports->Set(String::New("mjsunit"),      String::New(native_mjsunit));
1356       exports->Set(String::New("net"),          String::New(native_net));
1357       exports->Set(String::New("posix"),        String::New(native_posix));
1358       exports->Set(String::New("querystring"),  String::New(native_querystring));
1359       exports->Set(String::New("repl"),         String::New(native_repl));
1360       exports->Set(String::New("sys"),          String::New(native_sys));
1361       exports->Set(String::New("tcp"),          String::New(native_tcp));
1362       exports->Set(String::New("tcp_old"),     String::New(native_tcp_old));
1363       exports->Set(String::New("uri"),          String::New(native_uri));
1364       exports->Set(String::New("url"),          String::New(native_url));
1365       exports->Set(String::New("utils"),        String::New(native_utils));
1366       binding_cache->Set(module, exports);
1367     }
1368
1369   } else {
1370     assert(0);
1371     return ThrowException(Exception::Error(String::New("No such module")));
1372   }
1373
1374   return scope.Close(exports);
1375 }
1376
1377
1378 static void Load(int argc, char *argv[]) {
1379   HandleScope scope;
1380
1381   Local<FunctionTemplate> process_template = FunctionTemplate::New();
1382   node::EventEmitter::Initialize(process_template);
1383
1384   process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
1385
1386   // Add a reference to the global object
1387   Local<Object> global = Context::GetCurrent()->Global();
1388   process->Set(String::NewSymbol("global"), global);
1389
1390   // process.version
1391   process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
1392   // process.installPrefix
1393   process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
1394
1395   // process.platform
1396 #define xstr(s) str(s)
1397 #define str(s) #s
1398   process->Set(String::NewSymbol("platform"), String::New(xstr(PLATFORM)));
1399
1400   // process.argv
1401   int i, j;
1402   Local<Array> arguments = Array::New(argc - option_end_index + 1);
1403   arguments->Set(Integer::New(0), String::New(argv[0]));
1404   for (j = 1, i = option_end_index + 1; i < argc; j++, i++) {
1405     Local<String> arg = String::New(argv[i]);
1406     arguments->Set(Integer::New(j), arg);
1407   }
1408   // assign it
1409   process->Set(String::NewSymbol("ARGV"), arguments);
1410   process->Set(String::NewSymbol("argv"), arguments);
1411
1412   // create process.env
1413   Local<Object> env = Object::New();
1414   for (i = 0; environ[i]; i++) {
1415     // skip entries without a '=' character
1416     for (j = 0; environ[i][j] && environ[i][j] != '='; j++) { ; }
1417     // create the v8 objects
1418     Local<String> field = String::New(environ[i], j);
1419     Local<String> value = Local<String>();
1420     if (environ[i][j] == '=') {
1421       value = String::New(environ[i]+j+1);
1422     }
1423     // assign them
1424     env->Set(field, value);
1425   }
1426   // assign process.ENV
1427   process->Set(String::NewSymbol("ENV"), env);
1428   process->Set(String::NewSymbol("env"), env);
1429
1430   process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
1431
1432   // define various internal methods
1433   NODE_SET_METHOD(process, "loop", Loop);
1434   NODE_SET_METHOD(process, "unloop", Unloop);
1435 //   NODE_SET_METHOD(process, "evalcx", EvalCX);
1436   NODE_SET_METHOD(process, "compile", Compile);
1437   NODE_SET_METHOD(process, "_byteLength", ByteLength);
1438   NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
1439   NODE_SET_METHOD(process, "reallyExit", Exit);
1440   NODE_SET_METHOD(process, "chdir", Chdir);
1441   NODE_SET_METHOD(process, "cwd", Cwd);
1442   NODE_SET_METHOD(process, "getuid", GetUid);
1443   NODE_SET_METHOD(process, "setuid", SetUid);
1444
1445   NODE_SET_METHOD(process, "setgid", SetGid);
1446   NODE_SET_METHOD(process, "getgid", GetGid);
1447
1448   NODE_SET_METHOD(process, "umask", Umask);
1449   NODE_SET_METHOD(process, "dlopen", DLOpen);
1450   NODE_SET_METHOD(process, "kill", Kill);
1451   NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
1452   NODE_SET_METHOD(process, "checkBreak", CheckBreak);
1453
1454   NODE_SET_METHOD(process, "binding", Binding);
1455
1456   // Assign the EventEmitter. It was created in main().
1457   process->Set(String::NewSymbol("EventEmitter"),
1458                EventEmitter::constructor_template->GetFunction());
1459
1460
1461   // Initialize the C++ modules..................filename of module
1462   IOWatcher::Initialize(process);              // io_watcher.cc
1463   // Not in use at the moment.
1464   //IdleWatcher::Initialize(process);            // idle_watcher.cc
1465   Timer::Initialize(process);                  // timer.cc
1466   DefineConstants(process);                    // constants.cc
1467
1468   // Compile, execute the src/node.js file. (Which was included as static C
1469   // string in node_natives.h. 'natve_node' is the string containing that
1470   // source code.)
1471
1472   // The node.js file returns a function 'f'
1473
1474 #ifndef NDEBUG
1475   TryCatch try_catch;
1476 #endif
1477
1478   Local<Value> f_value = ExecuteString(String::New(native_node),
1479                                        String::New("node.js"));
1480 #ifndef NDEBUG
1481   if (try_catch.HasCaught())  {
1482     ReportException(try_catch);
1483     exit(10);
1484   }
1485 #endif
1486   assert(f_value->IsFunction());
1487   Local<Function> f = Local<Function>::Cast(f_value);
1488
1489   // Now we call 'f' with the 'process' variable that we've built up with
1490   // all our bindings. Inside node.js we'll take care of assigning things to
1491   // their places.
1492
1493   // We start the process this way in order to be more modular. Developers
1494   // who do not like how 'src/node.js' setups the module system but do like
1495   // Node's I/O bindings may want to replace 'f' with their own function.
1496
1497   Local<Value> args[1] = { Local<Value>::New(process) };
1498
1499   f->Call(global, 1, args);
1500
1501 #ifndef NDEBUG
1502   if (try_catch.HasCaught())  {
1503     ReportException(try_catch);
1504     exit(11);
1505   }
1506 #endif
1507 }
1508
1509 static void PrintHelp();
1510
1511 static void ParseDebugOpt(const char* arg) {
1512   const char *p = 0;
1513
1514   use_debug_agent = true;
1515   if (!strcmp (arg, "--debug-brk")) {
1516     debug_wait_connect = true;
1517     return;
1518   } else if (!strcmp(arg, "--debug")) {
1519     return;
1520   } else if (strstr(arg, "--debug-brk=") == arg) {
1521     debug_wait_connect = true;
1522     p = 1 + strchr(arg, '=');
1523     debug_port = atoi(p);
1524   } else if (strstr(arg, "--debug=") == arg) {
1525     p = 1 + strchr(arg, '=');
1526     debug_port = atoi(p);
1527   }
1528   if (p && debug_port > 1024 && debug_port <  65536)
1529       return;
1530
1531   fprintf(stderr, "Bad debug option.\n");
1532   if (p) fprintf(stderr, "Debug port must be in range 1025 to 65535.\n");
1533
1534   PrintHelp();
1535   exit(1);
1536 }
1537
1538 static void PrintHelp() {
1539   printf("Usage: node [options] script.js [arguments] \n"
1540          "Options:\n"
1541          "  -v, --version      print node's version\n"
1542          "  --debug[=port]     enable remote debugging via given TCP port\n"
1543          "                     without stopping the execution\n"
1544          "  --debug-brk[=port] as above, but break in script.js and\n"
1545          "                     wait for remote debugger to connect\n"
1546          "  --v8-options       print v8 command line options\n"
1547          "  --vars             print various compiled-in variables\n"
1548          "\n"
1549          "Enviromental variables:\n"
1550          "NODE_PATH            ':'-separated list of directories\n"
1551          "                     prefixed to the module search path,\n"
1552          "                     require.paths.\n"
1553          "NODE_DEBUG           Print additional debugging output.\n"
1554          "\n"
1555          "Documentation can be found at http://nodejs.org/api.html"
1556          " or with 'man node'\n");
1557 }
1558
1559 // Parse node command line arguments.
1560 static void ParseArgs(int *argc, char **argv) {
1561   // TODO use parse opts
1562   for (int i = 1; i < *argc; i++) {
1563     const char *arg = argv[i];
1564     if (strstr(arg, "--debug") == arg) {
1565       ParseDebugOpt(arg);
1566       argv[i] = const_cast<char*>("");
1567       option_end_index = i;
1568     } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
1569       printf("%s\n", NODE_VERSION);
1570       exit(0);
1571     } else if (strcmp(arg, "--vars") == 0) {
1572       printf("NODE_PREFIX: %s\n", NODE_PREFIX);
1573       printf("NODE_CFLAGS: %s\n", NODE_CFLAGS);
1574       exit(0);
1575     } else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
1576       PrintHelp();
1577       exit(0);
1578     } else if (strcmp(arg, "--v8-options") == 0) {
1579       argv[i] = const_cast<char*>("--help");
1580       option_end_index = i+1;
1581     } else if (argv[i][0] != '-') {
1582       option_end_index = i-1;
1583       break;
1584     }
1585   }
1586 }
1587
1588 }  // namespace node
1589
1590
1591 int main(int argc, char *argv[]) {
1592   // Parse a few arguments which are specific to Node.
1593   node::ParseArgs(&argc, argv);
1594   // Parse the rest of the args (up to the 'option_end_index' (where '--' was
1595   // in the command line))
1596   V8::SetFlagsFromCommandLine(&node::option_end_index, argv, false);
1597
1598   // Error out if we don't have a script argument.
1599   if (argc < 2) {
1600     fprintf(stderr, "No script was specified.\n");
1601     node::PrintHelp();
1602     return 1;
1603   }
1604
1605   // Ignore the SIGPIPE
1606   evcom_ignore_sigpipe();
1607
1608   // Initialize the default ev loop.
1609 #ifdef __sun
1610   // TODO(Ryan) I'm experiencing abnormally high load using Solaris's
1611   // EVBACKEND_PORT. Temporarally forcing select() until I debug.
1612   ev_default_loop(EVBACKEND_SELECT);
1613 #else
1614   ev_default_loop(EVFLAG_AUTO);
1615 #endif
1616
1617   ev_prepare_init(&node::next_tick_watcher, node::Tick);
1618   ev_prepare_start(EV_DEFAULT_UC_ &node::next_tick_watcher);
1619   ev_unref(EV_DEFAULT_UC);
1620
1621   ev_idle_init(&node::tick_spinner, node::Spin);
1622
1623   ev_timer_init(&node::gc_timer, node::CheckIdleness, 2*GC_INTERVAL, 2*GC_INTERVAL);
1624
1625   ev_check_init(&node::gc_check, node::Activity);
1626   ev_check_start(EV_DEFAULT_UC_ &node::gc_check);
1627   ev_unref(EV_DEFAULT_UC);
1628
1629   ev_idle_init(&node::gc_idle, node::NotifyIdleness);
1630
1631
1632   // Setup the EIO thread pool
1633   { // It requires 3, yes 3, watchers.
1634     ev_idle_init(&node::eio_poller, node::DoPoll);
1635
1636     ev_async_init(&node::eio_want_poll_notifier, node::WantPollNotifier);
1637     ev_async_start(EV_DEFAULT_UC_ &node::eio_want_poll_notifier);
1638     ev_unref(EV_DEFAULT_UC);
1639
1640     ev_async_init(&node::eio_done_poll_notifier, node::DonePollNotifier);
1641     ev_async_start(EV_DEFAULT_UC_ &node::eio_done_poll_notifier);
1642     ev_unref(EV_DEFAULT_UC);
1643
1644     eio_init(node::EIOWantPoll, node::EIODonePoll);
1645     // Don't handle more than 10 reqs on each eio_poll(). This is to avoid
1646     // race conditions. See test/mjsunit/test-eio-race.js
1647     eio_set_max_poll_reqs(10);
1648   }
1649
1650   V8::Initialize();
1651   HandleScope handle_scope;
1652
1653   V8::SetFatalErrorHandler(node::OnFatalError);
1654
1655   // If the --debug flag was specified then initialize the debug thread.
1656   if (node::use_debug_agent) {
1657     // Initialize the async watcher for receiving messages from the debug
1658     // thread and marshal it into the main thread. DebugMessageCallback()
1659     // is called from the main thread to execute a random bit of javascript
1660     // - which will give V8 control so it can handle whatever new message
1661     // had been received on the debug thread.
1662     ev_async_init(&node::debug_watcher, node::DebugMessageCallback);
1663     ev_set_priority(&node::debug_watcher, EV_MAXPRI);
1664     // Set the callback DebugMessageDispatch which is called from the debug
1665     // thread.
1666     Debug::SetDebugMessageDispatchHandler(node::DebugMessageDispatch);
1667     // Start the async watcher.
1668     ev_async_start(EV_DEFAULT_UC_ &node::debug_watcher);
1669     // unref it so that we exit the event loop despite it being active.
1670     ev_unref(EV_DEFAULT_UC);
1671
1672     // Start the debug thread and it's associated TCP server on port 5858.
1673     bool r = Debug::EnableAgent("node " NODE_VERSION, node::debug_port);
1674
1675     // Crappy check that everything went well. FIXME
1676     assert(r);
1677     // Print out some information.
1678     printf("debugger listening on port %d\n", node::debug_port);
1679   }
1680
1681   // Create the one and only Context.
1682   Persistent<Context> context = Context::New();
1683   Context::Scope context_scope(context);
1684
1685   // Create all the objects, load modules, do everything.
1686   // so your next reading stop should be node::Load()!
1687   node::Load(argc, argv);
1688
1689   node::Stdio::Flush();
1690
1691 #ifndef NDEBUG
1692   // Clean up.
1693   context.Dispose();
1694   V8::Dispose();
1695 #endif  // NDEBUG
1696   return 0;
1697 }
1698