Change GC idle notify so that it runs along side setInterval
[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_file.h>
23 #if 0
24 // not in use
25 # include <node_idle_watcher.h>
26 #endif
27 #include <node_http_parser.h>
28 #include <node_signal_watcher.h>
29 #include <node_stat_watcher.h>
30 #include <node_timer.h>
31 #include <node_child_process.h>
32 #include <node_constants.h>
33 #include <node_stdio.h>
34 #include <node_natives.h>
35 #include <node_version.h>
36 #ifdef HAVE_OPENSSL
37 #include <node_crypto.h>
38 #endif
39 #include <node_script.h>
40
41 #include <v8-debug.h>
42
43 using namespace v8;
44
45 extern char **environ;
46
47 namespace node {
48
49 static Persistent<Object> process;
50
51 static Persistent<String> errno_symbol;
52 static Persistent<String> syscall_symbol;
53
54 static Persistent<String> dev_symbol;
55 static Persistent<String> ino_symbol;
56 static Persistent<String> mode_symbol;
57 static Persistent<String> nlink_symbol;
58 static Persistent<String> uid_symbol;
59 static Persistent<String> gid_symbol;
60 static Persistent<String> rdev_symbol;
61 static Persistent<String> size_symbol;
62 static Persistent<String> blksize_symbol;
63 static Persistent<String> blocks_symbol;
64 static Persistent<String> atime_symbol;
65 static Persistent<String> mtime_symbol;
66 static Persistent<String> ctime_symbol;
67
68 static Persistent<String> rss_symbol;
69 static Persistent<String> vsize_symbol;
70 static Persistent<String> heap_total_symbol;
71 static Persistent<String> heap_used_symbol;
72
73 static Persistent<String> listeners_symbol;
74 static Persistent<String> uncaught_exception_symbol;
75 static Persistent<String> emit_symbol;
76
77 static int option_end_index = 0;
78 static bool use_debug_agent = false;
79 static bool debug_wait_connect = false;
80 static int debug_port=5858;
81
82 static ev_prepare next_tick_watcher;
83 static ev_idle tick_spinner;
84 static bool need_tick_cb;
85 static Persistent<String> tick_callback_sym;
86
87 static ev_async eio_want_poll_notifier;
88 static ev_async eio_done_poll_notifier;
89 static ev_idle  eio_poller;
90
91 // We need to notify V8 when we're idle so that it can run the garbage
92 // collector. The interface to this is V8::IdleNotification(). It returns
93 // true if the heap hasn't be fully compacted, and needs to be run again.
94 // Returning false means that it doesn't have anymore work to do.
95 //
96 // A rather convoluted algorithm has been devised to determine when Node is
97 // idle. You'll have to figure it out for yourself.
98 static ev_check gc_check;
99 static ev_idle  gc_idle;
100 static ev_timer gc_timer;
101 bool need_gc;
102
103
104 #define FAST_TICK 0.7
105 #define GC_WAIT_TIME 5.
106 #define RPM_SAMPLES 100
107 #define TICK_TIME(n) tick_times[(tick_time_head - (n)) % RPM_SAMPLES]
108 static ev_tstamp tick_times[RPM_SAMPLES];
109 static int tick_time_head;
110
111 static void StartGCTimer () {
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 StopGCTimer () {
119   if (ev_is_active(&gc_timer)) {
120     ev_ref(EV_DEFAULT_UC);
121     ev_timer_stop(&gc_timer);
122   }
123 }
124
125 static void Idle(EV_P_ ev_idle *watcher, int revents) {
126   assert(watcher == &gc_idle);
127   assert(revents == EV_IDLE);
128
129   //fprintf(stderr, "idle\n");
130
131   if (V8::IdleNotification()) {
132     ev_idle_stop(EV_A_ watcher);
133     StopGCTimer();
134   }
135 }
136
137
138 // Called directly after every call to select() (or epoll, or whatever)
139 static void Check(EV_P_ ev_check *watcher, int revents) {
140   assert(watcher == &gc_check);
141   assert(revents == EV_CHECK);
142
143   tick_times[tick_time_head] = ev_now();
144   tick_time_head = (tick_time_head + 1) % RPM_SAMPLES;
145
146   StartGCTimer();
147
148   for (int i = 0; i < (int)(GC_WAIT_TIME/FAST_TICK); i++) {
149     double d = TICK_TIME(i+1) - TICK_TIME(i+2);
150     //printf("d = %f\n", d);
151     // If in the last 5 ticks the difference between
152     // ticks was less than 0.7 seconds, then continue.
153     if (d < FAST_TICK) {
154       //printf("---\n");
155       return;
156     }
157   }
158
159   // Otherwise start the gc!
160
161   //fprintf(stderr, "start idle 2\n");
162   ev_idle_start(EV_A_ &gc_idle);
163 }
164
165
166 static Handle<Value> NeedTickCallback(const Arguments& args) {
167   HandleScope scope;
168   need_tick_cb = true;
169   ev_idle_start(EV_DEFAULT_UC_ &tick_spinner);
170   return Undefined();
171 }
172
173
174 static void Spin(EV_P_ ev_idle *watcher, int revents) {
175   assert(watcher == &tick_spinner);
176   assert(revents == EV_IDLE);
177 }
178
179
180 static void Tick(EV_P_ ev_prepare *watcher, int revents) {
181   assert(watcher == &next_tick_watcher);
182   assert(revents == EV_PREPARE);
183
184   // Avoid entering a V8 scope.
185   if (!need_tick_cb) return;
186
187   need_tick_cb = false;
188   ev_idle_stop(EV_DEFAULT_UC_ &tick_spinner);
189
190   HandleScope scope;
191
192   if (tick_callback_sym.IsEmpty()) {
193     // Lazily set the symbol
194     tick_callback_sym =
195       Persistent<String>::New(String::NewSymbol("_tickCallback"));
196   }
197
198   Local<Value> cb_v = process->Get(tick_callback_sym);
199   if (!cb_v->IsFunction()) return;
200   Local<Function> cb = Local<Function>::Cast(cb_v);
201
202   TryCatch try_catch;
203
204   cb->Call(process, 0, NULL);
205
206   if (try_catch.HasCaught()) {
207     FatalException(try_catch);
208   }
209 }
210
211
212 static void DoPoll(EV_P_ ev_idle *watcher, int revents) {
213   assert(watcher == &eio_poller);
214   assert(revents == EV_IDLE);
215
216   //printf("eio_poller\n");
217
218   if (eio_poll() != -1) {
219     //printf("eio_poller stop\n");
220     ev_idle_stop(EV_DEFAULT_UC_ watcher);
221   }
222 }
223
224
225 // Called from the main thread.
226 static void WantPollNotifier(EV_P_ ev_async *watcher, int revents) {
227   assert(watcher == &eio_want_poll_notifier);
228   assert(revents == EV_ASYNC);
229
230   //printf("want poll notifier\n");
231
232   if (eio_poll() == -1) {
233     //printf("eio_poller start\n");
234     ev_idle_start(EV_DEFAULT_UC_ &eio_poller);
235   }
236 }
237
238
239 static void DonePollNotifier(EV_P_ ev_async *watcher, int revents) {
240   assert(watcher == &eio_done_poll_notifier);
241   assert(revents == EV_ASYNC);
242
243   //printf("done poll notifier\n");
244
245   if (eio_poll() != -1) {
246     //printf("eio_poller stop\n");
247     ev_idle_stop(EV_DEFAULT_UC_ &eio_poller);
248   }
249 }
250
251
252 // EIOWantPoll() is called from the EIO thread pool each time an EIO
253 // request (that is, one of the node.fs.* functions) has completed.
254 static void EIOWantPoll(void) {
255   // Signal the main thread that eio_poll need to be processed.
256   ev_async_send(EV_DEFAULT_UC_ &eio_want_poll_notifier);
257 }
258
259
260 static void EIODonePoll(void) {
261   // Signal the main thread that we should stop calling eio_poll().
262   // from the idle watcher.
263   ev_async_send(EV_DEFAULT_UC_ &eio_done_poll_notifier);
264 }
265
266
267 static inline const char *errno_string(int errorno) {
268 #define ERRNO_CASE(e)  case e: return #e;
269   switch (errorno) {
270
271 #ifdef EACCES
272   ERRNO_CASE(EACCES);
273 #endif
274
275 #ifdef EADDRINUSE
276   ERRNO_CASE(EADDRINUSE);
277 #endif
278
279 #ifdef EADDRNOTAVAIL
280   ERRNO_CASE(EADDRNOTAVAIL);
281 #endif
282
283 #ifdef EAFNOSUPPORT
284   ERRNO_CASE(EAFNOSUPPORT);
285 #endif
286
287 #ifdef EAGAIN
288   ERRNO_CASE(EAGAIN);
289 #endif
290
291 #ifdef EWOULDBLOCK
292 # if EAGAIN != EWOULDBLOCK
293   ERRNO_CASE(EWOULDBLOCK);
294 # endif
295 #endif
296
297 #ifdef EALREADY
298   ERRNO_CASE(EALREADY);
299 #endif
300
301 #ifdef EBADF
302   ERRNO_CASE(EBADF);
303 #endif
304
305 #ifdef EBADMSG
306   ERRNO_CASE(EBADMSG);
307 #endif
308
309 #ifdef EBUSY
310   ERRNO_CASE(EBUSY);
311 #endif
312
313 #ifdef ECANCELED
314   ERRNO_CASE(ECANCELED);
315 #endif
316
317 #ifdef ECHILD
318   ERRNO_CASE(ECHILD);
319 #endif
320
321 #ifdef ECONNABORTED
322   ERRNO_CASE(ECONNABORTED);
323 #endif
324
325 #ifdef ECONNREFUSED
326   ERRNO_CASE(ECONNREFUSED);
327 #endif
328
329 #ifdef ECONNRESET
330   ERRNO_CASE(ECONNRESET);
331 #endif
332
333 #ifdef EDEADLK
334   ERRNO_CASE(EDEADLK);
335 #endif
336
337 #ifdef EDESTADDRREQ
338   ERRNO_CASE(EDESTADDRREQ);
339 #endif
340
341 #ifdef EDOM
342   ERRNO_CASE(EDOM);
343 #endif
344
345 #ifdef EDQUOT
346   ERRNO_CASE(EDQUOT);
347 #endif
348
349 #ifdef EEXIST
350   ERRNO_CASE(EEXIST);
351 #endif
352
353 #ifdef EFAULT
354   ERRNO_CASE(EFAULT);
355 #endif
356
357 #ifdef EFBIG
358   ERRNO_CASE(EFBIG);
359 #endif
360
361 #ifdef EHOSTUNREACH
362   ERRNO_CASE(EHOSTUNREACH);
363 #endif
364
365 #ifdef EIDRM
366   ERRNO_CASE(EIDRM);
367 #endif
368
369 #ifdef EILSEQ
370   ERRNO_CASE(EILSEQ);
371 #endif
372
373 #ifdef EINPROGRESS
374   ERRNO_CASE(EINPROGRESS);
375 #endif
376
377 #ifdef EINTR
378   ERRNO_CASE(EINTR);
379 #endif
380
381 #ifdef EINVAL
382   ERRNO_CASE(EINVAL);
383 #endif
384
385 #ifdef EIO
386   ERRNO_CASE(EIO);
387 #endif
388
389 #ifdef EISCONN
390   ERRNO_CASE(EISCONN);
391 #endif
392
393 #ifdef EISDIR
394   ERRNO_CASE(EISDIR);
395 #endif
396
397 #ifdef ELOOP
398   ERRNO_CASE(ELOOP);
399 #endif
400
401 #ifdef EMFILE
402   ERRNO_CASE(EMFILE);
403 #endif
404
405 #ifdef EMLINK
406   ERRNO_CASE(EMLINK);
407 #endif
408
409 #ifdef EMSGSIZE
410   ERRNO_CASE(EMSGSIZE);
411 #endif
412
413 #ifdef EMULTIHOP
414   ERRNO_CASE(EMULTIHOP);
415 #endif
416
417 #ifdef ENAMETOOLONG
418   ERRNO_CASE(ENAMETOOLONG);
419 #endif
420
421 #ifdef ENETDOWN
422   ERRNO_CASE(ENETDOWN);
423 #endif
424
425 #ifdef ENETRESET
426   ERRNO_CASE(ENETRESET);
427 #endif
428
429 #ifdef ENETUNREACH
430   ERRNO_CASE(ENETUNREACH);
431 #endif
432
433 #ifdef ENFILE
434   ERRNO_CASE(ENFILE);
435 #endif
436
437 #ifdef ENOBUFS
438   ERRNO_CASE(ENOBUFS);
439 #endif
440
441 #ifdef ENODATA
442   ERRNO_CASE(ENODATA);
443 #endif
444
445 #ifdef ENODEV
446   ERRNO_CASE(ENODEV);
447 #endif
448
449 #ifdef ENOENT
450   ERRNO_CASE(ENOENT);
451 #endif
452
453 #ifdef ENOEXEC
454   ERRNO_CASE(ENOEXEC);
455 #endif
456
457 #ifdef ENOLINK
458   ERRNO_CASE(ENOLINK);
459 #endif
460
461 #ifdef ENOLCK
462 # if ENOLINK != ENOLCK
463   ERRNO_CASE(ENOLCK);
464 # endif
465 #endif
466
467 #ifdef ENOMEM
468   ERRNO_CASE(ENOMEM);
469 #endif
470
471 #ifdef ENOMSG
472   ERRNO_CASE(ENOMSG);
473 #endif
474
475 #ifdef ENOPROTOOPT
476   ERRNO_CASE(ENOPROTOOPT);
477 #endif
478
479 #ifdef ENOSPC
480   ERRNO_CASE(ENOSPC);
481 #endif
482
483 #ifdef ENOSR
484   ERRNO_CASE(ENOSR);
485 #endif
486
487 #ifdef ENOSTR
488   ERRNO_CASE(ENOSTR);
489 #endif
490
491 #ifdef ENOSYS
492   ERRNO_CASE(ENOSYS);
493 #endif
494
495 #ifdef ENOTCONN
496   ERRNO_CASE(ENOTCONN);
497 #endif
498
499 #ifdef ENOTDIR
500   ERRNO_CASE(ENOTDIR);
501 #endif
502
503 #ifdef ENOTEMPTY
504   ERRNO_CASE(ENOTEMPTY);
505 #endif
506
507 #ifdef ENOTSOCK
508   ERRNO_CASE(ENOTSOCK);
509 #endif
510
511 #ifdef ENOTSUP
512   ERRNO_CASE(ENOTSUP);
513 #else
514 # ifdef EOPNOTSUPP
515   ERRNO_CASE(EOPNOTSUPP);
516 # endif
517 #endif
518
519 #ifdef ENOTTY
520   ERRNO_CASE(ENOTTY);
521 #endif
522
523 #ifdef ENXIO
524   ERRNO_CASE(ENXIO);
525 #endif
526
527
528 #ifdef EOVERFLOW
529   ERRNO_CASE(EOVERFLOW);
530 #endif
531
532 #ifdef EPERM
533   ERRNO_CASE(EPERM);
534 #endif
535
536 #ifdef EPIPE
537   ERRNO_CASE(EPIPE);
538 #endif
539
540 #ifdef EPROTO
541   ERRNO_CASE(EPROTO);
542 #endif
543
544 #ifdef EPROTONOSUPPORT
545   ERRNO_CASE(EPROTONOSUPPORT);
546 #endif
547
548 #ifdef EPROTOTYPE
549   ERRNO_CASE(EPROTOTYPE);
550 #endif
551
552 #ifdef ERANGE
553   ERRNO_CASE(ERANGE);
554 #endif
555
556 #ifdef EROFS
557   ERRNO_CASE(EROFS);
558 #endif
559
560 #ifdef ESPIPE
561   ERRNO_CASE(ESPIPE);
562 #endif
563
564 #ifdef ESRCH
565   ERRNO_CASE(ESRCH);
566 #endif
567
568 #ifdef ESTALE
569   ERRNO_CASE(ESTALE);
570 #endif
571
572 #ifdef ETIME
573   ERRNO_CASE(ETIME);
574 #endif
575
576 #ifdef ETIMEDOUT
577   ERRNO_CASE(ETIMEDOUT);
578 #endif
579
580 #ifdef ETXTBSY
581   ERRNO_CASE(ETXTBSY);
582 #endif
583
584 #ifdef EXDEV
585   ERRNO_CASE(EXDEV);
586 #endif
587
588   default: return "";
589   }
590 }
591
592 const char *signo_string(int signo) {
593 #define SIGNO_CASE(e)  case e: return #e;
594   switch (signo) {
595
596 #ifdef SIGHUP
597   SIGNO_CASE(SIGHUP);
598 #endif
599
600 #ifdef SIGINT
601   SIGNO_CASE(SIGINT);
602 #endif
603
604 #ifdef SIGQUIT
605   SIGNO_CASE(SIGQUIT);
606 #endif
607
608 #ifdef SIGILL
609   SIGNO_CASE(SIGILL);
610 #endif
611
612 #ifdef SIGTRAP
613   SIGNO_CASE(SIGTRAP);
614 #endif
615
616 #ifdef SIGABRT
617   SIGNO_CASE(SIGABRT);
618 #endif
619
620 #ifdef SIGIOT
621 # if SIGABRT != SIGIOT
622   SIGNO_CASE(SIGIOT);
623 # endif
624 #endif
625
626 #ifdef SIGBUS
627   SIGNO_CASE(SIGBUS);
628 #endif
629
630 #ifdef SIGFPE
631   SIGNO_CASE(SIGFPE);
632 #endif
633
634 #ifdef SIGKILL
635   SIGNO_CASE(SIGKILL);
636 #endif
637
638 #ifdef SIGUSR1
639   SIGNO_CASE(SIGUSR1);
640 #endif
641
642 #ifdef SIGSEGV
643   SIGNO_CASE(SIGSEGV);
644 #endif
645
646 #ifdef SIGUSR2
647   SIGNO_CASE(SIGUSR2);
648 #endif
649
650 #ifdef SIGPIPE
651   SIGNO_CASE(SIGPIPE);
652 #endif
653
654 #ifdef SIGALRM
655   SIGNO_CASE(SIGALRM);
656 #endif
657
658   SIGNO_CASE(SIGTERM);
659   SIGNO_CASE(SIGCHLD);
660
661 #ifdef SIGSTKFLT
662   SIGNO_CASE(SIGSTKFLT);
663 #endif
664
665
666 #ifdef SIGCONT
667   SIGNO_CASE(SIGCONT);
668 #endif
669
670 #ifdef SIGSTOP
671   SIGNO_CASE(SIGSTOP);
672 #endif
673
674 #ifdef SIGTSTP
675   SIGNO_CASE(SIGTSTP);
676 #endif
677
678 #ifdef SIGTTIN
679   SIGNO_CASE(SIGTTIN);
680 #endif
681
682 #ifdef SIGTTOU
683   SIGNO_CASE(SIGTTOU);
684 #endif
685
686 #ifdef SIGURG
687   SIGNO_CASE(SIGURG);
688 #endif
689
690 #ifdef SIGXCPU
691   SIGNO_CASE(SIGXCPU);
692 #endif
693
694 #ifdef SIGXFSZ
695   SIGNO_CASE(SIGXFSZ);
696 #endif
697
698 #ifdef SIGVTALRM
699   SIGNO_CASE(SIGVTALRM);
700 #endif
701
702 #ifdef SIGPROF
703   SIGNO_CASE(SIGPROF);
704 #endif
705
706 #ifdef SIGWINCH
707   SIGNO_CASE(SIGWINCH);
708 #endif
709
710 #ifdef SIGIO
711   SIGNO_CASE(SIGIO);
712 #endif
713
714 #ifdef SIGPOLL
715 # if SIGPOLL != SIGIO
716   SIGNO_CASE(SIGPOLL);
717 # endif
718 #endif
719
720 #ifdef SIGLOST
721   SIGNO_CASE(SIGLOST);
722 #endif
723
724 #ifdef SIGPWR
725   SIGNO_CASE(SIGPWR);
726 #endif
727
728 #ifdef SIGSYS
729   SIGNO_CASE(SIGSYS);
730 #endif
731
732   default: return "";
733   }
734 }
735
736
737 Local<Value> ErrnoException(int errorno,
738                             const char *syscall,
739                             const char *msg) {
740   Local<String> estring = String::NewSymbol(errno_string(errorno));
741   if (!msg[0]) msg = strerror(errorno);
742   Local<String> message = String::NewSymbol(msg);
743
744   Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
745   Local<String> cons2 = String::Concat(cons1, message);
746
747   Local<Value> e = Exception::Error(cons2);
748
749   Local<Object> obj = e->ToObject();
750
751   if (errno_symbol.IsEmpty()) {
752     syscall_symbol = NODE_PSYMBOL("syscall");
753     errno_symbol = NODE_PSYMBOL("errno");
754   }
755
756   obj->Set(errno_symbol, Integer::New(errorno));
757   if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
758   return e;
759 }
760
761
762 enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
763   HandleScope scope;
764
765   if (!encoding_v->IsString()) return _default;
766
767   String::Utf8Value encoding(encoding_v->ToString());
768
769   if (strcasecmp(*encoding, "utf8") == 0) {
770     return UTF8;
771   } else if (strcasecmp(*encoding, "utf-8") == 0) {
772     return UTF8;
773   } else if (strcasecmp(*encoding, "ascii") == 0) {
774     return ASCII;
775   } else if (strcasecmp(*encoding, "binary") == 0) {
776     return BINARY;
777   } else if (strcasecmp(*encoding, "raw") == 0) {
778     fprintf(stderr, "'raw' (array of integers) has been removed. "
779                     "Use 'binary'.\n");
780     return BINARY;
781   } else if (strcasecmp(*encoding, "raws") == 0) {
782     fprintf(stderr, "'raws' encoding has been renamed to 'binary'. "
783                     "Please update your code.\n");
784     return BINARY;
785   } else {
786     return _default;
787   }
788 }
789
790 Local<Value> Encode(const void *buf, size_t len, enum encoding encoding) {
791   HandleScope scope;
792
793   if (!len) return scope.Close(String::Empty());
794
795   if (encoding == BINARY) {
796     const unsigned char *cbuf = static_cast<const unsigned char*>(buf);
797     uint16_t * twobytebuf = new uint16_t[len];
798     for (size_t i = 0; i < len; i++) {
799       // XXX is the following line platform independent?
800       twobytebuf[i] = cbuf[i];
801     }
802     Local<String> chunk = String::New(twobytebuf, len);
803     delete [] twobytebuf; // TODO use ExternalTwoByteString?
804     return scope.Close(chunk);
805   }
806
807   // utf8 or ascii encoding
808   Local<String> chunk = String::New((const char*)buf, len);
809   return scope.Close(chunk);
810 }
811
812 // Returns -1 if the handle was not valid for decoding
813 ssize_t DecodeBytes(v8::Handle<v8::Value> val, enum encoding encoding) {
814   HandleScope scope;
815
816   if (val->IsArray()) {
817     fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
818                     "Use 'binary'.\n");
819     assert(0);
820     return -1;
821   }
822
823   Local<String> str = val->ToString();
824
825   if (encoding == UTF8) return str->Utf8Length();
826
827   return str->Length();
828 }
829
830 #ifndef MIN
831 # define MIN(a, b) ((a) < (b) ? (a) : (b))
832 #endif
833
834 // Returns number of bytes written.
835 ssize_t DecodeWrite(char *buf,
836                     size_t buflen,
837                     v8::Handle<v8::Value> val,
838                     enum encoding encoding) {
839   HandleScope scope;
840
841   // XXX
842   // A lot of improvement can be made here. See:
843   // http://code.google.com/p/v8/issues/detail?id=270
844   // http://groups.google.com/group/v8-dev/browse_thread/thread/dba28a81d9215291/ece2b50a3b4022c
845   // http://groups.google.com/group/v8-users/browse_thread/thread/1f83b0ba1f0a611
846
847   if (val->IsArray()) {
848     fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
849                     "Use 'binary'.\n");
850     assert(0);
851     return -1;
852   }
853
854   Local<String> str = val->ToString();
855
856   if (encoding == UTF8) {
857     str->WriteUtf8(buf, buflen, NULL, String::HINT_MANY_WRITES_EXPECTED);
858     return buflen;
859   }
860
861   if (encoding == ASCII) {
862     str->WriteAscii(buf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
863     return buflen;
864   }
865
866   // THIS IS AWFUL!!! FIXME
867
868   assert(encoding == BINARY);
869
870   uint16_t * twobytebuf = new uint16_t[buflen];
871
872   str->Write(twobytebuf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
873
874   for (size_t i = 0; i < buflen; i++) {
875     unsigned char *b = reinterpret_cast<unsigned char*>(&twobytebuf[i]);
876     assert(b[1] == 0);
877     buf[i] = b[0];
878   }
879
880   delete [] twobytebuf;
881
882   return buflen;
883 }
884
885 static Persistent<FunctionTemplate> stats_constructor_template;
886
887 Local<Object> BuildStatsObject(struct stat * s) {
888   HandleScope scope;
889
890   if (dev_symbol.IsEmpty()) {
891     dev_symbol = NODE_PSYMBOL("dev");
892     ino_symbol = NODE_PSYMBOL("ino");
893     mode_symbol = NODE_PSYMBOL("mode");
894     nlink_symbol = NODE_PSYMBOL("nlink");
895     uid_symbol = NODE_PSYMBOL("uid");
896     gid_symbol = NODE_PSYMBOL("gid");
897     rdev_symbol = NODE_PSYMBOL("rdev");
898     size_symbol = NODE_PSYMBOL("size");
899     blksize_symbol = NODE_PSYMBOL("blksize");
900     blocks_symbol = NODE_PSYMBOL("blocks");
901     atime_symbol = NODE_PSYMBOL("atime");
902     mtime_symbol = NODE_PSYMBOL("mtime");
903     ctime_symbol = NODE_PSYMBOL("ctime");
904   }
905
906   Local<Object> stats =
907     stats_constructor_template->GetFunction()->NewInstance();
908
909   /* ID of device containing file */
910   stats->Set(dev_symbol, Integer::New(s->st_dev));
911
912   /* inode number */
913   stats->Set(ino_symbol, Integer::New(s->st_ino));
914
915   /* protection */
916   stats->Set(mode_symbol, Integer::New(s->st_mode));
917
918   /* number of hard links */
919   stats->Set(nlink_symbol, Integer::New(s->st_nlink));
920
921   /* user ID of owner */
922   stats->Set(uid_symbol, Integer::New(s->st_uid));
923
924   /* group ID of owner */
925   stats->Set(gid_symbol, Integer::New(s->st_gid));
926
927   /* device ID (if special file) */
928   stats->Set(rdev_symbol, Integer::New(s->st_rdev));
929
930   /* total size, in bytes */
931   stats->Set(size_symbol, Integer::New(s->st_size));
932
933   /* blocksize for filesystem I/O */
934   stats->Set(blksize_symbol, Integer::New(s->st_blksize));
935
936   /* number of blocks allocated */
937   stats->Set(blocks_symbol, Integer::New(s->st_blocks));
938
939   /* time of last access */
940   stats->Set(atime_symbol, NODE_UNIXTIME_V8(s->st_atime));
941
942   /* time of last modification */
943   stats->Set(mtime_symbol, NODE_UNIXTIME_V8(s->st_mtime));
944
945   /* time of last status change */
946   stats->Set(ctime_symbol, NODE_UNIXTIME_V8(s->st_ctime));
947
948   return scope.Close(stats);
949 }
950
951
952 // Extracts a C str from a V8 Utf8Value.
953 const char* ToCString(const v8::String::Utf8Value& value) {
954   return *value ? *value : "<str conversion failed>";
955 }
956
957 static void ReportException(TryCatch &try_catch, bool show_line = false) {
958   Handle<Message> message = try_catch.Message();
959
960   Handle<Value> error = try_catch.Exception();
961   Handle<String> stack;
962
963   if (error->IsObject()) {
964     Handle<Object> obj = Handle<Object>::Cast(error);
965     Handle<Value> raw_stack = obj->Get(String::New("stack"));
966     if (raw_stack->IsString()) stack = Handle<String>::Cast(raw_stack);
967   }
968
969   if (show_line && !message.IsEmpty()) {
970     // Print (filename):(line number): (message).
971     String::Utf8Value filename(message->GetScriptResourceName());
972     const char* filename_string = ToCString(filename);
973     int linenum = message->GetLineNumber();
974     fprintf(stderr, "%s:%i\n", filename_string, linenum);
975     // Print line of source code.
976     String::Utf8Value sourceline(message->GetSourceLine());
977     const char* sourceline_string = ToCString(sourceline);
978     fprintf(stderr, "%s\n", sourceline_string);
979     // Print wavy underline (GetUnderline is deprecated).
980     int start = message->GetStartColumn();
981     for (int i = 0; i < start; i++) {
982       fprintf(stderr, " ");
983     }
984     int end = message->GetEndColumn();
985     for (int i = start; i < end; i++) {
986       fprintf(stderr, "^");
987     }
988     fprintf(stderr, "\n");
989   }
990
991   if (stack.IsEmpty()) {
992     message->PrintCurrentStackTrace(stderr);
993   } else {
994     String::Utf8Value trace(stack);
995     fprintf(stderr, "%s\n", *trace);
996   }
997   fflush(stderr);
998 }
999
1000 // Executes a str within the current v8 context.
1001 Local<Value> ExecuteString(Local<String> source, Local<Value> filename) {
1002   HandleScope scope;
1003   TryCatch try_catch;
1004
1005   Local<v8::Script> script = v8::Script::Compile(source, filename);
1006   if (script.IsEmpty()) {
1007     ReportException(try_catch);
1008     exit(1);
1009   }
1010
1011   Local<Value> result = script->Run();
1012   if (result.IsEmpty()) {
1013     ReportException(try_catch);
1014     exit(1);
1015   }
1016
1017   return scope.Close(result);
1018 }
1019
1020 static Handle<Value> ByteLength(const Arguments& args) {
1021   HandleScope scope;
1022
1023   if (args.Length() < 1 || !args[0]->IsString()) {
1024     return ThrowException(Exception::Error(String::New("Bad argument.")));
1025   }
1026
1027   Local<Integer> length = Integer::New(DecodeBytes(args[0], ParseEncoding(args[1], UTF8)));
1028
1029   return scope.Close(length);
1030 }
1031
1032 static Handle<Value> Loop(const Arguments& args) {
1033   HandleScope scope;
1034   assert(args.Length() == 0);
1035
1036   // TODO Probably don't need to start this each time.
1037   // Avoids failing on test/mjsunit/test-eio-race3.js though
1038   ev_idle_start(EV_DEFAULT_UC_ &eio_poller);
1039
1040   ev_loop(EV_DEFAULT_UC_ 0);
1041   return Undefined();
1042 }
1043
1044 static Handle<Value> Unloop(const Arguments& args) {
1045   fprintf(stderr, "Deprecation: Don't use process.unloop(). It will be removed soon.\n");
1046   HandleScope scope;
1047   int how = EVUNLOOP_ONE;
1048   if (args[0]->IsString()) {
1049     String::Utf8Value how_s(args[0]->ToString());
1050     if (0 == strcmp(*how_s, "all")) {
1051       how = EVUNLOOP_ALL;
1052     }
1053   }
1054   ev_unloop(EV_DEFAULT_ how);
1055   return Undefined();
1056 }
1057
1058 static Handle<Value> Chdir(const Arguments& args) {
1059   HandleScope scope;
1060
1061   if (args.Length() != 1 || !args[0]->IsString()) {
1062     return ThrowException(Exception::Error(String::New("Bad argument.")));
1063   }
1064
1065   String::Utf8Value path(args[0]->ToString());
1066
1067   int r = chdir(*path);
1068
1069   if (r != 0) {
1070     return ThrowException(Exception::Error(String::New(strerror(errno))));
1071   }
1072
1073   return Undefined();
1074 }
1075
1076 static Handle<Value> Cwd(const Arguments& args) {
1077   HandleScope scope;
1078   assert(args.Length() == 0);
1079
1080   char output[PATH_MAX];
1081   char *r = getcwd(output, PATH_MAX);
1082   if (r == NULL) {
1083     return ThrowException(Exception::Error(String::New(strerror(errno))));
1084   }
1085   Local<String> cwd = String::New(output);
1086
1087   return scope.Close(cwd);
1088 }
1089
1090 static Handle<Value> Umask(const Arguments& args){
1091   HandleScope scope;
1092   unsigned int old;
1093   if(args.Length() < 1) {
1094     old = umask(0);
1095     umask((mode_t)old);
1096   }
1097   else if(!args[0]->IsInt32()) {
1098     return ThrowException(Exception::TypeError(
1099           String::New("argument must be an integer.")));
1100   }
1101   else {
1102     old = umask((mode_t)args[0]->Uint32Value());
1103   }
1104   return scope.Close(Uint32::New(old));
1105 }
1106
1107
1108 static Handle<Value> GetUid(const Arguments& args) {
1109   HandleScope scope;
1110   assert(args.Length() == 0);
1111   int uid = getuid();
1112   return scope.Close(Integer::New(uid));
1113 }
1114
1115 static Handle<Value> GetGid(const Arguments& args) {
1116   HandleScope scope;
1117   assert(args.Length() == 0);
1118   int gid = getgid();
1119   return scope.Close(Integer::New(gid));
1120 }
1121
1122
1123 static Handle<Value> SetGid(const Arguments& args) {
1124   HandleScope scope;
1125
1126   if (args.Length() < 1) {
1127     return ThrowException(Exception::Error(
1128       String::New("setgid requires 1 argument")));
1129   }
1130
1131   Local<Integer> given_gid = args[0]->ToInteger();
1132   int gid = given_gid->Int32Value();
1133   int result;
1134   if ((result = setgid(gid)) != 0) {
1135     return ThrowException(Exception::Error(String::New(strerror(errno))));
1136   }
1137   return Undefined();
1138 }
1139
1140 static Handle<Value> SetUid(const Arguments& args) {
1141   HandleScope scope;
1142
1143   if (args.Length() < 1) {
1144     return ThrowException(Exception::Error(
1145           String::New("setuid requires 1 argument")));
1146   }
1147
1148   Local<Integer> given_uid = args[0]->ToInteger();
1149   int uid = given_uid->Int32Value();
1150   int result;
1151   if ((result = setuid(uid)) != 0) {
1152     return ThrowException(Exception::Error(String::New(strerror(errno))));
1153   }
1154   return Undefined();
1155 }
1156
1157
1158 v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
1159   HandleScope scope;
1160   fflush(stderr);
1161   Stdio::Flush();
1162   exit(args[0]->IntegerValue());
1163   return Undefined();
1164 }
1165
1166 #ifdef __sun
1167 #define HAVE_GETMEM 1
1168 #include <unistd.h> /* getpagesize() */
1169
1170 #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
1171 #define PROCFS_FILE_OFFSET_BITS_HACK 1
1172 #undef _FILE_OFFSET_BITS
1173 #else
1174 #define PROCFS_FILE_OFFSET_BITS_HACK 0
1175 #endif
1176
1177 #include <procfs.h>
1178
1179 #if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
1180 #define _FILE_OFFSET_BITS 64
1181 #endif
1182
1183 int getmem(size_t *rss, size_t *vsize) {
1184   pid_t pid = getpid();
1185
1186   size_t page_size = getpagesize();
1187   char pidpath[1024];
1188   sprintf(pidpath, "/proc/%d/psinfo", pid);
1189
1190   psinfo_t psinfo;
1191   FILE *f = fopen(pidpath, "r");
1192   if (!f) return -1;
1193
1194   if (fread(&psinfo, sizeof(psinfo_t), 1, f) != 1) {
1195     fclose (f);
1196     return -1;
1197   }
1198
1199   /* XXX correct? */
1200
1201   *vsize = (size_t) psinfo.pr_size * page_size;
1202   *rss = (size_t) psinfo.pr_rssize * 1024;
1203
1204   fclose (f);
1205
1206   return 0;
1207 }
1208 #endif
1209
1210
1211 #ifdef __FreeBSD__
1212 #define HAVE_GETMEM 1
1213 #include <kvm.h>
1214 #include <sys/param.h>
1215 #include <sys/sysctl.h>
1216 #include <sys/user.h>
1217 #include <paths.h>
1218 #include <fcntl.h>
1219 #include <unistd.h>
1220
1221 int getmem(size_t *rss, size_t *vsize) {
1222   kvm_t *kd = NULL;
1223   struct kinfo_proc *kinfo = NULL;
1224   pid_t pid;
1225   int nprocs;
1226   size_t page_size = getpagesize();
1227
1228   pid = getpid();
1229
1230   kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
1231   if (kd == NULL) goto error;
1232
1233   kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
1234   if (kinfo == NULL) goto error;
1235
1236   *rss = kinfo->ki_rssize * page_size;
1237   *vsize = kinfo->ki_size;
1238
1239   kvm_close(kd);
1240
1241   return 0;
1242
1243 error:
1244   if (kd) kvm_close(kd);
1245   return -1;
1246 }
1247 #endif  // __FreeBSD__
1248
1249
1250 #ifdef __APPLE__
1251 #define HAVE_GETMEM 1
1252 /* Researched by Tim Becker and Michael Knight
1253  * http://blog.kuriositaet.de/?p=257
1254  */
1255
1256 #include <mach/task.h>
1257 #include <mach/mach_init.h>
1258
1259 int getmem(size_t *rss, size_t *vsize) {
1260   struct task_basic_info t_info;
1261   mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
1262
1263   int r = task_info(mach_task_self(),
1264                     TASK_BASIC_INFO,
1265                     (task_info_t)&t_info,
1266                     &t_info_count);
1267
1268   if (r != KERN_SUCCESS) return -1;
1269
1270   *rss = t_info.resident_size;
1271   *vsize  = t_info.virtual_size;
1272
1273   return 0;
1274 }
1275 #endif  // __APPLE__
1276
1277 #ifdef __linux__
1278 # define HAVE_GETMEM 1
1279 # include <sys/param.h> /* for MAXPATHLEN */
1280
1281 int getmem(size_t *rss, size_t *vsize) {
1282   FILE *f = fopen("/proc/self/stat", "r");
1283   if (!f) return -1;
1284
1285   int itmp;
1286   char ctmp;
1287   char buffer[MAXPATHLEN];
1288   size_t page_size = getpagesize();
1289
1290   /* PID */
1291   if (fscanf(f, "%d ", &itmp) == 0) goto error;
1292   /* Exec file */
1293   if (fscanf (f, "%s ", &buffer[0]) == 0) goto error;
1294   /* State */
1295   if (fscanf (f, "%c ", &ctmp) == 0) goto error;
1296   /* Parent process */
1297   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1298   /* Process group */
1299   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1300   /* Session id */
1301   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1302   /* TTY */
1303   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1304   /* TTY owner process group */
1305   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1306   /* Flags */
1307   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1308   /* Minor faults (no memory page) */
1309   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1310   /* Minor faults, children */
1311   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1312   /* Major faults (memory page faults) */
1313   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1314   /* Major faults, children */
1315   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1316   /* utime */
1317   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1318   /* stime */
1319   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1320   /* utime, children */
1321   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1322   /* stime, children */
1323   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1324   /* jiffies remaining in current time slice */
1325   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1326   /* 'nice' value */
1327   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1328   /* jiffies until next timeout */
1329   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1330   /* jiffies until next SIGALRM */
1331   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1332   /* start time (jiffies since system boot) */
1333   if (fscanf (f, "%d ", &itmp) == 0) goto error;
1334
1335   /* Virtual memory size */
1336   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1337   *vsize = (size_t) itmp;
1338
1339   /* Resident set size */
1340   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1341   *rss = (size_t) itmp * page_size;
1342
1343   /* rlim */
1344   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1345   /* Start of text */
1346   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1347   /* End of text */
1348   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1349   /* Start of stack */
1350   if (fscanf (f, "%u ", &itmp) == 0) goto error;
1351
1352   fclose (f);
1353
1354   return 0;
1355
1356 error:
1357   fclose (f);
1358   return -1;
1359 }
1360 #endif  // __linux__
1361
1362
1363 static void CheckStatus(EV_P_ ev_timer *watcher, int revents) {
1364   assert(watcher == &gc_timer);
1365   assert(revents == EV_TIMER);
1366
1367 #if HAVE_GETMEM
1368   // check memory
1369   size_t rss, vsize;
1370   if (!ev_is_active(&gc_idle) && getmem(&rss, &vsize) == 0) {
1371     if (rss > 1024*1024*128) {
1372       // larger than 128 megs, just start the idle watcher
1373       ev_idle_start(EV_A_ &gc_idle);
1374       return;
1375     }
1376   }
1377 #endif // HAVE_GETMEM
1378
1379   double d = ev_now() - TICK_TIME(3);
1380
1381   //printfb("timer d = %f\n", d);
1382
1383   if (d  >= GC_WAIT_TIME - 1.) {
1384     //fprintf(stderr, "start idle\n");
1385     ev_idle_start(EV_A_ &gc_idle);
1386   }
1387 }
1388
1389
1390 v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
1391   HandleScope scope;
1392   assert(args.Length() == 0);
1393
1394 #ifndef HAVE_GETMEM
1395   return ThrowException(Exception::Error(String::New("Not support on your platform. (Talk to Ryan.)")));
1396 #else
1397   size_t rss, vsize;
1398
1399   int r = getmem(&rss, &vsize);
1400
1401   if (r != 0) {
1402     return ThrowException(Exception::Error(String::New(strerror(errno))));
1403   }
1404
1405   Local<Object> info = Object::New();
1406
1407   if (rss_symbol.IsEmpty()) {
1408     rss_symbol = NODE_PSYMBOL("rss");
1409     vsize_symbol = NODE_PSYMBOL("vsize");
1410     heap_total_symbol = NODE_PSYMBOL("heapTotal");
1411     heap_used_symbol = NODE_PSYMBOL("heapUsed");
1412   }
1413
1414   info->Set(rss_symbol, Integer::NewFromUnsigned(rss));
1415   info->Set(vsize_symbol, Integer::NewFromUnsigned(vsize));
1416
1417   // V8 memory usage
1418   HeapStatistics v8_heap_stats;
1419   V8::GetHeapStatistics(&v8_heap_stats);
1420   info->Set(heap_total_symbol,
1421             Integer::NewFromUnsigned(v8_heap_stats.total_heap_size()));
1422   info->Set(heap_used_symbol,
1423             Integer::NewFromUnsigned(v8_heap_stats.used_heap_size()));
1424
1425   return scope.Close(info);
1426 #endif
1427 }
1428
1429
1430 v8::Handle<v8::Value> Kill(const v8::Arguments& args) {
1431   HandleScope scope;
1432
1433   if (args.Length() < 1 || !args[0]->IsNumber()) {
1434     return ThrowException(Exception::Error(String::New("Bad argument.")));
1435   }
1436
1437   pid_t pid = args[0]->IntegerValue();
1438
1439   int sig = SIGTERM;
1440
1441   if (args.Length() >= 2) {
1442     if (args[1]->IsNumber()) {
1443       sig = args[1]->Int32Value();
1444     } else if (args[1]->IsString()) {
1445       Local<String> signame = args[1]->ToString();
1446
1447       Local<Value> sig_v = process->Get(signame);
1448       if (!sig_v->IsNumber()) {
1449         return ThrowException(Exception::Error(String::New("Unknown signal")));
1450       }
1451       sig = sig_v->Int32Value();
1452     }
1453   }
1454
1455   int r = kill(pid, sig);
1456
1457   if (r != 0) {
1458     return ThrowException(Exception::Error(String::New(strerror(errno))));
1459   }
1460
1461   return Undefined();
1462 }
1463
1464 typedef void (*extInit)(Handle<Object> exports);
1465
1466 // DLOpen is node.dlopen(). Used to load 'module.node' dynamically shared
1467 // objects.
1468 Handle<Value> DLOpen(const v8::Arguments& args) {
1469   HandleScope scope;
1470
1471   if (args.Length() < 2) return Undefined();
1472
1473   String::Utf8Value filename(args[0]->ToString()); // Cast
1474   Local<Object> target = args[1]->ToObject(); // Cast
1475
1476   // Actually call dlopen().
1477   // FIXME: This is a blocking function and should be called asynchronously!
1478   // This function should be moved to file.cc and use libeio to make this
1479   // system call.
1480   void *handle = dlopen(*filename, RTLD_LAZY);
1481
1482   // Handle errors.
1483   if (handle == NULL) {
1484     Local<Value> exception = Exception::Error(String::New(dlerror()));
1485     return ThrowException(exception);
1486   }
1487
1488   // Get the init() function from the dynamically shared object.
1489   void *init_handle = dlsym(handle, "init");
1490   // Error out if not found.
1491   if (init_handle == NULL) {
1492     Local<Value> exception =
1493       Exception::Error(String::New("No 'init' symbol found in module."));
1494     return ThrowException(exception);
1495   }
1496   extInit init = (extInit)(init_handle); // Cast
1497
1498   // Execute the C++ module
1499   init(target);
1500
1501   return Undefined();
1502 }
1503
1504
1505 Handle<Value> Compile(const Arguments& args) {
1506   HandleScope scope;
1507
1508   if (args.Length() < 2) {
1509     return ThrowException(Exception::TypeError(
1510           String::New("needs two arguments.")));
1511   }
1512
1513   Local<String> source = args[0]->ToString();
1514   Local<String> filename = args[1]->ToString();
1515
1516   TryCatch try_catch;
1517
1518   Local<v8::Script> script = v8::Script::Compile(source, filename);
1519   if (try_catch.HasCaught()) {
1520     // Hack because I can't get a proper stacktrace on SyntaxError
1521     ReportException(try_catch, true);
1522     exit(1);
1523   }
1524
1525   Local<Value> result = script->Run();
1526   if (try_catch.HasCaught()) return try_catch.ReThrow();
1527
1528   return scope.Close(result);
1529 }
1530
1531 static void OnFatalError(const char* location, const char* message) {
1532   if (location) {
1533     fprintf(stderr, "FATAL ERROR: %s %s\n", location, message);
1534   } else {
1535     fprintf(stderr, "FATAL ERROR: %s\n", message);
1536   }
1537   exit(1);
1538 }
1539
1540 static int uncaught_exception_counter = 0;
1541
1542 void FatalException(TryCatch &try_catch) {
1543   HandleScope scope;
1544
1545   // Check if uncaught_exception_counter indicates a recursion
1546   if (uncaught_exception_counter > 0) {
1547     ReportException(try_catch);
1548     exit(1);
1549   }
1550
1551   if (listeners_symbol.IsEmpty()) {
1552     listeners_symbol = NODE_PSYMBOL("listeners");
1553     uncaught_exception_symbol = NODE_PSYMBOL("uncaughtException");
1554     emit_symbol = NODE_PSYMBOL("emit");
1555   }
1556
1557   Local<Value> listeners_v = process->Get(listeners_symbol);
1558   assert(listeners_v->IsFunction());
1559
1560   Local<Function> listeners = Local<Function>::Cast(listeners_v);
1561
1562   Local<String> uncaught_exception_symbol_l = Local<String>::New(uncaught_exception_symbol);
1563   Local<Value> argv[1] = { uncaught_exception_symbol_l  };
1564   Local<Value> ret = listeners->Call(process, 1, argv);
1565
1566   assert(ret->IsArray());
1567
1568   Local<Array> listener_array = Local<Array>::Cast(ret);
1569
1570   uint32_t length = listener_array->Length();
1571   // Report and exit if process has no "uncaughtException" listener
1572   if (length == 0) {
1573     ReportException(try_catch);
1574     exit(1);
1575   }
1576
1577   // Otherwise fire the process "uncaughtException" event
1578   Local<Value> emit_v = process->Get(emit_symbol);
1579   assert(emit_v->IsFunction());
1580
1581   Local<Function> emit = Local<Function>::Cast(emit_v);
1582
1583   Local<Value> error = try_catch.Exception();
1584   Local<Value> event_argv[2] = { uncaught_exception_symbol_l, error };
1585
1586   uncaught_exception_counter++;
1587   emit->Call(process, 2, event_argv);
1588   // Decrement so we know if the next exception is a recursion or not
1589   uncaught_exception_counter--;
1590 }
1591
1592
1593 static ev_async debug_watcher;
1594 volatile static bool debugger_msg_pending = false;
1595
1596 static void DebugMessageCallback(EV_P_ ev_async *watcher, int revents) {
1597   HandleScope scope;
1598   assert(watcher == &debug_watcher);
1599   assert(revents == EV_ASYNC);
1600   Debug::ProcessDebugMessages();
1601 }
1602
1603 static void DebugMessageDispatch(void) {
1604   // This function is called from V8's debug thread when a debug TCP client
1605   // has sent a message.
1606
1607   // Send a signal to our main thread saying that it should enter V8 to
1608   // handle the message.
1609   debugger_msg_pending = true;
1610   ev_async_send(EV_DEFAULT_UC_ &debug_watcher);
1611 }
1612
1613 static Handle<Value> CheckBreak(const Arguments& args) {
1614   HandleScope scope;
1615   assert(args.Length() == 0);
1616
1617   // TODO FIXME This function is a hack to wait until V8 is ready to accept
1618   // commands. There seems to be a bug in EnableAgent( _ , _ , true) which
1619   // makes it unusable here. Ideally we'd be able to bind EnableAgent and
1620   // get it to halt until Eclipse connects.
1621
1622   if (!debug_wait_connect)
1623     return Undefined();
1624
1625   printf("Waiting for remote debugger connection...\n");
1626
1627   const int halfSecond = 50;
1628   const int tenMs=10000;
1629   debugger_msg_pending = false;
1630   for (;;) {
1631     if (debugger_msg_pending) {
1632       Debug::DebugBreak();
1633       Debug::ProcessDebugMessages();
1634       debugger_msg_pending = false;
1635
1636       // wait for 500 msec of silence from remote debugger
1637       int cnt = halfSecond;
1638         while (cnt --) {
1639         debugger_msg_pending = false;
1640         usleep(tenMs);
1641         if (debugger_msg_pending) {
1642           debugger_msg_pending = false;
1643           cnt = halfSecond;
1644         }
1645       }
1646       break;
1647     }
1648     usleep(tenMs);
1649   }
1650   return Undefined();
1651 }
1652
1653 Persistent<Object> binding_cache;
1654
1655 static Handle<Value> Binding(const Arguments& args) {
1656   HandleScope scope;
1657
1658   Local<String> module = args[0]->ToString();
1659   String::Utf8Value module_v(module);
1660
1661   if (binding_cache.IsEmpty()) {
1662     binding_cache = Persistent<Object>::New(Object::New());
1663   }
1664
1665   Local<Object> exports;
1666
1667   // TODO DRY THIS UP!
1668
1669   if (!strcmp(*module_v, "stdio")) {
1670     if (binding_cache->Has(module)) {
1671       exports = binding_cache->Get(module)->ToObject();
1672     } else {
1673       exports = Object::New();
1674       Stdio::Initialize(exports);
1675       binding_cache->Set(module, exports);
1676     }
1677
1678   } else if (!strcmp(*module_v, "cares")) {
1679     if (binding_cache->Has(module)) {
1680       exports = binding_cache->Get(module)->ToObject();
1681     } else {
1682       exports = Object::New();
1683       Cares::Initialize(exports);
1684       binding_cache->Set(module, exports);
1685     }
1686
1687   } else if (!strcmp(*module_v, "fs")) {
1688     if (binding_cache->Has(module)) {
1689       exports = binding_cache->Get(module)->ToObject();
1690     } else {
1691       exports = Object::New();
1692
1693       // Initialize the stats object
1694       Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
1695       stats_constructor_template = Persistent<FunctionTemplate>::New(stat_templ);
1696       exports->Set(String::NewSymbol("Stats"),
1697                    stats_constructor_template->GetFunction());
1698       StatWatcher::Initialize(exports);
1699       File::Initialize(exports);
1700       binding_cache->Set(module, exports);
1701     }
1702
1703   } else if (!strcmp(*module_v, "signal_watcher")) {
1704     if (binding_cache->Has(module)) {
1705       exports = binding_cache->Get(module)->ToObject();
1706     } else {
1707       exports = Object::New();
1708       SignalWatcher::Initialize(exports);
1709       binding_cache->Set(module, exports);
1710     }
1711
1712   } else if (!strcmp(*module_v, "net")) {
1713     if (binding_cache->Has(module)) {
1714       exports = binding_cache->Get(module)->ToObject();
1715     } else {
1716       exports = Object::New();
1717       InitNet2(exports);
1718       binding_cache->Set(module, exports);
1719     }
1720
1721   } else if (!strcmp(*module_v, "http_parser")) {
1722     if (binding_cache->Has(module)) {
1723       exports = binding_cache->Get(module)->ToObject();
1724     } else {
1725       exports = Object::New();
1726       InitHttpParser(exports);
1727       binding_cache->Set(module, exports);
1728     }
1729
1730   } else if (!strcmp(*module_v, "child_process")) {
1731     if (binding_cache->Has(module)) {
1732       exports = binding_cache->Get(module)->ToObject();
1733     } else {
1734       exports = Object::New();
1735       ChildProcess::Initialize(exports);
1736       binding_cache->Set(module, exports);
1737     }
1738
1739   } else if (!strcmp(*module_v, "buffer")) {
1740     if (binding_cache->Has(module)) {
1741       exports = binding_cache->Get(module)->ToObject();
1742     } else {
1743       exports = Object::New();
1744       Buffer::Initialize(exports);
1745       binding_cache->Set(module, exports);
1746     }
1747   #ifdef HAVE_OPENSSL
1748   } else if (!strcmp(*module_v, "crypto")) {
1749     if (binding_cache->Has(module)) {
1750       exports = binding_cache->Get(module)->ToObject();
1751     } else {
1752       exports = Object::New();
1753       InitCrypto(exports);
1754       binding_cache->Set(module, exports);
1755     }
1756   #endif
1757   } else if (!strcmp(*module_v, "evals")) {
1758     if (binding_cache->Has(module)) {
1759       exports = binding_cache->Get(module)->ToObject();
1760     } else {
1761       exports = Object::New();
1762       node::Script::Initialize(exports);
1763       binding_cache->Set(module, exports);
1764     }
1765
1766   } else if (!strcmp(*module_v, "natives")) {
1767     if (binding_cache->Has(module)) {
1768       exports = binding_cache->Get(module)->ToObject();
1769     } else {
1770       exports = Object::New();
1771       // Explicitly define native sources.
1772       // TODO DRY/automate this?
1773       exports->Set(String::New("assert"),       String::New(native_assert));
1774       exports->Set(String::New("buffer"),       String::New(native_buffer));
1775       exports->Set(String::New("child_process"),String::New(native_child_process));
1776       exports->Set(String::New("dns"),          String::New(native_dns));
1777       exports->Set(String::New("events"),       String::New(native_events));
1778       exports->Set(String::New("file"),         String::New(native_file));
1779       exports->Set(String::New("freelist"),     String::New(native_freelist));
1780       exports->Set(String::New("fs"),           String::New(native_fs));
1781       exports->Set(String::New("http"),         String::New(native_http));
1782       exports->Set(String::New("crypto"),       String::New(native_crypto));
1783       exports->Set(String::New("ini"),          String::New(native_ini));
1784       exports->Set(String::New("mjsunit"),      String::New(native_mjsunit));
1785       exports->Set(String::New("net"),          String::New(native_net));
1786       exports->Set(String::New("posix"),        String::New(native_posix));
1787       exports->Set(String::New("querystring"),  String::New(native_querystring));
1788       exports->Set(String::New("repl"),         String::New(native_repl));
1789       exports->Set(String::New("sys"),          String::New(native_sys));
1790       exports->Set(String::New("tcp"),          String::New(native_tcp));
1791       exports->Set(String::New("uri"),          String::New(native_uri));
1792       exports->Set(String::New("url"),          String::New(native_url));
1793       exports->Set(String::New("utils"),        String::New(native_utils));
1794       exports->Set(String::New("path"),         String::New(native_path));
1795       exports->Set(String::New("module"),       String::New(native_module));
1796       binding_cache->Set(module, exports);
1797     }
1798
1799   } else {
1800     return ThrowException(Exception::Error(String::New("No such module")));
1801   }
1802
1803   return scope.Close(exports);
1804 }
1805
1806
1807 static void Load(int argc, char *argv[]) {
1808   HandleScope scope;
1809
1810   Local<FunctionTemplate> process_template = FunctionTemplate::New();
1811   node::EventEmitter::Initialize(process_template);
1812
1813   process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
1814
1815   // Add a reference to the global object
1816   Local<Object> global = Context::GetCurrent()->Global();
1817   process->Set(String::NewSymbol("global"), global);
1818
1819   // process.version
1820   process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
1821   // process.installPrefix
1822   process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
1823
1824   // process.platform
1825 #define xstr(s) str(s)
1826 #define str(s) #s
1827   process->Set(String::NewSymbol("platform"), String::New(xstr(PLATFORM)));
1828
1829   // process.argv
1830   int i, j;
1831   Local<Array> arguments = Array::New(argc - option_end_index + 1);
1832   arguments->Set(Integer::New(0), String::New(argv[0]));
1833   for (j = 1, i = option_end_index + 1; i < argc; j++, i++) {
1834     Local<String> arg = String::New(argv[i]);
1835     arguments->Set(Integer::New(j), arg);
1836   }
1837   // assign it
1838   process->Set(String::NewSymbol("ARGV"), arguments);
1839   process->Set(String::NewSymbol("argv"), arguments);
1840
1841   // create process.env
1842   Local<Object> env = Object::New();
1843   for (i = 0; environ[i]; i++) {
1844     // skip entries without a '=' character
1845     for (j = 0; environ[i][j] && environ[i][j] != '='; j++) { ; }
1846     // create the v8 objects
1847     Local<String> field = String::New(environ[i], j);
1848     Local<String> value = Local<String>();
1849     if (environ[i][j] == '=') {
1850       value = String::New(environ[i]+j+1);
1851     }
1852     // assign them
1853     env->Set(field, value);
1854   }
1855   // assign process.ENV
1856   process->Set(String::NewSymbol("ENV"), env);
1857   process->Set(String::NewSymbol("env"), env);
1858
1859   process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
1860
1861   // define various internal methods
1862   NODE_SET_METHOD(process, "loop", Loop);
1863   NODE_SET_METHOD(process, "unloop", Unloop);
1864   NODE_SET_METHOD(process, "compile", Compile);
1865   NODE_SET_METHOD(process, "_byteLength", ByteLength);
1866   NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
1867   NODE_SET_METHOD(process, "reallyExit", Exit);
1868   NODE_SET_METHOD(process, "chdir", Chdir);
1869   NODE_SET_METHOD(process, "cwd", Cwd);
1870   NODE_SET_METHOD(process, "getuid", GetUid);
1871   NODE_SET_METHOD(process, "setuid", SetUid);
1872
1873   NODE_SET_METHOD(process, "setgid", SetGid);
1874   NODE_SET_METHOD(process, "getgid", GetGid);
1875
1876   NODE_SET_METHOD(process, "umask", Umask);
1877   NODE_SET_METHOD(process, "dlopen", DLOpen);
1878   NODE_SET_METHOD(process, "kill", Kill);
1879   NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
1880   NODE_SET_METHOD(process, "checkBreak", CheckBreak);
1881
1882   NODE_SET_METHOD(process, "binding", Binding);
1883
1884   // Assign the EventEmitter. It was created in main().
1885   process->Set(String::NewSymbol("EventEmitter"),
1886                EventEmitter::constructor_template->GetFunction());
1887
1888
1889   // Initialize the C++ modules..................filename of module
1890   IOWatcher::Initialize(process);              // io_watcher.cc
1891   // Not in use at the moment.
1892   //IdleWatcher::Initialize(process);            // idle_watcher.cc
1893   Timer::Initialize(process);                  // timer.cc
1894   DefineConstants(process);                    // constants.cc
1895
1896   // Compile, execute the src/node.js file. (Which was included as static C
1897   // string in node_natives.h. 'natve_node' is the string containing that
1898   // source code.)
1899
1900   // The node.js file returns a function 'f'
1901
1902 #ifndef NDEBUG
1903   TryCatch try_catch;
1904 #endif
1905
1906   Local<Value> f_value = ExecuteString(String::New(native_node),
1907                                        String::New("node.js"));
1908 #ifndef NDEBUG
1909   if (try_catch.HasCaught())  {
1910     ReportException(try_catch);
1911     exit(10);
1912   }
1913 #endif
1914   assert(f_value->IsFunction());
1915   Local<Function> f = Local<Function>::Cast(f_value);
1916
1917   // Now we call 'f' with the 'process' variable that we've built up with
1918   // all our bindings. Inside node.js we'll take care of assigning things to
1919   // their places.
1920
1921   // We start the process this way in order to be more modular. Developers
1922   // who do not like how 'src/node.js' setups the module system but do like
1923   // Node's I/O bindings may want to replace 'f' with their own function.
1924
1925   Local<Value> args[1] = { Local<Value>::New(process) };
1926
1927   f->Call(global, 1, args);
1928
1929 #ifndef NDEBUG
1930   if (try_catch.HasCaught())  {
1931     ReportException(try_catch);
1932     exit(11);
1933   }
1934 #endif
1935 }
1936
1937 static void PrintHelp();
1938
1939 static void ParseDebugOpt(const char* arg) {
1940   const char *p = 0;
1941
1942   use_debug_agent = true;
1943   if (!strcmp (arg, "--debug-brk")) {
1944     debug_wait_connect = true;
1945     return;
1946   } else if (!strcmp(arg, "--debug")) {
1947     return;
1948   } else if (strstr(arg, "--debug-brk=") == arg) {
1949     debug_wait_connect = true;
1950     p = 1 + strchr(arg, '=');
1951     debug_port = atoi(p);
1952   } else if (strstr(arg, "--debug=") == arg) {
1953     p = 1 + strchr(arg, '=');
1954     debug_port = atoi(p);
1955   }
1956   if (p && debug_port > 1024 && debug_port <  65536)
1957       return;
1958
1959   fprintf(stderr, "Bad debug option.\n");
1960   if (p) fprintf(stderr, "Debug port must be in range 1025 to 65535.\n");
1961
1962   PrintHelp();
1963   exit(1);
1964 }
1965
1966 static void PrintHelp() {
1967   printf("Usage: node [options] script.js [arguments] \n"
1968          "Options:\n"
1969          "  -v, --version      print node's version\n"
1970          "  --debug[=port]     enable remote debugging via given TCP port\n"
1971          "                     without stopping the execution\n"
1972          "  --debug-brk[=port] as above, but break in script.js and\n"
1973          "                     wait for remote debugger to connect\n"
1974          "  --v8-options       print v8 command line options\n"
1975          "  --vars             print various compiled-in variables\n"
1976          "\n"
1977          "Enviromental variables:\n"
1978          "NODE_PATH            ':'-separated list of directories\n"
1979          "                     prefixed to the module search path,\n"
1980          "                     require.paths.\n"
1981          "NODE_DEBUG           Print additional debugging output.\n"
1982          "\n"
1983          "Documentation can be found at http://nodejs.org/api.html"
1984          " or with 'man node'\n");
1985 }
1986
1987 // Parse node command line arguments.
1988 static void ParseArgs(int *argc, char **argv) {
1989   // TODO use parse opts
1990   for (int i = 1; i < *argc; i++) {
1991     const char *arg = argv[i];
1992     if (strstr(arg, "--debug") == arg) {
1993       ParseDebugOpt(arg);
1994       argv[i] = const_cast<char*>("");
1995       option_end_index = i;
1996     } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
1997       printf("%s\n", NODE_VERSION);
1998       exit(0);
1999     } else if (strcmp(arg, "--vars") == 0) {
2000       printf("NODE_PREFIX: %s\n", NODE_PREFIX);
2001       printf("NODE_CFLAGS: %s\n", NODE_CFLAGS);
2002       exit(0);
2003     } else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
2004       PrintHelp();
2005       exit(0);
2006     } else if (strcmp(arg, "--v8-options") == 0) {
2007       argv[i] = const_cast<char*>("--help");
2008       option_end_index = i+1;
2009     } else if (argv[i][0] != '-') {
2010       option_end_index = i-1;
2011       break;
2012     }
2013   }
2014 }
2015
2016 }  // namespace node
2017
2018
2019 int main(int argc, char *argv[]) {
2020   // Parse a few arguments which are specific to Node.
2021   node::ParseArgs(&argc, argv);
2022   // Parse the rest of the args (up to the 'option_end_index' (where '--' was
2023   // in the command line))
2024   V8::SetFlagsFromCommandLine(&node::option_end_index, argv, false);
2025
2026   // Error out if we don't have a script argument.
2027   if (argc < 2) {
2028     fprintf(stderr, "No script was specified.\n");
2029     node::PrintHelp();
2030     return 1;
2031   }
2032
2033
2034   // Ignore SIGPIPE
2035   struct sigaction sa;
2036   bzero(&sa, sizeof(sa));
2037   sa.sa_handler = SIG_IGN;
2038   sigaction(SIGPIPE, &sa, NULL);
2039
2040
2041   // Initialize the default ev loop.
2042 #ifdef __sun
2043   // TODO(Ryan) I'm experiencing abnormally high load using Solaris's
2044   // EVBACKEND_PORT. Temporarally forcing select() until I debug.
2045   ev_default_loop(EVBACKEND_SELECT);
2046 #else
2047   ev_default_loop(EVFLAG_AUTO);
2048 #endif
2049
2050   ev_prepare_init(&node::next_tick_watcher, node::Tick);
2051   ev_prepare_start(EV_DEFAULT_UC_ &node::next_tick_watcher);
2052   ev_unref(EV_DEFAULT_UC);
2053
2054   ev_idle_init(&node::tick_spinner, node::Spin);
2055
2056   ev_check_init(&node::gc_check, node::Check);
2057   ev_check_start(EV_DEFAULT_UC_ &node::gc_check);
2058   ev_unref(EV_DEFAULT_UC);
2059
2060   ev_idle_init(&node::gc_idle, node::Idle);
2061   ev_timer_init(&node::gc_timer, node::CheckStatus, 5., 5.);
2062
2063
2064   // Setup the EIO thread pool
2065   { // It requires 3, yes 3, watchers.
2066     ev_idle_init(&node::eio_poller, node::DoPoll);
2067
2068     ev_async_init(&node::eio_want_poll_notifier, node::WantPollNotifier);
2069     ev_async_start(EV_DEFAULT_UC_ &node::eio_want_poll_notifier);
2070     ev_unref(EV_DEFAULT_UC);
2071
2072     ev_async_init(&node::eio_done_poll_notifier, node::DonePollNotifier);
2073     ev_async_start(EV_DEFAULT_UC_ &node::eio_done_poll_notifier);
2074     ev_unref(EV_DEFAULT_UC);
2075
2076     eio_init(node::EIOWantPoll, node::EIODonePoll);
2077     // Don't handle more than 10 reqs on each eio_poll(). This is to avoid
2078     // race conditions. See test/mjsunit/test-eio-race.js
2079     eio_set_max_poll_reqs(10);
2080   }
2081
2082   V8::Initialize();
2083   HandleScope handle_scope;
2084
2085   V8::SetFatalErrorHandler(node::OnFatalError);
2086
2087   // If the --debug flag was specified then initialize the debug thread.
2088   if (node::use_debug_agent) {
2089     // Initialize the async watcher for receiving messages from the debug
2090     // thread and marshal it into the main thread. DebugMessageCallback()
2091     // is called from the main thread to execute a random bit of javascript
2092     // - which will give V8 control so it can handle whatever new message
2093     // had been received on the debug thread.
2094     ev_async_init(&node::debug_watcher, node::DebugMessageCallback);
2095     ev_set_priority(&node::debug_watcher, EV_MAXPRI);
2096     // Set the callback DebugMessageDispatch which is called from the debug
2097     // thread.
2098     Debug::SetDebugMessageDispatchHandler(node::DebugMessageDispatch);
2099     // Start the async watcher.
2100     ev_async_start(EV_DEFAULT_UC_ &node::debug_watcher);
2101     // unref it so that we exit the event loop despite it being active.
2102     ev_unref(EV_DEFAULT_UC);
2103
2104     // Start the debug thread and it's associated TCP server on port 5858.
2105     bool r = Debug::EnableAgent("node " NODE_VERSION, node::debug_port);
2106
2107     // Crappy check that everything went well. FIXME
2108     assert(r);
2109     // Print out some information.
2110     printf("debugger listening on port %d\n", node::debug_port);
2111   }
2112
2113   // Create the one and only Context.
2114   Persistent<Context> context = Context::New();
2115   Context::Scope context_scope(context);
2116
2117   // Create all the objects, load modules, do everything.
2118   // so your next reading stop should be node::Load()!
2119   node::Load(argc, argv);
2120
2121   node::Stdio::Flush();
2122
2123 #ifndef NDEBUG
2124   // Clean up.
2125   context.Dispose();
2126   V8::Dispose();
2127 #endif  // NDEBUG
2128   return 0;
2129 }
2130