The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / src / node.cc @ 35a1421e
History | View | Annotate | Download (72 KB)
1 |
// Copyright Joyent, Inc. and other Node contributors.
|
---|---|
2 |
//
|
3 |
// Permission is hereby granted, free of charge, to any person obtaining a
|
4 |
// copy of this software and associated documentation files (the
|
5 |
// "Software"), to deal in the Software without restriction, including
|
6 |
// without limitation the rights to use, copy, modify, merge, publish,
|
7 |
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
8 |
// persons to whom the Software is furnished to do so, subject to the
|
9 |
// following conditions:
|
10 |
//
|
11 |
// The above copyright notice and this permission notice shall be included
|
12 |
// in all copies or substantial portions of the Software.
|
13 |
//
|
14 |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
15 |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16 |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
17 |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
18 |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
19 |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
20 |
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21 |
|
22 |
#include "node.h" |
23 |
#include "req_wrap.h" |
24 |
#include "handle_wrap.h" |
25 |
|
26 |
#include "uv.h" |
27 |
|
28 |
#include "v8-debug.h" |
29 |
#if defined HAVE_DTRACE || defined HAVE_ETW
|
30 |
# include "node_dtrace.h" |
31 |
#endif
|
32 |
|
33 |
#ifdef HAVE_ETW
|
34 |
# include "node_win32_etw_provider.h" |
35 |
#endif
|
36 |
|
37 |
#include <locale.h> |
38 |
#include <signal.h> |
39 |
#include <stdio.h> |
40 |
#include <stdlib.h> |
41 |
#include <string.h> |
42 |
#if !defined(_MSC_VER)
|
43 |
#include <strings.h> |
44 |
#else
|
45 |
#define strcasecmp _stricmp
|
46 |
#endif
|
47 |
#include <limits.h> /* PATH_MAX */ |
48 |
#include <assert.h> |
49 |
#if !defined(_MSC_VER)
|
50 |
#include <unistd.h> /* setuid, getuid */ |
51 |
#else
|
52 |
#include <direct.h> |
53 |
#include <process.h> |
54 |
#define getpid _getpid
|
55 |
#include <io.h> |
56 |
#define umask _umask
|
57 |
typedef int mode_t; |
58 |
#endif
|
59 |
#include <errno.h> |
60 |
#include <sys/types.h> |
61 |
#include "zlib.h" |
62 |
|
63 |
#ifdef __POSIX__
|
64 |
# include <pwd.h> /* getpwnam() */ |
65 |
# include <grp.h> /* getgrnam() */ |
66 |
#endif
|
67 |
|
68 |
#include "node_buffer.h" |
69 |
#ifdef __POSIX__
|
70 |
# include "node_io_watcher.h" |
71 |
#endif
|
72 |
#include "node_file.h" |
73 |
#include "node_http_parser.h" |
74 |
#ifdef __POSIX__
|
75 |
# include "node_signal_watcher.h" |
76 |
# include "node_stat_watcher.h" |
77 |
#endif
|
78 |
#include "node_constants.h" |
79 |
#include "node_javascript.h" |
80 |
#include "node_version.h" |
81 |
#include "node_string.h" |
82 |
#if HAVE_OPENSSL
|
83 |
# include "node_crypto.h" |
84 |
#endif
|
85 |
#include "node_script.h" |
86 |
#include "v8_typed_array.h" |
87 |
|
88 |
using namespace v8; |
89 |
|
90 |
# ifdef __APPLE__
|
91 |
# include <crt_externs.h> |
92 |
# define environ (*_NSGetEnviron())
|
93 |
# elif !defined(_MSC_VER)
|
94 |
extern char **environ; |
95 |
# endif
|
96 |
|
97 |
namespace node {
|
98 |
|
99 |
ngx_queue_t handle_wrap_queue = { &handle_wrap_queue, &handle_wrap_queue }; |
100 |
ngx_queue_t req_wrap_queue = { &req_wrap_queue, &req_wrap_queue }; |
101 |
|
102 |
// declared in req_wrap.h
|
103 |
Persistent<String> process_symbol; |
104 |
Persistent<String> domain_symbol; |
105 |
|
106 |
static Persistent<Object> process;
|
107 |
|
108 |
static Persistent<String> errno_symbol;
|
109 |
static Persistent<String> syscall_symbol;
|
110 |
static Persistent<String> errpath_symbol;
|
111 |
static Persistent<String> code_symbol;
|
112 |
|
113 |
static Persistent<String> rss_symbol;
|
114 |
static Persistent<String> heap_total_symbol;
|
115 |
static Persistent<String> heap_used_symbol;
|
116 |
|
117 |
static Persistent<String> listeners_symbol;
|
118 |
static Persistent<String> uncaught_exception_symbol;
|
119 |
static Persistent<String> emit_symbol;
|
120 |
|
121 |
static Persistent<String> enter_symbol;
|
122 |
static Persistent<String> exit_symbol;
|
123 |
static Persistent<String> disposed_symbol;
|
124 |
|
125 |
|
126 |
static bool print_eval = false; |
127 |
static bool force_repl = false; |
128 |
static char *eval_string = NULL; |
129 |
static int option_end_index = 0; |
130 |
static bool use_debug_agent = false; |
131 |
static bool debug_wait_connect = false; |
132 |
static int debug_port=5858; |
133 |
static int max_stack_size = 0; |
134 |
|
135 |
static uv_check_t check_tick_watcher;
|
136 |
static uv_prepare_t prepare_tick_watcher;
|
137 |
static uv_idle_t tick_spinner;
|
138 |
static bool need_tick_cb; |
139 |
static Persistent<String> tick_callback_sym;
|
140 |
|
141 |
|
142 |
#ifdef OPENSSL_NPN_NEGOTIATED
|
143 |
static bool use_npn = true; |
144 |
#else
|
145 |
static bool use_npn = false; |
146 |
#endif
|
147 |
|
148 |
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
149 |
static bool use_sni = true; |
150 |
#else
|
151 |
static bool use_sni = false; |
152 |
#endif
|
153 |
|
154 |
#ifdef __POSIX__
|
155 |
// Buffer for getpwnam_r(), getgrpam_r() and other misc callers; keep this
|
156 |
// scoped at file-level rather than method-level to avoid excess stack usage.
|
157 |
static char getbuf[PATH_MAX + 1]; |
158 |
#endif
|
159 |
|
160 |
// We need to notify V8 when we're idle so that it can run the garbage
|
161 |
// collector. The interface to this is V8::IdleNotification(). It returns
|
162 |
// true if the heap hasn't be fully compacted, and needs to be run again.
|
163 |
// Returning false means that it doesn't have anymore work to do.
|
164 |
//
|
165 |
// A rather convoluted algorithm has been devised to determine when Node is
|
166 |
// idle. You'll have to figure it out for yourself.
|
167 |
static uv_check_t gc_check;
|
168 |
static uv_idle_t gc_idle;
|
169 |
static uv_timer_t gc_timer;
|
170 |
bool need_gc;
|
171 |
|
172 |
// process-relative uptime base, initialized at start-up
|
173 |
static double prog_start_time; |
174 |
|
175 |
#define FAST_TICK 700. |
176 |
#define GC_WAIT_TIME 5000. |
177 |
#define RPM_SAMPLES 100 |
178 |
#define TICK_TIME(n) tick_times[(tick_time_head - (n)) % RPM_SAMPLES]
|
179 |
static int64_t tick_times[RPM_SAMPLES];
|
180 |
static int tick_time_head; |
181 |
|
182 |
static void CheckStatus(uv_timer_t* watcher, int status); |
183 |
|
184 |
static void StartGCTimer () { |
185 |
if (!uv_is_active((uv_handle_t*) &gc_timer)) {
|
186 |
uv_timer_start(&gc_timer, node::CheckStatus, 5000, 5000); |
187 |
} |
188 |
} |
189 |
|
190 |
static void StopGCTimer () { |
191 |
if (uv_is_active((uv_handle_t*) &gc_timer)) {
|
192 |
uv_timer_stop(&gc_timer); |
193 |
} |
194 |
} |
195 |
|
196 |
static void Idle(uv_idle_t* watcher, int status) { |
197 |
assert((uv_idle_t*) watcher == &gc_idle); |
198 |
|
199 |
if (V8::IdleNotification()) {
|
200 |
uv_idle_stop(&gc_idle); |
201 |
StopGCTimer(); |
202 |
} |
203 |
} |
204 |
|
205 |
|
206 |
// Called directly after every call to select() (or epoll, or whatever)
|
207 |
static void Check(uv_check_t* watcher, int status) { |
208 |
assert(watcher == &gc_check); |
209 |
|
210 |
tick_times[tick_time_head] = uv_now(uv_default_loop()); |
211 |
tick_time_head = (tick_time_head + 1) % RPM_SAMPLES;
|
212 |
|
213 |
StartGCTimer(); |
214 |
|
215 |
for (int i = 0; i < (int)(GC_WAIT_TIME/FAST_TICK); i++) { |
216 |
double d = TICK_TIME(i+1) - TICK_TIME(i+2); |
217 |
//printf("d = %f\n", d);
|
218 |
// If in the last 5 ticks the difference between
|
219 |
// ticks was less than 0.7 seconds, then continue.
|
220 |
if (d < FAST_TICK) {
|
221 |
//printf("---\n");
|
222 |
return;
|
223 |
} |
224 |
} |
225 |
|
226 |
// Otherwise start the gc!
|
227 |
|
228 |
//fprintf(stderr, "start idle 2\n");
|
229 |
uv_idle_start(&gc_idle, node::Idle); |
230 |
} |
231 |
|
232 |
|
233 |
static void Tick(void) { |
234 |
// Avoid entering a V8 scope.
|
235 |
if (!need_tick_cb) return; |
236 |
need_tick_cb = false;
|
237 |
|
238 |
uv_idle_stop(&tick_spinner); |
239 |
|
240 |
HandleScope scope; |
241 |
|
242 |
if (tick_callback_sym.IsEmpty()) {
|
243 |
// Lazily set the symbol
|
244 |
tick_callback_sym = NODE_PSYMBOL("_tickCallback");
|
245 |
} |
246 |
|
247 |
Local<Value> cb_v = process->Get(tick_callback_sym); |
248 |
if (!cb_v->IsFunction()) return; |
249 |
Local<Function> cb = Local<Function>::Cast(cb_v); |
250 |
|
251 |
TryCatch try_catch; |
252 |
|
253 |
cb->Call(process, 0, NULL); |
254 |
|
255 |
if (try_catch.HasCaught()) {
|
256 |
FatalException(try_catch); |
257 |
} |
258 |
} |
259 |
|
260 |
|
261 |
static void Spin(uv_idle_t* handle, int status) { |
262 |
assert((uv_idle_t*) handle == &tick_spinner); |
263 |
assert(status == 0);
|
264 |
Tick(); |
265 |
} |
266 |
|
267 |
static void StartTickSpinner() { |
268 |
need_tick_cb = true;
|
269 |
// TODO: this tick_spinner shouldn't be necessary. An ev_prepare should be
|
270 |
// sufficent, the problem is only in the case of the very last "tick" -
|
271 |
// there is nothing left to do in the event loop and libev will exit. The
|
272 |
// ev_prepare callback isn't called before exiting. Thus we start this
|
273 |
// tick_spinner to keep the event loop alive long enough to handle it.
|
274 |
uv_idle_start(&tick_spinner, Spin); |
275 |
} |
276 |
|
277 |
static Handle<Value> NeedTickCallback(const Arguments& args) { |
278 |
StartTickSpinner(); |
279 |
return Undefined();
|
280 |
} |
281 |
|
282 |
static void PrepareTick(uv_prepare_t* handle, int status) { |
283 |
assert(handle == &prepare_tick_watcher); |
284 |
assert(status == 0);
|
285 |
Tick(); |
286 |
} |
287 |
|
288 |
|
289 |
static void CheckTick(uv_check_t* handle, int status) { |
290 |
assert(handle == &check_tick_watcher); |
291 |
assert(status == 0);
|
292 |
Tick(); |
293 |
} |
294 |
|
295 |
static inline const char *errno_string(int errorno) { |
296 |
#define ERRNO_CASE(e) case e: return #e; |
297 |
switch (errorno) {
|
298 |
|
299 |
#ifdef EACCES
|
300 |
ERRNO_CASE(EACCES); |
301 |
#endif
|
302 |
|
303 |
#ifdef EADDRINUSE
|
304 |
ERRNO_CASE(EADDRINUSE); |
305 |
#endif
|
306 |
|
307 |
#ifdef EADDRNOTAVAIL
|
308 |
ERRNO_CASE(EADDRNOTAVAIL); |
309 |
#endif
|
310 |
|
311 |
#ifdef EAFNOSUPPORT
|
312 |
ERRNO_CASE(EAFNOSUPPORT); |
313 |
#endif
|
314 |
|
315 |
#ifdef EAGAIN
|
316 |
ERRNO_CASE(EAGAIN); |
317 |
#endif
|
318 |
|
319 |
#ifdef EWOULDBLOCK
|
320 |
# if EAGAIN != EWOULDBLOCK
|
321 |
ERRNO_CASE(EWOULDBLOCK); |
322 |
# endif
|
323 |
#endif
|
324 |
|
325 |
#ifdef EALREADY
|
326 |
ERRNO_CASE(EALREADY); |
327 |
#endif
|
328 |
|
329 |
#ifdef EBADF
|
330 |
ERRNO_CASE(EBADF); |
331 |
#endif
|
332 |
|
333 |
#ifdef EBADMSG
|
334 |
ERRNO_CASE(EBADMSG); |
335 |
#endif
|
336 |
|
337 |
#ifdef EBUSY
|
338 |
ERRNO_CASE(EBUSY); |
339 |
#endif
|
340 |
|
341 |
#ifdef ECANCELED
|
342 |
ERRNO_CASE(ECANCELED); |
343 |
#endif
|
344 |
|
345 |
#ifdef ECHILD
|
346 |
ERRNO_CASE(ECHILD); |
347 |
#endif
|
348 |
|
349 |
#ifdef ECONNABORTED
|
350 |
ERRNO_CASE(ECONNABORTED); |
351 |
#endif
|
352 |
|
353 |
#ifdef ECONNREFUSED
|
354 |
ERRNO_CASE(ECONNREFUSED); |
355 |
#endif
|
356 |
|
357 |
#ifdef ECONNRESET
|
358 |
ERRNO_CASE(ECONNRESET); |
359 |
#endif
|
360 |
|
361 |
#ifdef EDEADLK
|
362 |
ERRNO_CASE(EDEADLK); |
363 |
#endif
|
364 |
|
365 |
#ifdef EDESTADDRREQ
|
366 |
ERRNO_CASE(EDESTADDRREQ); |
367 |
#endif
|
368 |
|
369 |
#ifdef EDOM
|
370 |
ERRNO_CASE(EDOM); |
371 |
#endif
|
372 |
|
373 |
#ifdef EDQUOT
|
374 |
ERRNO_CASE(EDQUOT); |
375 |
#endif
|
376 |
|
377 |
#ifdef EEXIST
|
378 |
ERRNO_CASE(EEXIST); |
379 |
#endif
|
380 |
|
381 |
#ifdef EFAULT
|
382 |
ERRNO_CASE(EFAULT); |
383 |
#endif
|
384 |
|
385 |
#ifdef EFBIG
|
386 |
ERRNO_CASE(EFBIG); |
387 |
#endif
|
388 |
|
389 |
#ifdef EHOSTUNREACH
|
390 |
ERRNO_CASE(EHOSTUNREACH); |
391 |
#endif
|
392 |
|
393 |
#ifdef EIDRM
|
394 |
ERRNO_CASE(EIDRM); |
395 |
#endif
|
396 |
|
397 |
#ifdef EILSEQ
|
398 |
ERRNO_CASE(EILSEQ); |
399 |
#endif
|
400 |
|
401 |
#ifdef EINPROGRESS
|
402 |
ERRNO_CASE(EINPROGRESS); |
403 |
#endif
|
404 |
|
405 |
#ifdef EINTR
|
406 |
ERRNO_CASE(EINTR); |
407 |
#endif
|
408 |
|
409 |
#ifdef EINVAL
|
410 |
ERRNO_CASE(EINVAL); |
411 |
#endif
|
412 |
|
413 |
#ifdef EIO
|
414 |
ERRNO_CASE(EIO); |
415 |
#endif
|
416 |
|
417 |
#ifdef EISCONN
|
418 |
ERRNO_CASE(EISCONN); |
419 |
#endif
|
420 |
|
421 |
#ifdef EISDIR
|
422 |
ERRNO_CASE(EISDIR); |
423 |
#endif
|
424 |
|
425 |
#ifdef ELOOP
|
426 |
ERRNO_CASE(ELOOP); |
427 |
#endif
|
428 |
|
429 |
#ifdef EMFILE
|
430 |
ERRNO_CASE(EMFILE); |
431 |
#endif
|
432 |
|
433 |
#ifdef EMLINK
|
434 |
ERRNO_CASE(EMLINK); |
435 |
#endif
|
436 |
|
437 |
#ifdef EMSGSIZE
|
438 |
ERRNO_CASE(EMSGSIZE); |
439 |
#endif
|
440 |
|
441 |
#ifdef EMULTIHOP
|
442 |
ERRNO_CASE(EMULTIHOP); |
443 |
#endif
|
444 |
|
445 |
#ifdef ENAMETOOLONG
|
446 |
ERRNO_CASE(ENAMETOOLONG); |
447 |
#endif
|
448 |
|
449 |
#ifdef ENETDOWN
|
450 |
ERRNO_CASE(ENETDOWN); |
451 |
#endif
|
452 |
|
453 |
#ifdef ENETRESET
|
454 |
ERRNO_CASE(ENETRESET); |
455 |
#endif
|
456 |
|
457 |
#ifdef ENETUNREACH
|
458 |
ERRNO_CASE(ENETUNREACH); |
459 |
#endif
|
460 |
|
461 |
#ifdef ENFILE
|
462 |
ERRNO_CASE(ENFILE); |
463 |
#endif
|
464 |
|
465 |
#ifdef ENOBUFS
|
466 |
ERRNO_CASE(ENOBUFS); |
467 |
#endif
|
468 |
|
469 |
#ifdef ENODATA
|
470 |
ERRNO_CASE(ENODATA); |
471 |
#endif
|
472 |
|
473 |
#ifdef ENODEV
|
474 |
ERRNO_CASE(ENODEV); |
475 |
#endif
|
476 |
|
477 |
#ifdef ENOENT
|
478 |
ERRNO_CASE(ENOENT); |
479 |
#endif
|
480 |
|
481 |
#ifdef ENOEXEC
|
482 |
ERRNO_CASE(ENOEXEC); |
483 |
#endif
|
484 |
|
485 |
#ifdef ENOLINK
|
486 |
ERRNO_CASE(ENOLINK); |
487 |
#endif
|
488 |
|
489 |
#ifdef ENOLCK
|
490 |
# if ENOLINK != ENOLCK
|
491 |
ERRNO_CASE(ENOLCK); |
492 |
# endif
|
493 |
#endif
|
494 |
|
495 |
#ifdef ENOMEM
|
496 |
ERRNO_CASE(ENOMEM); |
497 |
#endif
|
498 |
|
499 |
#ifdef ENOMSG
|
500 |
ERRNO_CASE(ENOMSG); |
501 |
#endif
|
502 |
|
503 |
#ifdef ENOPROTOOPT
|
504 |
ERRNO_CASE(ENOPROTOOPT); |
505 |
#endif
|
506 |
|
507 |
#ifdef ENOSPC
|
508 |
ERRNO_CASE(ENOSPC); |
509 |
#endif
|
510 |
|
511 |
#ifdef ENOSR
|
512 |
ERRNO_CASE(ENOSR); |
513 |
#endif
|
514 |
|
515 |
#ifdef ENOSTR
|
516 |
ERRNO_CASE(ENOSTR); |
517 |
#endif
|
518 |
|
519 |
#ifdef ENOSYS
|
520 |
ERRNO_CASE(ENOSYS); |
521 |
#endif
|
522 |
|
523 |
#ifdef ENOTCONN
|
524 |
ERRNO_CASE(ENOTCONN); |
525 |
#endif
|
526 |
|
527 |
#ifdef ENOTDIR
|
528 |
ERRNO_CASE(ENOTDIR); |
529 |
#endif
|
530 |
|
531 |
#ifdef ENOTEMPTY
|
532 |
ERRNO_CASE(ENOTEMPTY); |
533 |
#endif
|
534 |
|
535 |
#ifdef ENOTSOCK
|
536 |
ERRNO_CASE(ENOTSOCK); |
537 |
#endif
|
538 |
|
539 |
#ifdef ENOTSUP
|
540 |
ERRNO_CASE(ENOTSUP); |
541 |
#else
|
542 |
# ifdef EOPNOTSUPP
|
543 |
ERRNO_CASE(EOPNOTSUPP); |
544 |
# endif
|
545 |
#endif
|
546 |
|
547 |
#ifdef ENOTTY
|
548 |
ERRNO_CASE(ENOTTY); |
549 |
#endif
|
550 |
|
551 |
#ifdef ENXIO
|
552 |
ERRNO_CASE(ENXIO); |
553 |
#endif
|
554 |
|
555 |
|
556 |
#ifdef EOVERFLOW
|
557 |
ERRNO_CASE(EOVERFLOW); |
558 |
#endif
|
559 |
|
560 |
#ifdef EPERM
|
561 |
ERRNO_CASE(EPERM); |
562 |
#endif
|
563 |
|
564 |
#ifdef EPIPE
|
565 |
ERRNO_CASE(EPIPE); |
566 |
#endif
|
567 |
|
568 |
#ifdef EPROTO
|
569 |
ERRNO_CASE(EPROTO); |
570 |
#endif
|
571 |
|
572 |
#ifdef EPROTONOSUPPORT
|
573 |
ERRNO_CASE(EPROTONOSUPPORT); |
574 |
#endif
|
575 |
|
576 |
#ifdef EPROTOTYPE
|
577 |
ERRNO_CASE(EPROTOTYPE); |
578 |
#endif
|
579 |
|
580 |
#ifdef ERANGE
|
581 |
ERRNO_CASE(ERANGE); |
582 |
#endif
|
583 |
|
584 |
#ifdef EROFS
|
585 |
ERRNO_CASE(EROFS); |
586 |
#endif
|
587 |
|
588 |
#ifdef ESPIPE
|
589 |
ERRNO_CASE(ESPIPE); |
590 |
#endif
|
591 |
|
592 |
#ifdef ESRCH
|
593 |
ERRNO_CASE(ESRCH); |
594 |
#endif
|
595 |
|
596 |
#ifdef ESTALE
|
597 |
ERRNO_CASE(ESTALE); |
598 |
#endif
|
599 |
|
600 |
#ifdef ETIME
|
601 |
ERRNO_CASE(ETIME); |
602 |
#endif
|
603 |
|
604 |
#ifdef ETIMEDOUT
|
605 |
ERRNO_CASE(ETIMEDOUT); |
606 |
#endif
|
607 |
|
608 |
#ifdef ETXTBSY
|
609 |
ERRNO_CASE(ETXTBSY); |
610 |
#endif
|
611 |
|
612 |
#ifdef EXDEV
|
613 |
ERRNO_CASE(EXDEV); |
614 |
#endif
|
615 |
|
616 |
default: return ""; |
617 |
} |
618 |
} |
619 |
|
620 |
const char *signo_string(int signo) { |
621 |
#define SIGNO_CASE(e) case e: return #e; |
622 |
switch (signo) {
|
623 |
|
624 |
#ifdef SIGHUP
|
625 |
SIGNO_CASE(SIGHUP); |
626 |
#endif
|
627 |
|
628 |
#ifdef SIGINT
|
629 |
SIGNO_CASE(SIGINT); |
630 |
#endif
|
631 |
|
632 |
#ifdef SIGQUIT
|
633 |
SIGNO_CASE(SIGQUIT); |
634 |
#endif
|
635 |
|
636 |
#ifdef SIGILL
|
637 |
SIGNO_CASE(SIGILL); |
638 |
#endif
|
639 |
|
640 |
#ifdef SIGTRAP
|
641 |
SIGNO_CASE(SIGTRAP); |
642 |
#endif
|
643 |
|
644 |
#ifdef SIGABRT
|
645 |
SIGNO_CASE(SIGABRT); |
646 |
#endif
|
647 |
|
648 |
#ifdef SIGIOT
|
649 |
# if SIGABRT != SIGIOT
|
650 |
SIGNO_CASE(SIGIOT); |
651 |
# endif
|
652 |
#endif
|
653 |
|
654 |
#ifdef SIGBUS
|
655 |
SIGNO_CASE(SIGBUS); |
656 |
#endif
|
657 |
|
658 |
#ifdef SIGFPE
|
659 |
SIGNO_CASE(SIGFPE); |
660 |
#endif
|
661 |
|
662 |
#ifdef SIGKILL
|
663 |
SIGNO_CASE(SIGKILL); |
664 |
#endif
|
665 |
|
666 |
#ifdef SIGUSR1
|
667 |
SIGNO_CASE(SIGUSR1); |
668 |
#endif
|
669 |
|
670 |
#ifdef SIGSEGV
|
671 |
SIGNO_CASE(SIGSEGV); |
672 |
#endif
|
673 |
|
674 |
#ifdef SIGUSR2
|
675 |
SIGNO_CASE(SIGUSR2); |
676 |
#endif
|
677 |
|
678 |
#ifdef SIGPIPE
|
679 |
SIGNO_CASE(SIGPIPE); |
680 |
#endif
|
681 |
|
682 |
#ifdef SIGALRM
|
683 |
SIGNO_CASE(SIGALRM); |
684 |
#endif
|
685 |
|
686 |
SIGNO_CASE(SIGTERM); |
687 |
|
688 |
#ifdef SIGCHLD
|
689 |
SIGNO_CASE(SIGCHLD); |
690 |
#endif
|
691 |
|
692 |
#ifdef SIGSTKFLT
|
693 |
SIGNO_CASE(SIGSTKFLT); |
694 |
#endif
|
695 |
|
696 |
|
697 |
#ifdef SIGCONT
|
698 |
SIGNO_CASE(SIGCONT); |
699 |
#endif
|
700 |
|
701 |
#ifdef SIGSTOP
|
702 |
SIGNO_CASE(SIGSTOP); |
703 |
#endif
|
704 |
|
705 |
#ifdef SIGTSTP
|
706 |
SIGNO_CASE(SIGTSTP); |
707 |
#endif
|
708 |
|
709 |
#ifdef SIGTTIN
|
710 |
SIGNO_CASE(SIGTTIN); |
711 |
#endif
|
712 |
|
713 |
#ifdef SIGTTOU
|
714 |
SIGNO_CASE(SIGTTOU); |
715 |
#endif
|
716 |
|
717 |
#ifdef SIGURG
|
718 |
SIGNO_CASE(SIGURG); |
719 |
#endif
|
720 |
|
721 |
#ifdef SIGXCPU
|
722 |
SIGNO_CASE(SIGXCPU); |
723 |
#endif
|
724 |
|
725 |
#ifdef SIGXFSZ
|
726 |
SIGNO_CASE(SIGXFSZ); |
727 |
#endif
|
728 |
|
729 |
#ifdef SIGVTALRM
|
730 |
SIGNO_CASE(SIGVTALRM); |
731 |
#endif
|
732 |
|
733 |
#ifdef SIGPROF
|
734 |
SIGNO_CASE(SIGPROF); |
735 |
#endif
|
736 |
|
737 |
#ifdef SIGWINCH
|
738 |
SIGNO_CASE(SIGWINCH); |
739 |
#endif
|
740 |
|
741 |
#ifdef SIGIO
|
742 |
SIGNO_CASE(SIGIO); |
743 |
#endif
|
744 |
|
745 |
#ifdef SIGPOLL
|
746 |
# if SIGPOLL != SIGIO
|
747 |
SIGNO_CASE(SIGPOLL); |
748 |
# endif
|
749 |
#endif
|
750 |
|
751 |
#ifdef SIGLOST
|
752 |
SIGNO_CASE(SIGLOST); |
753 |
#endif
|
754 |
|
755 |
#ifdef SIGPWR
|
756 |
# if SIGPWR != SIGLOST
|
757 |
SIGNO_CASE(SIGPWR); |
758 |
# endif
|
759 |
#endif
|
760 |
|
761 |
#ifdef SIGSYS
|
762 |
SIGNO_CASE(SIGSYS); |
763 |
#endif
|
764 |
|
765 |
default: return ""; |
766 |
} |
767 |
} |
768 |
|
769 |
|
770 |
Local<Value> ErrnoException(int errorno,
|
771 |
const char *syscall, |
772 |
const char *msg, |
773 |
const char *path) { |
774 |
Local<Value> e; |
775 |
Local<String> estring = String::NewSymbol(errno_string(errorno)); |
776 |
if (!msg[0]) { |
777 |
msg = strerror(errorno); |
778 |
} |
779 |
Local<String> message = String::NewSymbol(msg); |
780 |
|
781 |
Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
|
782 |
Local<String> cons2 = String::Concat(cons1, message); |
783 |
|
784 |
if (syscall_symbol.IsEmpty()) {
|
785 |
syscall_symbol = NODE_PSYMBOL("syscall");
|
786 |
errno_symbol = NODE_PSYMBOL("errno");
|
787 |
errpath_symbol = NODE_PSYMBOL("path");
|
788 |
code_symbol = NODE_PSYMBOL("code");
|
789 |
} |
790 |
|
791 |
if (path) {
|
792 |
Local<String> cons3 = String::Concat(cons2, String::NewSymbol(" '"));
|
793 |
Local<String> cons4 = String::Concat(cons3, String::New(path)); |
794 |
Local<String> cons5 = String::Concat(cons4, String::NewSymbol("'"));
|
795 |
e = Exception::Error(cons5); |
796 |
} else {
|
797 |
e = Exception::Error(cons2); |
798 |
} |
799 |
|
800 |
Local<Object> obj = e->ToObject(); |
801 |
|
802 |
obj->Set(errno_symbol, Integer::New(errorno)); |
803 |
obj->Set(code_symbol, estring); |
804 |
if (path) obj->Set(errpath_symbol, String::New(path));
|
805 |
if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
|
806 |
return e;
|
807 |
} |
808 |
|
809 |
|
810 |
static const char* get_uv_errno_string(int errorno) { |
811 |
uv_err_t err; |
812 |
memset(&err, 0, sizeof err); |
813 |
err.code = (uv_err_code)errorno; |
814 |
return uv_err_name(err);
|
815 |
} |
816 |
|
817 |
|
818 |
static const char* get_uv_errno_message(int errorno) { |
819 |
uv_err_t err; |
820 |
memset(&err, 0, sizeof err); |
821 |
err.code = (uv_err_code)errorno; |
822 |
return uv_strerror(err);
|
823 |
} |
824 |
|
825 |
|
826 |
// hack alert! copy of ErrnoException, tuned for uv errors
|
827 |
Local<Value> UVException(int errorno,
|
828 |
const char *syscall, |
829 |
const char *msg, |
830 |
const char *path) { |
831 |
if (syscall_symbol.IsEmpty()) {
|
832 |
syscall_symbol = NODE_PSYMBOL("syscall");
|
833 |
errno_symbol = NODE_PSYMBOL("errno");
|
834 |
errpath_symbol = NODE_PSYMBOL("path");
|
835 |
code_symbol = NODE_PSYMBOL("code");
|
836 |
} |
837 |
|
838 |
if (!msg || !msg[0]) |
839 |
msg = get_uv_errno_message(errorno); |
840 |
|
841 |
Local<String> estring = String::NewSymbol(get_uv_errno_string(errorno)); |
842 |
Local<String> message = String::NewSymbol(msg); |
843 |
Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
|
844 |
Local<String> cons2 = String::Concat(cons1, message); |
845 |
|
846 |
Local<Value> e; |
847 |
|
848 |
Local<String> path_str; |
849 |
|
850 |
if (path) {
|
851 |
#ifdef _WIN32
|
852 |
if (strncmp(path, "\\\\?\\UNC\\", 8) == 0) { |
853 |
path_str = String::Concat(String::New("\\\\"), String::New(path + 8)); |
854 |
} else if (strncmp(path, "\\\\?\\", 4) == 0) { |
855 |
path_str = String::New(path + 4);
|
856 |
} else {
|
857 |
path_str = String::New(path); |
858 |
} |
859 |
#else
|
860 |
path_str = String::New(path); |
861 |
#endif
|
862 |
|
863 |
Local<String> cons3 = String::Concat(cons2, String::NewSymbol(" '"));
|
864 |
Local<String> cons4 = String::Concat(cons3, path_str); |
865 |
Local<String> cons5 = String::Concat(cons4, String::NewSymbol("'"));
|
866 |
e = Exception::Error(cons5); |
867 |
} else {
|
868 |
e = Exception::Error(cons2); |
869 |
} |
870 |
|
871 |
Local<Object> obj = e->ToObject(); |
872 |
|
873 |
// TODO errno should probably go
|
874 |
obj->Set(errno_symbol, Integer::New(errorno)); |
875 |
obj->Set(code_symbol, estring); |
876 |
if (path) obj->Set(errpath_symbol, path_str);
|
877 |
if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
|
878 |
return e;
|
879 |
} |
880 |
|
881 |
|
882 |
#ifdef _WIN32
|
883 |
// Does about the same as strerror(),
|
884 |
// but supports all windows error messages
|
885 |
static const char *winapi_strerror(const int errorno) { |
886 |
char *errmsg = NULL; |
887 |
|
888 |
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
889 |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
|
890 |
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errmsg, 0, NULL); |
891 |
|
892 |
if (errmsg) {
|
893 |
// Remove trailing newlines
|
894 |
for (int i = strlen(errmsg) - 1; |
895 |
i >= 0 && (errmsg[i] == '\n' || errmsg[i] == '\r'); i--) { |
896 |
errmsg[i] = '\0';
|
897 |
} |
898 |
|
899 |
return errmsg;
|
900 |
} else {
|
901 |
// FormatMessage failed
|
902 |
return "Unknown error"; |
903 |
} |
904 |
} |
905 |
|
906 |
|
907 |
Local<Value> WinapiErrnoException(int errorno,
|
908 |
const char* syscall, |
909 |
const char* msg, |
910 |
const char* path) { |
911 |
Local<Value> e; |
912 |
if (!msg || !msg[0]) { |
913 |
msg = winapi_strerror(errorno); |
914 |
} |
915 |
Local<String> message = String::NewSymbol(msg); |
916 |
|
917 |
if (syscall_symbol.IsEmpty()) {
|
918 |
syscall_symbol = NODE_PSYMBOL("syscall");
|
919 |
errno_symbol = NODE_PSYMBOL("errno");
|
920 |
errpath_symbol = NODE_PSYMBOL("path");
|
921 |
code_symbol = NODE_PSYMBOL("code");
|
922 |
} |
923 |
|
924 |
if (path) {
|
925 |
Local<String> cons1 = String::Concat(message, String::NewSymbol(" '"));
|
926 |
Local<String> cons2 = String::Concat(cons1, String::New(path)); |
927 |
Local<String> cons3 = String::Concat(cons2, String::NewSymbol("'"));
|
928 |
e = Exception::Error(cons3); |
929 |
} else {
|
930 |
e = Exception::Error(message); |
931 |
} |
932 |
|
933 |
Local<Object> obj = e->ToObject(); |
934 |
|
935 |
obj->Set(errno_symbol, Integer::New(errorno)); |
936 |
if (path) obj->Set(errpath_symbol, String::New(path));
|
937 |
if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
|
938 |
return e;
|
939 |
} |
940 |
#endif
|
941 |
|
942 |
|
943 |
Handle<Value> FromConstructorTemplate(Persistent<FunctionTemplate>& t, |
944 |
const Arguments& args) {
|
945 |
HandleScope scope; |
946 |
|
947 |
const int argc = args.Length(); |
948 |
Local<Value>* argv = new Local<Value>[argc];
|
949 |
|
950 |
for (int i = 0; i < argc; ++i) { |
951 |
argv[i] = args[i]; |
952 |
} |
953 |
|
954 |
Local<Object> instance = t->GetFunction()->NewInstance(argc, argv); |
955 |
|
956 |
delete[] argv;
|
957 |
|
958 |
return scope.Close(instance);
|
959 |
} |
960 |
|
961 |
|
962 |
// MakeCallback may only be made directly off the event loop.
|
963 |
// That is there can be no JavaScript stack frames underneath it.
|
964 |
// (Is there any way to assert that?)
|
965 |
//
|
966 |
// Maybe make this a method of a node::Handle super class
|
967 |
//
|
968 |
Handle<Value> |
969 |
MakeCallback(const Handle<Object> object,
|
970 |
const char* method, |
971 |
int argc,
|
972 |
Handle<Value> argv[]) { |
973 |
HandleScope scope; |
974 |
|
975 |
Handle<Value> ret = |
976 |
MakeCallback(object, String::NewSymbol(method), argc, argv); |
977 |
|
978 |
return scope.Close(ret);
|
979 |
} |
980 |
|
981 |
Handle<Value> |
982 |
MakeCallback(const Handle<Object> object,
|
983 |
const Handle<String> symbol,
|
984 |
int argc,
|
985 |
Handle<Value> argv[]) { |
986 |
HandleScope scope; |
987 |
|
988 |
Local<Value> callback_v = object->Get(symbol); |
989 |
if (!callback_v->IsFunction()) {
|
990 |
String::Utf8Value method(symbol); |
991 |
// XXX: If the object has a domain attached, handle it there?
|
992 |
// At least, would be good to get *some* sort of indication
|
993 |
// of how we got here, even if it's not catchable.
|
994 |
fprintf(stderr, "Non-function in MakeCallback. method = %s\n", *method);
|
995 |
abort(); |
996 |
} |
997 |
|
998 |
Local<Function> callback = Local<Function>::Cast(callback_v); |
999 |
|
1000 |
return scope.Close(MakeCallback(object, callback, argc, argv));
|
1001 |
} |
1002 |
|
1003 |
Handle<Value> |
1004 |
MakeCallback(const Handle<Object> object,
|
1005 |
const Handle<Function> callback,
|
1006 |
int argc,
|
1007 |
Handle<Value> argv[]) { |
1008 |
HandleScope scope; |
1009 |
|
1010 |
// TODO Hook for long stack traces to be made here.
|
1011 |
|
1012 |
TryCatch try_catch; |
1013 |
|
1014 |
if (enter_symbol.IsEmpty()) {
|
1015 |
enter_symbol = NODE_PSYMBOL("enter");
|
1016 |
exit_symbol = NODE_PSYMBOL("exit");
|
1017 |
disposed_symbol = NODE_PSYMBOL("_disposed");
|
1018 |
} |
1019 |
|
1020 |
Local<Value> domain_v = object->Get(domain_symbol); |
1021 |
Local<Object> domain; |
1022 |
Local<Function> enter; |
1023 |
Local<Function> exit; |
1024 |
if (!domain_v->IsUndefined()) {
|
1025 |
domain = domain_v->ToObject(); |
1026 |
if (domain->Get(disposed_symbol)->BooleanValue()) {
|
1027 |
// domain has been disposed of.
|
1028 |
return Undefined();
|
1029 |
} |
1030 |
enter = Local<Function>::Cast(domain->Get(enter_symbol)); |
1031 |
enter->Call(domain, 0, NULL); |
1032 |
} |
1033 |
|
1034 |
if (try_catch.HasCaught()) {
|
1035 |
FatalException(try_catch); |
1036 |
return Undefined();
|
1037 |
} |
1038 |
|
1039 |
Local<Value> ret = callback->Call(object, argc, argv); |
1040 |
|
1041 |
if (try_catch.HasCaught()) {
|
1042 |
FatalException(try_catch); |
1043 |
return Undefined();
|
1044 |
} |
1045 |
|
1046 |
if (!domain_v->IsUndefined()) {
|
1047 |
exit = Local<Function>::Cast(domain->Get(exit_symbol)); |
1048 |
exit->Call(domain, 0, NULL); |
1049 |
} |
1050 |
|
1051 |
if (try_catch.HasCaught()) {
|
1052 |
FatalException(try_catch); |
1053 |
return Undefined();
|
1054 |
} |
1055 |
|
1056 |
return scope.Close(ret);
|
1057 |
} |
1058 |
|
1059 |
|
1060 |
void SetErrno(uv_err_t err) {
|
1061 |
HandleScope scope; |
1062 |
|
1063 |
if (errno_symbol.IsEmpty()) {
|
1064 |
errno_symbol = NODE_PSYMBOL("errno");
|
1065 |
} |
1066 |
|
1067 |
if (err.code == UV_UNKNOWN) {
|
1068 |
char errno_buf[100]; |
1069 |
snprintf(errno_buf, 100, "Unknown system errno %d", err.sys_errno_); |
1070 |
Context::GetCurrent()->Global()->Set(errno_symbol, String::New(errno_buf)); |
1071 |
} else {
|
1072 |
Context::GetCurrent()->Global()->Set(errno_symbol, |
1073 |
String::NewSymbol(uv_err_name(err))); |
1074 |
} |
1075 |
} |
1076 |
|
1077 |
|
1078 |
enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) { |
1079 |
HandleScope scope; |
1080 |
|
1081 |
if (!encoding_v->IsString()) return _default; |
1082 |
|
1083 |
String::Utf8Value encoding(encoding_v); |
1084 |
|
1085 |
if (strcasecmp(*encoding, "utf8") == 0) { |
1086 |
return UTF8;
|
1087 |
} else if (strcasecmp(*encoding, "utf-8") == 0) { |
1088 |
return UTF8;
|
1089 |
} else if (strcasecmp(*encoding, "ascii") == 0) { |
1090 |
return ASCII;
|
1091 |
} else if (strcasecmp(*encoding, "base64") == 0) { |
1092 |
return BASE64;
|
1093 |
} else if (strcasecmp(*encoding, "ucs2") == 0) { |
1094 |
return UCS2;
|
1095 |
} else if (strcasecmp(*encoding, "ucs-2") == 0) { |
1096 |
return UCS2;
|
1097 |
} else if (strcasecmp(*encoding, "binary") == 0) { |
1098 |
return BINARY;
|
1099 |
} else if (strcasecmp(*encoding, "hex") == 0) { |
1100 |
return HEX;
|
1101 |
} else if (strcasecmp(*encoding, "raw") == 0) { |
1102 |
fprintf(stderr, "'raw' (array of integers) has been removed. "
|
1103 |
"Use 'binary'.\n");
|
1104 |
return BINARY;
|
1105 |
} else if (strcasecmp(*encoding, "raws") == 0) { |
1106 |
fprintf(stderr, "'raws' encoding has been renamed to 'binary'. "
|
1107 |
"Please update your code.\n");
|
1108 |
return BINARY;
|
1109 |
} else {
|
1110 |
return _default;
|
1111 |
} |
1112 |
} |
1113 |
|
1114 |
Local<Value> Encode(const void *buf, size_t len, enum encoding encoding) { |
1115 |
HandleScope scope; |
1116 |
|
1117 |
if (!len) return scope.Close(String::Empty()); |
1118 |
|
1119 |
if (encoding == BINARY) {
|
1120 |
const unsigned char *cbuf = static_cast<const unsigned char*>(buf); |
1121 |
uint16_t * twobytebuf = new uint16_t[len];
|
1122 |
for (size_t i = 0; i < len; i++) { |
1123 |
// XXX is the following line platform independent?
|
1124 |
twobytebuf[i] = cbuf[i]; |
1125 |
} |
1126 |
Local<String> chunk = String::New(twobytebuf, len); |
1127 |
delete [] twobytebuf; // TODO use ExternalTwoByteString? |
1128 |
return scope.Close(chunk);
|
1129 |
} |
1130 |
|
1131 |
// utf8 or ascii encoding
|
1132 |
Local<String> chunk = String::New((const char*)buf, len); |
1133 |
return scope.Close(chunk);
|
1134 |
} |
1135 |
|
1136 |
// Returns -1 if the handle was not valid for decoding
|
1137 |
ssize_t DecodeBytes(v8::Handle<v8::Value> val, enum encoding encoding) {
|
1138 |
HandleScope scope; |
1139 |
|
1140 |
if (val->IsArray()) {
|
1141 |
fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
|
1142 |
"Use 'binary'.\n");
|
1143 |
assert(0);
|
1144 |
return -1; |
1145 |
} |
1146 |
|
1147 |
if (encoding == BINARY && Buffer::HasInstance(val)) {
|
1148 |
return Buffer::Length(val->ToObject());
|
1149 |
} |
1150 |
|
1151 |
Local<String> str = val->ToString(); |
1152 |
|
1153 |
if (encoding == UTF8) return str->Utf8Length(); |
1154 |
else if (encoding == UCS2) return str->Length() * 2; |
1155 |
else if (encoding == HEX) return str->Length() / 2; |
1156 |
|
1157 |
return str->Length();
|
1158 |
} |
1159 |
|
1160 |
#ifndef MIN
|
1161 |
# define MIN(a, b) ((a) < (b) ? (a) : (b))
|
1162 |
#endif
|
1163 |
|
1164 |
// Returns number of bytes written.
|
1165 |
ssize_t DecodeWrite(char *buf,
|
1166 |
size_t buflen, |
1167 |
v8::Handle<v8::Value> val, |
1168 |
enum encoding encoding) {
|
1169 |
HandleScope scope; |
1170 |
|
1171 |
// XXX
|
1172 |
// A lot of improvement can be made here. See:
|
1173 |
// http://code.google.com/p/v8/issues/detail?id=270
|
1174 |
// http://groups.google.com/group/v8-dev/browse_thread/thread/dba28a81d9215291/ece2b50a3b4022c
|
1175 |
// http://groups.google.com/group/v8-users/browse_thread/thread/1f83b0ba1f0a611
|
1176 |
|
1177 |
if (val->IsArray()) {
|
1178 |
fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
|
1179 |
"Use 'binary'.\n");
|
1180 |
assert(0);
|
1181 |
return -1; |
1182 |
} |
1183 |
|
1184 |
Local<String> str = val->ToString(); |
1185 |
|
1186 |
if (encoding == UTF8) {
|
1187 |
str->WriteUtf8(buf, buflen, NULL, String::HINT_MANY_WRITES_EXPECTED);
|
1188 |
return buflen;
|
1189 |
} |
1190 |
|
1191 |
if (encoding == ASCII) {
|
1192 |
str->WriteAscii(buf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
|
1193 |
return buflen;
|
1194 |
} |
1195 |
|
1196 |
// THIS IS AWFUL!!! FIXME
|
1197 |
|
1198 |
assert(encoding == BINARY); |
1199 |
|
1200 |
uint16_t * twobytebuf = new uint16_t[buflen];
|
1201 |
|
1202 |
str->Write(twobytebuf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
|
1203 |
|
1204 |
for (size_t i = 0; i < buflen; i++) { |
1205 |
unsigned char *b = reinterpret_cast<unsigned char*>(&twobytebuf[i]); |
1206 |
buf[i] = b[0];
|
1207 |
} |
1208 |
|
1209 |
delete [] twobytebuf;
|
1210 |
|
1211 |
return buflen;
|
1212 |
} |
1213 |
|
1214 |
|
1215 |
void DisplayExceptionLine (TryCatch &try_catch) {
|
1216 |
HandleScope scope; |
1217 |
|
1218 |
Handle<Message> message = try_catch.Message(); |
1219 |
|
1220 |
uv_tty_reset_mode(); |
1221 |
|
1222 |
fprintf(stderr, "\n");
|
1223 |
|
1224 |
if (!message.IsEmpty()) {
|
1225 |
// Print (filename):(line number): (message).
|
1226 |
String::Utf8Value filename(message->GetScriptResourceName()); |
1227 |
const char* filename_string = *filename; |
1228 |
int linenum = message->GetLineNumber();
|
1229 |
fprintf(stderr, "%s:%i\n", filename_string, linenum);
|
1230 |
// Print line of source code.
|
1231 |
String::Utf8Value sourceline(message->GetSourceLine()); |
1232 |
const char* sourceline_string = *sourceline; |
1233 |
|
1234 |
// HACK HACK HACK
|
1235 |
//
|
1236 |
// FIXME
|
1237 |
//
|
1238 |
// Because of how CommonJS modules work, all scripts are wrapped with a
|
1239 |
// "function (function (exports, __filename, ...) {"
|
1240 |
// to provide script local variables.
|
1241 |
//
|
1242 |
// When reporting errors on the first line of a script, this wrapper
|
1243 |
// function is leaked to the user. This HACK is to remove it. The length
|
1244 |
// of the wrapper is 62. That wrapper is defined in src/node.js
|
1245 |
//
|
1246 |
// If that wrapper is ever changed, then this number also has to be
|
1247 |
// updated. Or - someone could clean this up so that the two peices
|
1248 |
// don't need to be changed.
|
1249 |
//
|
1250 |
// Even better would be to get support into V8 for wrappers that
|
1251 |
// shouldn't be reported to users.
|
1252 |
int offset = linenum == 1 ? 62 : 0; |
1253 |
|
1254 |
fprintf(stderr, "%s\n", sourceline_string + offset);
|
1255 |
// Print wavy underline (GetUnderline is deprecated).
|
1256 |
int start = message->GetStartColumn();
|
1257 |
for (int i = offset; i < start; i++) { |
1258 |
fputc((sourceline_string[i] == '\t') ? '\t' : ' ', stderr); |
1259 |
} |
1260 |
int end = message->GetEndColumn();
|
1261 |
for (int i = start; i < end; i++) { |
1262 |
fputc('^', stderr);
|
1263 |
} |
1264 |
fputc('\n', stderr);
|
1265 |
} |
1266 |
} |
1267 |
|
1268 |
|
1269 |
static void ReportException(TryCatch &try_catch, bool show_line) { |
1270 |
HandleScope scope; |
1271 |
|
1272 |
if (show_line) DisplayExceptionLine(try_catch);
|
1273 |
|
1274 |
String::Utf8Value trace(try_catch.StackTrace()); |
1275 |
|
1276 |
// range errors have a trace member set to undefined
|
1277 |
if (trace.length() > 0 && !try_catch.StackTrace()->IsUndefined()) { |
1278 |
fprintf(stderr, "%s\n", *trace);
|
1279 |
} else {
|
1280 |
// this really only happens for RangeErrors, since they're the only
|
1281 |
// kind that won't have all this info in the trace, or when non-Error
|
1282 |
// objects are thrown manually.
|
1283 |
Local<Value> er = try_catch.Exception(); |
1284 |
bool isErrorObject = er->IsObject() &&
|
1285 |
!(er->ToObject()->Get(String::New("message"))->IsUndefined()) &&
|
1286 |
!(er->ToObject()->Get(String::New("name"))->IsUndefined());
|
1287 |
|
1288 |
if (isErrorObject) {
|
1289 |
String::Utf8Value name(er->ToObject()->Get(String::New("name")));
|
1290 |
fprintf(stderr, "%s: ", *name);
|
1291 |
} |
1292 |
|
1293 |
String::Utf8Value msg(!isErrorObject ? er |
1294 |
: er->ToObject()->Get(String::New("message")));
|
1295 |
fprintf(stderr, "%s\n", *msg);
|
1296 |
} |
1297 |
|
1298 |
fflush(stderr); |
1299 |
} |
1300 |
|
1301 |
// Executes a str within the current v8 context.
|
1302 |
Local<Value> ExecuteString(Handle<String> source, Handle<Value> filename) { |
1303 |
HandleScope scope; |
1304 |
TryCatch try_catch; |
1305 |
|
1306 |
Local<v8::Script> script = v8::Script::Compile(source, filename); |
1307 |
if (script.IsEmpty()) {
|
1308 |
ReportException(try_catch, true);
|
1309 |
exit(1);
|
1310 |
} |
1311 |
|
1312 |
Local<Value> result = script->Run(); |
1313 |
if (result.IsEmpty()) {
|
1314 |
ReportException(try_catch, true);
|
1315 |
exit(1);
|
1316 |
} |
1317 |
|
1318 |
return scope.Close(result);
|
1319 |
} |
1320 |
|
1321 |
|
1322 |
static Handle<Value> GetActiveRequests(const Arguments& args) { |
1323 |
HandleScope scope; |
1324 |
|
1325 |
Local<Array> ary = Array::New(); |
1326 |
ngx_queue_t* q = NULL;
|
1327 |
int i = 0; |
1328 |
|
1329 |
ngx_queue_foreach(q, &req_wrap_queue) { |
1330 |
ReqWrap<uv_req_t>* w = container_of(q, ReqWrap<uv_req_t>, req_wrap_queue_); |
1331 |
if (w->object_.IsEmpty()) continue; |
1332 |
ary->Set(i++, w->object_); |
1333 |
} |
1334 |
|
1335 |
return scope.Close(ary);
|
1336 |
} |
1337 |
|
1338 |
|
1339 |
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
|
1340 |
// implemented here for consistency with GetActiveRequests().
|
1341 |
Handle<Value> GetActiveHandles(const Arguments& args) {
|
1342 |
HandleScope scope; |
1343 |
|
1344 |
Local<Array> ary = Array::New(); |
1345 |
ngx_queue_t* q = NULL;
|
1346 |
int i = 0; |
1347 |
|
1348 |
Local<String> owner_sym = String::New("owner");
|
1349 |
|
1350 |
ngx_queue_foreach(q, &handle_wrap_queue) { |
1351 |
HandleWrap* w = container_of(q, HandleWrap, handle_wrap_queue_); |
1352 |
if (w->object_.IsEmpty() || w->unref_) continue; |
1353 |
Local<Value> obj = w->object_->Get(owner_sym); |
1354 |
if (obj->IsUndefined()) obj = *w->object_;
|
1355 |
ary->Set(i++, obj); |
1356 |
} |
1357 |
|
1358 |
return scope.Close(ary);
|
1359 |
} |
1360 |
|
1361 |
|
1362 |
static Handle<Value> Abort(const Arguments& args) { |
1363 |
abort(); |
1364 |
return Undefined();
|
1365 |
} |
1366 |
|
1367 |
|
1368 |
static Handle<Value> Chdir(const Arguments& args) { |
1369 |
HandleScope scope; |
1370 |
|
1371 |
if (args.Length() != 1 || !args[0]->IsString()) { |
1372 |
return ThrowException(Exception::Error(String::New("Bad argument."))); |
1373 |
} |
1374 |
|
1375 |
String::Utf8Value path(args[0]);
|
1376 |
|
1377 |
uv_err_t r = uv_chdir(*path); |
1378 |
|
1379 |
if (r.code != UV_OK) {
|
1380 |
return ThrowException(UVException(r.code, "uv_chdir")); |
1381 |
} |
1382 |
|
1383 |
return Undefined();
|
1384 |
} |
1385 |
|
1386 |
|
1387 |
static Handle<Value> Cwd(const Arguments& args) { |
1388 |
HandleScope scope; |
1389 |
#ifdef _WIN32
|
1390 |
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
|
1391 |
char buf[MAX_PATH * 4 + 1]; |
1392 |
#else
|
1393 |
char buf[PATH_MAX + 1]; |
1394 |
#endif
|
1395 |
|
1396 |
uv_err_t r = uv_cwd(buf, ARRAY_SIZE(buf) - 1);
|
1397 |
if (r.code != UV_OK) {
|
1398 |
return ThrowException(UVException(r.code, "uv_cwd")); |
1399 |
} |
1400 |
|
1401 |
buf[ARRAY_SIZE(buf) - 1] = '\0'; |
1402 |
Local<String> cwd = String::New(buf); |
1403 |
|
1404 |
return scope.Close(cwd);
|
1405 |
} |
1406 |
|
1407 |
|
1408 |
static Handle<Value> Umask(const Arguments& args) { |
1409 |
HandleScope scope; |
1410 |
unsigned int old; |
1411 |
|
1412 |
if (args.Length() < 1 || args[0]->IsUndefined()) { |
1413 |
old = umask(0);
|
1414 |
umask((mode_t)old); |
1415 |
|
1416 |
} else if(!args[0]->IsInt32() && !args[0]->IsString()) { |
1417 |
return ThrowException(Exception::TypeError(
|
1418 |
String::New("argument must be an integer or octal string.")));
|
1419 |
|
1420 |
} else {
|
1421 |
int oct;
|
1422 |
if(args[0]->IsInt32()) { |
1423 |
oct = args[0]->Uint32Value();
|
1424 |
} else {
|
1425 |
oct = 0;
|
1426 |
String::Utf8Value str(args[0]);
|
1427 |
|
1428 |
// Parse the octal string.
|
1429 |
for (int i = 0; i < str.length(); i++) { |
1430 |
char c = (*str)[i];
|
1431 |
if (c > '7' || c < '0') { |
1432 |
return ThrowException(Exception::TypeError(
|
1433 |
String::New("invalid octal string")));
|
1434 |
} |
1435 |
oct *= 8;
|
1436 |
oct += c - '0';
|
1437 |
} |
1438 |
} |
1439 |
old = umask(static_cast<mode_t>(oct));
|
1440 |
} |
1441 |
|
1442 |
return scope.Close(Uint32::New(old));
|
1443 |
} |
1444 |
|
1445 |
|
1446 |
#ifdef __POSIX__
|
1447 |
|
1448 |
static Handle<Value> GetUid(const Arguments& args) { |
1449 |
HandleScope scope; |
1450 |
int uid = getuid();
|
1451 |
return scope.Close(Integer::New(uid));
|
1452 |
} |
1453 |
|
1454 |
|
1455 |
static Handle<Value> GetGid(const Arguments& args) { |
1456 |
HandleScope scope; |
1457 |
int gid = getgid();
|
1458 |
return scope.Close(Integer::New(gid));
|
1459 |
} |
1460 |
|
1461 |
|
1462 |
static Handle<Value> SetGid(const Arguments& args) { |
1463 |
HandleScope scope; |
1464 |
|
1465 |
if (args.Length() < 1) { |
1466 |
return ThrowException(Exception::Error(
|
1467 |
String::New("setgid requires 1 argument")));
|
1468 |
} |
1469 |
|
1470 |
int gid;
|
1471 |
|
1472 |
if (args[0]->IsNumber()) { |
1473 |
gid = args[0]->Int32Value();
|
1474 |
} else if (args[0]->IsString()) { |
1475 |
String::Utf8Value grpnam(args[0]);
|
1476 |
struct group grp, *grpp = NULL; |
1477 |
int err;
|
1478 |
|
1479 |
if ((err = getgrnam_r(*grpnam, &grp, getbuf, ARRAY_SIZE(getbuf), &grpp)) ||
|
1480 |
grpp == NULL) {
|
1481 |
if (errno == 0) |
1482 |
return ThrowException(Exception::Error(
|
1483 |
String::New("setgid group id does not exist")));
|
1484 |
else
|
1485 |
return ThrowException(ErrnoException(errno, "getgrnam_r")); |
1486 |
} |
1487 |
|
1488 |
gid = grpp->gr_gid; |
1489 |
} else {
|
1490 |
return ThrowException(Exception::Error(
|
1491 |
String::New("setgid argument must be a number or a string")));
|
1492 |
} |
1493 |
|
1494 |
int result;
|
1495 |
if ((result = setgid(gid)) != 0) { |
1496 |
return ThrowException(ErrnoException(errno, "setgid")); |
1497 |
} |
1498 |
return Undefined();
|
1499 |
} |
1500 |
|
1501 |
|
1502 |
static Handle<Value> SetUid(const Arguments& args) { |
1503 |
HandleScope scope; |
1504 |
|
1505 |
if (args.Length() < 1) { |
1506 |
return ThrowException(Exception::Error(
|
1507 |
String::New("setuid requires 1 argument")));
|
1508 |
} |
1509 |
|
1510 |
int uid;
|
1511 |
|
1512 |
if (args[0]->IsNumber()) { |
1513 |
uid = args[0]->Int32Value();
|
1514 |
} else if (args[0]->IsString()) { |
1515 |
String::Utf8Value pwnam(args[0]);
|
1516 |
struct passwd pwd, *pwdp = NULL; |
1517 |
int err;
|
1518 |
|
1519 |
if ((err = getpwnam_r(*pwnam, &pwd, getbuf, ARRAY_SIZE(getbuf), &pwdp)) ||
|
1520 |
pwdp == NULL) {
|
1521 |
if (errno == 0) |
1522 |
return ThrowException(Exception::Error(
|
1523 |
String::New("setuid user id does not exist")));
|
1524 |
else
|
1525 |
return ThrowException(ErrnoException(errno, "getpwnam_r")); |
1526 |
} |
1527 |
|
1528 |
uid = pwdp->pw_uid; |
1529 |
} else {
|
1530 |
return ThrowException(Exception::Error(
|
1531 |
String::New("setuid argument must be a number or a string")));
|
1532 |
} |
1533 |
|
1534 |
int result;
|
1535 |
if ((result = setuid(uid)) != 0) { |
1536 |
return ThrowException(ErrnoException(errno, "setuid")); |
1537 |
} |
1538 |
return Undefined();
|
1539 |
} |
1540 |
|
1541 |
|
1542 |
#endif // __POSIX__ |
1543 |
|
1544 |
|
1545 |
v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
|
1546 |
HandleScope scope; |
1547 |
exit(args[0]->IntegerValue());
|
1548 |
return Undefined();
|
1549 |
} |
1550 |
|
1551 |
|
1552 |
static void CheckStatus(uv_timer_t* watcher, int status) { |
1553 |
assert(watcher == &gc_timer); |
1554 |
|
1555 |
// check memory
|
1556 |
if (!uv_is_active((uv_handle_t*) &gc_idle)) {
|
1557 |
HeapStatistics stats; |
1558 |
V8::GetHeapStatistics(&stats); |
1559 |
if (stats.total_heap_size() > 1024 * 1024 * 128) { |
1560 |
// larger than 128 megs, just start the idle watcher
|
1561 |
uv_idle_start(&gc_idle, node::Idle); |
1562 |
return;
|
1563 |
} |
1564 |
} |
1565 |
|
1566 |
double d = uv_now(uv_default_loop()) - TICK_TIME(3); |
1567 |
|
1568 |
//printfb("timer d = %f\n", d);
|
1569 |
|
1570 |
if (d >= GC_WAIT_TIME - 1.) { |
1571 |
//fprintf(stderr, "start idle\n");
|
1572 |
uv_idle_start(&gc_idle, node::Idle); |
1573 |
} |
1574 |
} |
1575 |
|
1576 |
|
1577 |
static Handle<Value> Uptime(const Arguments& args) { |
1578 |
HandleScope scope; |
1579 |
double uptime;
|
1580 |
|
1581 |
uv_err_t err = uv_uptime(&uptime); |
1582 |
|
1583 |
if (err.code != UV_OK) {
|
1584 |
return Undefined();
|
1585 |
} |
1586 |
|
1587 |
return scope.Close(Number::New(uptime - prog_start_time));
|
1588 |
} |
1589 |
|
1590 |
|
1591 |
v8::Handle<v8::Value> UVCounters(const v8::Arguments& args) {
|
1592 |
HandleScope scope; |
1593 |
|
1594 |
uv_counters_t* c = &uv_default_loop()->counters; |
1595 |
|
1596 |
Local<Object> obj = Object::New(); |
1597 |
|
1598 |
#define setc(name) \
|
1599 |
obj->Set(String::New(#name), Integer::New(static_cast<int32_t>(c->name))); |
1600 |
|
1601 |
setc(eio_init) |
1602 |
setc(req_init) |
1603 |
setc(handle_init) |
1604 |
setc(stream_init) |
1605 |
setc(tcp_init) |
1606 |
setc(udp_init) |
1607 |
setc(pipe_init) |
1608 |
setc(tty_init) |
1609 |
setc(prepare_init) |
1610 |
setc(check_init) |
1611 |
setc(idle_init) |
1612 |
setc(async_init) |
1613 |
setc(timer_init) |
1614 |
setc(process_init) |
1615 |
setc(fs_event_init) |
1616 |
|
1617 |
#undef setc
|
1618 |
|
1619 |
return scope.Close(obj);
|
1620 |
} |
1621 |
|
1622 |
|
1623 |
v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
|
1624 |
HandleScope scope; |
1625 |
|
1626 |
size_t rss; |
1627 |
|
1628 |
uv_err_t err = uv_resident_set_memory(&rss); |
1629 |
|
1630 |
if (err.code != UV_OK) {
|
1631 |
return ThrowException(UVException(err.code, "uv_resident_set_memory")); |
1632 |
} |
1633 |
|
1634 |
Local<Object> info = Object::New(); |
1635 |
|
1636 |
if (rss_symbol.IsEmpty()) {
|
1637 |
rss_symbol = NODE_PSYMBOL("rss");
|
1638 |
heap_total_symbol = NODE_PSYMBOL("heapTotal");
|
1639 |
heap_used_symbol = NODE_PSYMBOL("heapUsed");
|
1640 |
} |
1641 |
|
1642 |
info->Set(rss_symbol, Number::New(rss)); |
1643 |
|
1644 |
// V8 memory usage
|
1645 |
HeapStatistics v8_heap_stats; |
1646 |
V8::GetHeapStatistics(&v8_heap_stats); |
1647 |
info->Set(heap_total_symbol, |
1648 |
Integer::NewFromUnsigned(v8_heap_stats.total_heap_size())); |
1649 |
info->Set(heap_used_symbol, |
1650 |
Integer::NewFromUnsigned(v8_heap_stats.used_heap_size())); |
1651 |
|
1652 |
return scope.Close(info);
|
1653 |
} |
1654 |
|
1655 |
|
1656 |
Handle<Value> Kill(const Arguments& args) {
|
1657 |
HandleScope scope; |
1658 |
|
1659 |
if (args.Length() != 2) { |
1660 |
return ThrowException(Exception::Error(String::New("Bad argument."))); |
1661 |
} |
1662 |
|
1663 |
int pid = args[0]->IntegerValue(); |
1664 |
int sig = args[1]->Int32Value(); |
1665 |
uv_err_t err = uv_kill(pid, sig); |
1666 |
|
1667 |
if (err.code != UV_OK) {
|
1668 |
SetErrno(err); |
1669 |
return scope.Close(Integer::New(-1)); |
1670 |
} |
1671 |
|
1672 |
return Undefined();
|
1673 |
} |
1674 |
|
1675 |
// used in Hrtime() below
|
1676 |
#define NANOS_PER_SEC 1000000000 |
1677 |
|
1678 |
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
|
1679 |
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
|
1680 |
// so this function instead returns an Array with 2 entries representing seconds
|
1681 |
// and nanoseconds, to avoid any integer overflow possibility.
|
1682 |
// Pass in an Array from a previous hrtime() call to instead get a time diff.
|
1683 |
Handle<Value> Hrtime(const v8::Arguments& args) {
|
1684 |
HandleScope scope; |
1685 |
|
1686 |
uint64_t t = uv_hrtime(); |
1687 |
|
1688 |
if (args.Length() > 0) { |
1689 |
// return a time diff tuple
|
1690 |
Local<Array> inArray = Local<Array>::Cast(args[0]);
|
1691 |
uint64_t seconds = inArray->Get(0)->Uint32Value();
|
1692 |
uint64_t nanos = inArray->Get(1)->Uint32Value();
|
1693 |
t -= (seconds * NANOS_PER_SEC) + nanos; |
1694 |
} |
1695 |
|
1696 |
Local<Array> tuple = Array::New(2);
|
1697 |
tuple->Set(0, Integer::NewFromUnsigned(t / NANOS_PER_SEC));
|
1698 |
tuple->Set(1, Integer::NewFromUnsigned(t % NANOS_PER_SEC));
|
1699 |
|
1700 |
return scope.Close(tuple);
|
1701 |
} |
1702 |
|
1703 |
|
1704 |
typedef void (UV_DYNAMIC* extInit)(Handle<Object> exports); |
1705 |
|
1706 |
// DLOpen is node.dlopen(). Used to load 'module.node' dynamically shared
|
1707 |
// objects.
|
1708 |
Handle<Value> DLOpen(const v8::Arguments& args) {
|
1709 |
HandleScope scope; |
1710 |
char symbol[1024], *base, *pos; |
1711 |
uv_lib_t lib; |
1712 |
node_module_struct compat_mod; |
1713 |
int r;
|
1714 |
|
1715 |
if (args.Length() < 2) { |
1716 |
Local<Value> exception = Exception::Error( |
1717 |
String::New("process.dlopen takes exactly 2 arguments."));
|
1718 |
return ThrowException(exception);
|
1719 |
} |
1720 |
|
1721 |
String::Utf8Value filename(args[0]); // Cast |
1722 |
Local<Object> target = args[1]->ToObject(); // Cast |
1723 |
|
1724 |
if (uv_dlopen(*filename, &lib)) {
|
1725 |
Local<String> errmsg = String::New(uv_dlerror(&lib)); |
1726 |
#ifdef _WIN32
|
1727 |
// Windows needs to add the filename into the error message
|
1728 |
errmsg = String::Concat(errmsg, args[0]->ToString());
|
1729 |
#endif
|
1730 |
return ThrowException(Exception::Error(errmsg));
|
1731 |
} |
1732 |
|
1733 |
String::Utf8Value path(args[0]);
|
1734 |
base = *path; |
1735 |
|
1736 |
/* Find the shared library filename within the full path. */
|
1737 |
#ifdef __POSIX__
|
1738 |
pos = strrchr(base, '/');
|
1739 |
if (pos != NULL) { |
1740 |
base = pos + 1;
|
1741 |
} |
1742 |
#else // Windows |
1743 |
for (;;) {
|
1744 |
pos = strpbrk(base, "\\/:");
|
1745 |
if (pos == NULL) { |
1746 |
break;
|
1747 |
} |
1748 |
base = pos + 1;
|
1749 |
} |
1750 |
#endif
|
1751 |
|
1752 |
/* Strip the .node extension. */
|
1753 |
pos = strrchr(base, '.');
|
1754 |
if (pos != NULL) { |
1755 |
*pos = '\0';
|
1756 |
} |
1757 |
|
1758 |
/* Add the `_module` suffix to the extension name. */
|
1759 |
r = snprintf(symbol, sizeof symbol, "%s_module", base); |
1760 |
if (r <= 0 || static_cast<size_t>(r) >= sizeof symbol) { |
1761 |
Local<Value> exception = |
1762 |
Exception::Error(String::New("Out of memory."));
|
1763 |
return ThrowException(exception);
|
1764 |
} |
1765 |
|
1766 |
// Get the init() function from the dynamically shared object.
|
1767 |
node_module_struct *mod; |
1768 |
if (uv_dlsym(&lib, symbol, reinterpret_cast<void**>(&mod))) { |
1769 |
/* Start Compatibility hack: Remove once everyone is using NODE_MODULE macro */
|
1770 |
memset(&compat_mod, 0, sizeof compat_mod); |
1771 |
|
1772 |
mod = &compat_mod; |
1773 |
mod->version = NODE_MODULE_VERSION; |
1774 |
|
1775 |
if (uv_dlsym(&lib, "init", reinterpret_cast<void**>(&mod->register_func))) { |
1776 |
Local<String> errmsg = String::New(uv_dlerror(&lib)); |
1777 |
uv_dlclose(&lib); |
1778 |
return ThrowException(Exception::Error(errmsg));
|
1779 |
} |
1780 |
/* End Compatibility hack */
|
1781 |
} |
1782 |
|
1783 |
if (mod->version != NODE_MODULE_VERSION) {
|
1784 |
Local<Value> exception = Exception::Error( |
1785 |
String::New("Module version mismatch, refusing to load."));
|
1786 |
return ThrowException(exception);
|
1787 |
} |
1788 |
|
1789 |
// Execute the C++ module
|
1790 |
mod->register_func(target); |
1791 |
|
1792 |
// Tell coverity that 'handle' should not be freed when we return.
|
1793 |
// coverity[leaked_storage]
|
1794 |
return Undefined();
|
1795 |
} |
1796 |
|
1797 |
|
1798 |
static void OnFatalError(const char* location, const char* message) { |
1799 |
if (location) {
|
1800 |
fprintf(stderr, "FATAL ERROR: %s %s\n", location, message);
|
1801 |
} else {
|
1802 |
fprintf(stderr, "FATAL ERROR: %s\n", message);
|
1803 |
} |
1804 |
exit(1);
|
1805 |
} |
1806 |
|
1807 |
void FatalException(TryCatch &try_catch) {
|
1808 |
HandleScope scope; |
1809 |
|
1810 |
if (listeners_symbol.IsEmpty()) {
|
1811 |
listeners_symbol = NODE_PSYMBOL("listeners");
|
1812 |
uncaught_exception_symbol = NODE_PSYMBOL("uncaughtException");
|
1813 |
emit_symbol = NODE_PSYMBOL("emit");
|
1814 |
} |
1815 |
|
1816 |
Local<Value> listeners_v = process->Get(listeners_symbol); |
1817 |
assert(listeners_v->IsFunction()); |
1818 |
|
1819 |
Local<Function> listeners = Local<Function>::Cast(listeners_v); |
1820 |
|
1821 |
Local<String> uncaught_exception_symbol_l = Local<String>::New(uncaught_exception_symbol); |
1822 |
Local<Value> argv[1] = { uncaught_exception_symbol_l };
|
1823 |
Local<Value> ret = listeners->Call(process, 1, argv);
|
1824 |
|
1825 |
assert(ret->IsArray()); |
1826 |
|
1827 |
Local<Array> listener_array = Local<Array>::Cast(ret); |
1828 |
|
1829 |
uint32_t length = listener_array->Length(); |
1830 |
// Report and exit if process has no "uncaughtException" listener
|
1831 |
if (length == 0) { |
1832 |
ReportException(try_catch, true);
|
1833 |
exit(1);
|
1834 |
} |
1835 |
|
1836 |
// Otherwise fire the process "uncaughtException" event
|
1837 |
Local<Value> emit_v = process->Get(emit_symbol); |
1838 |
assert(emit_v->IsFunction()); |
1839 |
|
1840 |
Local<Function> emit = Local<Function>::Cast(emit_v); |
1841 |
|
1842 |
Local<Value> error = try_catch.Exception(); |
1843 |
Local<Value> event_argv[2] = { uncaught_exception_symbol_l, error };
|
1844 |
|
1845 |
TryCatch event_try_catch; |
1846 |
emit->Call(process, 2, event_argv);
|
1847 |
|
1848 |
if (event_try_catch.HasCaught()) {
|
1849 |
// the uncaught exception event threw, so we must exit.
|
1850 |
ReportException(event_try_catch, true);
|
1851 |
exit(1);
|
1852 |
} |
1853 |
|
1854 |
// This makes sure uncaught exceptions don't interfere with process.nextTick
|
1855 |
StartTickSpinner(); |
1856 |
} |
1857 |
|
1858 |
|
1859 |
Persistent<Object> binding_cache; |
1860 |
Persistent<Array> module_load_list; |
1861 |
|
1862 |
static Handle<Value> Binding(const Arguments& args) { |
1863 |
HandleScope scope; |
1864 |
|
1865 |
Local<String> module = args[0]->ToString();
|
1866 |
String::Utf8Value module_v(module); |
1867 |
node_module_struct* modp; |
1868 |
|
1869 |
if (binding_cache.IsEmpty()) {
|
1870 |
binding_cache = Persistent<Object>::New(Object::New()); |
1871 |
} |
1872 |
|
1873 |
Local<Object> exports; |
1874 |
|
1875 |
if (binding_cache->Has(module)) {
|
1876 |
exports = binding_cache->Get(module)->ToObject(); |
1877 |
return scope.Close(exports);
|
1878 |
} |
1879 |
|
1880 |
// Append a string to process.moduleLoadList
|
1881 |
char buf[1024]; |
1882 |
snprintf(buf, 1024, "Binding %s", *module_v); |
1883 |
uint32_t l = module_load_list->Length(); |
1884 |
module_load_list->Set(l, String::New(buf)); |
1885 |
|
1886 |
if ((modp = get_builtin_module(*module_v)) != NULL) { |
1887 |
exports = Object::New(); |
1888 |
modp->register_func(exports); |
1889 |
binding_cache->Set(module, exports); |
1890 |
|
1891 |
} else if (!strcmp(*module_v, "constants")) { |
1892 |
exports = Object::New(); |
1893 |
DefineConstants(exports); |
1894 |
binding_cache->Set(module, exports); |
1895 |
|
1896 |
#ifdef __POSIX__
|
1897 |
} else if (!strcmp(*module_v, "io_watcher")) { |
1898 |
exports = Object::New(); |
1899 |
IOWatcher::Initialize(exports); |
1900 |
binding_cache->Set(module, exports); |
1901 |
#endif
|
1902 |
|
1903 |
} else if (!strcmp(*module_v, "natives")) { |
1904 |
exports = Object::New(); |
1905 |
DefineJavaScript(exports); |
1906 |
binding_cache->Set(module, exports); |
1907 |
|
1908 |
} else {
|
1909 |
|
1910 |
return ThrowException(Exception::Error(String::New("No such module"))); |
1911 |
} |
1912 |
|
1913 |
return scope.Close(exports);
|
1914 |
} |
1915 |
|
1916 |
|
1917 |
static Handle<Value> ProcessTitleGetter(Local<String> property,
|
1918 |
const AccessorInfo& info) {
|
1919 |
HandleScope scope; |
1920 |
char buffer[512]; |
1921 |
uv_get_process_title(buffer, sizeof(buffer));
|
1922 |
return scope.Close(String::New(buffer));
|
1923 |
} |
1924 |
|
1925 |
|
1926 |
static void ProcessTitleSetter(Local<String> property, |
1927 |
Local<Value> value, |
1928 |
const AccessorInfo& info) {
|
1929 |
HandleScope scope; |
1930 |
String::Utf8Value title(value); |
1931 |
// TODO: protect with a lock
|
1932 |
uv_set_process_title(*title); |
1933 |
} |
1934 |
|
1935 |
|
1936 |
static Handle<Value> EnvGetter(Local<String> property,
|
1937 |
const AccessorInfo& info) {
|
1938 |
HandleScope scope; |
1939 |
#ifdef __POSIX__
|
1940 |
String::Utf8Value key(property); |
1941 |
const char* val = getenv(*key); |
1942 |
if (val) {
|
1943 |
return scope.Close(String::New(val));
|
1944 |
} |
1945 |
#else // _WIN32 |
1946 |
String::Value key(property); |
1947 |
WCHAR buffer[32767]; // The maximum size allowed for environment variables. |
1948 |
DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key),
|
1949 |
buffer, |
1950 |
ARRAY_SIZE(buffer)); |
1951 |
// If result >= sizeof buffer the buffer was too small. That should never
|
1952 |
// happen. If result == 0 and result != ERROR_SUCCESS the variable was not
|
1953 |
// not found.
|
1954 |
if ((result > 0 || GetLastError() == ERROR_SUCCESS) && |
1955 |
result < ARRAY_SIZE(buffer)) { |
1956 |
return scope.Close(String::New(reinterpret_cast<uint16_t*>(buffer), result)); |
1957 |
} |
1958 |
#endif
|
1959 |
// Not found
|
1960 |
return Undefined();
|
1961 |
} |
1962 |
|
1963 |
|
1964 |
static Handle<Value> EnvSetter(Local<String> property,
|
1965 |
Local<Value> value, |
1966 |
const AccessorInfo& info) {
|
1967 |
HandleScope scope; |
1968 |
#ifdef __POSIX__
|
1969 |
String::Utf8Value key(property); |
1970 |
String::Utf8Value val(value); |
1971 |
setenv(*key, *val, 1);
|
1972 |
#else // _WIN32 |
1973 |
String::Value key(property); |
1974 |
String::Value val(value); |
1975 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
|
1976 |
// Environment variables that start with '=' are read-only.
|
1977 |
if (key_ptr[0] != L'=') { |
1978 |
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
|
1979 |
} |
1980 |
#endif
|
1981 |
// Whether it worked or not, always return rval.
|
1982 |
return scope.Close(value);
|
1983 |
} |
1984 |
|
1985 |
|
1986 |
static Handle<Integer> EnvQuery(Local<String> property,
|
1987 |
const AccessorInfo& info) {
|
1988 |
HandleScope scope; |
1989 |
#ifdef __POSIX__
|
1990 |
String::Utf8Value key(property); |
1991 |
if (getenv(*key)) {
|
1992 |
return scope.Close(Integer::New(None));
|
1993 |
} |
1994 |
#else // _WIN32 |
1995 |
String::Value key(property); |
1996 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
|
1997 |
if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 || |
1998 |
GetLastError() == ERROR_SUCCESS) { |
1999 |
if (key_ptr[0] == L'=') { |
2000 |
// Environment variables that start with '=' are hidden and read-only.
|
2001 |
return scope.Close(Integer::New(v8::ReadOnly ||
|
2002 |
v8::DontDelete || |
2003 |
v8::DontEnum)); |
2004 |
} else {
|
2005 |
return scope.Close(Integer::New(None));
|
2006 |
} |
2007 |
} |
2008 |
#endif
|
2009 |
// Not found
|
2010 |
return scope.Close(Handle<Integer>());
|
2011 |
} |
2012 |
|
2013 |
|
2014 |
static Handle<Boolean> EnvDeleter(Local<String> property,
|
2015 |
const AccessorInfo& info) {
|
2016 |
HandleScope scope; |
2017 |
#ifdef __POSIX__
|
2018 |
String::Utf8Value key(property); |
2019 |
if (!getenv(*key)) return False(); |
2020 |
unsetenv(*key); // can't check return value, it's void on some platforms
|
2021 |
return True();
|
2022 |
#else
|
2023 |
String::Value key(property); |
2024 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
|
2025 |
if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) { |
2026 |
// Deletion failed. Return true if the key wasn't there in the first place,
|
2027 |
// false if it is still there.
|
2028 |
bool rv = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 && |
2029 |
GetLastError() != ERROR_SUCCESS; |
2030 |
return scope.Close(Boolean::New(rv));
|
2031 |
} |
2032 |
return True();
|
2033 |
#endif
|
2034 |
} |
2035 |
|
2036 |
|
2037 |
static Handle<Array> EnvEnumerator(const AccessorInfo& info) { |
2038 |
HandleScope scope; |
2039 |
#ifdef __POSIX__
|
2040 |
int size = 0; |
2041 |
while (environ[size]) size++;
|
2042 |
|
2043 |
Local<Array> env = Array::New(size); |
2044 |
|
2045 |
for (int i = 0; i < size; ++i) { |
2046 |
const char* var = environ[i]; |
2047 |
const char* s = strchr(var, '='); |
2048 |
const int length = s ? s - var : strlen(var); |
2049 |
env->Set(i, String::New(var, length)); |
2050 |
} |
2051 |
#else // _WIN32 |
2052 |
WCHAR* environment = GetEnvironmentStringsW(); |
2053 |
if (environment == NULL) { |
2054 |
// This should not happen.
|
2055 |
return scope.Close(Handle<Array>());
|
2056 |
} |
2057 |
Local<Array> env = Array::New(); |
2058 |
WCHAR* p = environment; |
2059 |
int i = 0; |
2060 |
while (*p != NULL) { |
2061 |
WCHAR *s; |
2062 |
if (*p == L'=') { |
2063 |
// If the key starts with '=' it is a hidden environment variable.
|
2064 |
p += wcslen(p) + 1;
|
2065 |
continue;
|
2066 |
} else {
|
2067 |
s = wcschr(p, L'=');
|
2068 |
} |
2069 |
if (!s) {
|
2070 |
s = p + wcslen(p); |
2071 |
} |
2072 |
env->Set(i++, String::New(reinterpret_cast<uint16_t*>(p), s - p));
|
2073 |
p = s + wcslen(s) + 1;
|
2074 |
} |
2075 |
FreeEnvironmentStringsW(environment); |
2076 |
#endif
|
2077 |
return scope.Close(env);
|
2078 |
} |
2079 |
|
2080 |
|
2081 |
static Handle<Object> GetFeatures() {
|
2082 |
HandleScope scope; |
2083 |
|
2084 |
Local<Object> obj = Object::New(); |
2085 |
obj->Set(String::NewSymbol("debug"),
|
2086 |
#if defined(DEBUG) && DEBUG
|
2087 |
True() |
2088 |
#else
|
2089 |
False() |
2090 |
#endif
|
2091 |
); |
2092 |
|
2093 |
obj->Set(String::NewSymbol("uv"), True());
|
2094 |
obj->Set(String::NewSymbol("ipv6"), True()); // TODO ping libuv |
2095 |
obj->Set(String::NewSymbol("tls_npn"), Boolean::New(use_npn));
|
2096 |
obj->Set(String::NewSymbol("tls_sni"), Boolean::New(use_sni));
|
2097 |
obj->Set(String::NewSymbol("tls"),
|
2098 |
Boolean::New(get_builtin_module("crypto") != NULL)); |
2099 |
|
2100 |
return scope.Close(obj);
|
2101 |
} |
2102 |
|
2103 |
|
2104 |
static Handle<Value> DebugPortGetter(Local<String> property,
|
2105 |
const AccessorInfo& info) {
|
2106 |
HandleScope scope; |
2107 |
return scope.Close(Integer::NewFromUnsigned(debug_port));
|
2108 |
} |
2109 |
|
2110 |
|
2111 |
static void DebugPortSetter(Local<String> property, |
2112 |
Local<Value> value, |
2113 |
const AccessorInfo& info) {
|
2114 |
HandleScope scope; |
2115 |
debug_port = value->NumberValue(); |
2116 |
} |
2117 |
|
2118 |
|
2119 |
static Handle<Value> DebugProcess(const Arguments& args); |
2120 |
static Handle<Value> DebugPause(const Arguments& args); |
2121 |
static Handle<Value> DebugEnd(const Arguments& args); |
2122 |
|
2123 |
Handle<Object> SetupProcessObject(int argc, char *argv[]) { |
2124 |
HandleScope scope; |
2125 |
|
2126 |
int i, j;
|
2127 |
|
2128 |
Local<FunctionTemplate> process_template = FunctionTemplate::New(); |
2129 |
|
2130 |
process = Persistent<Object>::New(process_template->GetFunction()->NewInstance()); |
2131 |
|
2132 |
|
2133 |
process->SetAccessor(String::New("title"),
|
2134 |
ProcessTitleGetter, |
2135 |
ProcessTitleSetter); |
2136 |
|
2137 |
// process.version
|
2138 |
process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
|
2139 |
|
2140 |
#ifdef NODE_PREFIX
|
2141 |
// process.installPrefix
|
2142 |
process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
|
2143 |
#endif
|
2144 |
|
2145 |
// process.moduleLoadList
|
2146 |
module_load_list = Persistent<Array>::New(Array::New()); |
2147 |
process->Set(String::NewSymbol("moduleLoadList"), module_load_list);
|
2148 |
|
2149 |
// process.versions
|
2150 |
Local<Object> versions = Object::New(); |
2151 |
process->Set(String::NewSymbol("versions"), versions);
|
2152 |
versions->Set(String::NewSymbol("http_parser"), String::New(
|
2153 |
NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) "."
|
2154 |
NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR))); |
2155 |
// +1 to get rid of the leading 'v'
|
2156 |
versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1)); |
2157 |
versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));
|
2158 |
versions->Set(String::NewSymbol("ares"), String::New(ARES_VERSION_STR));
|
2159 |
versions->Set(String::NewSymbol("uv"), String::New(
|
2160 |
NODE_STRINGIFY(UV_VERSION_MAJOR) "."
|
2161 |
NODE_STRINGIFY(UV_VERSION_MINOR))); |
2162 |
versions->Set(String::NewSymbol("zlib"), String::New(ZLIB_VERSION));
|
2163 |
#if HAVE_OPENSSL
|
2164 |
// Stupid code to slice out the version string.
|
2165 |
int c, l = strlen(OPENSSL_VERSION_TEXT);
|
2166 |
for (i = j = 0; i < l; i++) { |
2167 |
c = OPENSSL_VERSION_TEXT[i]; |
2168 |
if ('0' <= c && c <= '9') { |
2169 |
for (j = i + 1; j < l; j++) { |
2170 |
c = OPENSSL_VERSION_TEXT[j]; |
2171 |
if (c == ' ') break; |
2172 |
} |
2173 |
break;
|
2174 |
} |
2175 |
} |
2176 |
versions->Set(String::NewSymbol("openssl"),
|
2177 |
String::New(OPENSSL_VERSION_TEXT + i, j - i)); |
2178 |
#endif
|
2179 |
|
2180 |
|
2181 |
|
2182 |
// process.arch
|
2183 |
process->Set(String::NewSymbol("arch"), String::New(ARCH));
|
2184 |
|
2185 |
// process.platform
|
2186 |
process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
|
2187 |
|
2188 |
// process.argv
|
2189 |
Local<Array> arguments = Array::New(argc - option_end_index + 1);
|
2190 |
arguments->Set(Integer::New(0), String::New(argv[0])); |
2191 |
for (j = 1, i = option_end_index; i < argc; j++, i++) { |
2192 |
Local<String> arg = String::New(argv[i]); |
2193 |
arguments->Set(Integer::New(j), arg); |
2194 |
} |
2195 |
// assign it
|
2196 |
process->Set(String::NewSymbol("argv"), arguments);
|
2197 |
|
2198 |
// process.execArgv
|
2199 |
Local<Array> execArgv = Array::New(option_end_index - 1);
|
2200 |
for (j = 1, i = 0; j < option_end_index; j++, i++) { |
2201 |
execArgv->Set(Integer::New(i), String::New(argv[j])); |
2202 |
} |
2203 |
// assign it
|
2204 |
process->Set(String::NewSymbol("execArgv"), execArgv);
|
2205 |
|
2206 |
|
2207 |
// create process.env
|
2208 |
Local<ObjectTemplate> envTemplate = ObjectTemplate::New(); |
2209 |
envTemplate->SetNamedPropertyHandler(EnvGetter, |
2210 |
EnvSetter, |
2211 |
EnvQuery, |
2212 |
EnvDeleter, |
2213 |
EnvEnumerator, |
2214 |
Undefined()); |
2215 |
Local<Object> env = envTemplate->NewInstance(); |
2216 |
process->Set(String::NewSymbol("env"), env);
|
2217 |
|
2218 |
process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
|
2219 |
process->Set(String::NewSymbol("features"), GetFeatures());
|
2220 |
|
2221 |
// -e, --eval
|
2222 |
if (eval_string) {
|
2223 |
process->Set(String::NewSymbol("_eval"), String::New(eval_string));
|
2224 |
} |
2225 |
|
2226 |
// -p, --print
|
2227 |
if (print_eval) {
|
2228 |
process->Set(String::NewSymbol("_print_eval"), True());
|
2229 |
} |
2230 |
|
2231 |
// -i, --interactive
|
2232 |
if (force_repl) {
|
2233 |
process->Set(String::NewSymbol("_forceRepl"), True());
|
2234 |
} |
2235 |
|
2236 |
size_t size = 2*PATH_MAX;
|
2237 |
char* execPath = new char[size]; |
2238 |
if (uv_exepath(execPath, &size) != 0) { |
2239 |
// as a last ditch effort, fallback on argv[0] ?
|
2240 |
process->Set(String::NewSymbol("execPath"), String::New(argv[0])); |
2241 |
} else {
|
2242 |
process->Set(String::NewSymbol("execPath"), String::New(execPath, size));
|
2243 |
} |
2244 |
delete [] execPath;
|
2245 |
|
2246 |
process->SetAccessor(String::New("debugPort"),
|
2247 |
DebugPortGetter, |
2248 |
DebugPortSetter); |
2249 |
|
2250 |
|
2251 |
// define various internal methods
|
2252 |
NODE_SET_METHOD(process, "_getActiveRequests", GetActiveRequests);
|
2253 |
NODE_SET_METHOD(process, "_getActiveHandles", GetActiveHandles);
|
2254 |
NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
|
2255 |
NODE_SET_METHOD(process, "reallyExit", Exit);
|
2256 |
NODE_SET_METHOD(process, "abort", Abort);
|
2257 |
NODE_SET_METHOD(process, "chdir", Chdir);
|
2258 |
NODE_SET_METHOD(process, "cwd", Cwd);
|
2259 |
|
2260 |
NODE_SET_METHOD(process, "umask", Umask);
|
2261 |
|
2262 |
#ifdef __POSIX__
|
2263 |
NODE_SET_METHOD(process, "getuid", GetUid);
|
2264 |
NODE_SET_METHOD(process, "setuid", SetUid);
|
2265 |
|
2266 |
NODE_SET_METHOD(process, "setgid", SetGid);
|
2267 |
NODE_SET_METHOD(process, "getgid", GetGid);
|
2268 |
#endif // __POSIX__ |
2269 |
|
2270 |
NODE_SET_METHOD(process, "_kill", Kill);
|
2271 |
|
2272 |
NODE_SET_METHOD(process, "_debugProcess", DebugProcess);
|
2273 |
NODE_SET_METHOD(process, "_debugPause", DebugPause);
|
2274 |
NODE_SET_METHOD(process, "_debugEnd", DebugEnd);
|
2275 |
|
2276 |
NODE_SET_METHOD(process, "hrtime", Hrtime);
|
2277 |
|
2278 |
NODE_SET_METHOD(process, "dlopen", DLOpen);
|
2279 |
|
2280 |
NODE_SET_METHOD(process, "uptime", Uptime);
|
2281 |
NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
|
2282 |
NODE_SET_METHOD(process, "uvCounters", UVCounters);
|
2283 |
|
2284 |
NODE_SET_METHOD(process, "binding", Binding);
|
2285 |
|
2286 |
return process;
|
2287 |
} |
2288 |
|
2289 |
|
2290 |
static void AtExit() { |
2291 |
uv_tty_reset_mode(); |
2292 |
} |
2293 |
|
2294 |
|
2295 |
static void SignalExit(int signal) { |
2296 |
uv_tty_reset_mode(); |
2297 |
_exit(1);
|
2298 |
} |
2299 |
|
2300 |
|
2301 |
void Load(Handle<Object> process_l) {
|
2302 |
// Compile, execute the src/node.js file. (Which was included as static C
|
2303 |
// string in node_natives.h. 'natve_node' is the string containing that
|
2304 |
// source code.)
|
2305 |
|
2306 |
// The node.js file returns a function 'f'
|
2307 |
atexit(AtExit); |
2308 |
|
2309 |
TryCatch try_catch; |
2310 |
|
2311 |
Local<Value> f_value = ExecuteString(MainSource(), |
2312 |
IMMUTABLE_STRING("node.js"));
|
2313 |
if (try_catch.HasCaught()) {
|
2314 |
ReportException(try_catch, true);
|
2315 |
exit(10);
|
2316 |
} |
2317 |
assert(f_value->IsFunction()); |
2318 |
Local<Function> f = Local<Function>::Cast(f_value); |
2319 |
|
2320 |
// Now we call 'f' with the 'process' variable that we've built up with
|
2321 |
// all our bindings. Inside node.js we'll take care of assigning things to
|
2322 |
// their places.
|
2323 |
|
2324 |
// We start the process this way in order to be more modular. Developers
|
2325 |
// who do not like how 'src/node.js' setups the module system but do like
|
2326 |
// Node's I/O bindings may want to replace 'f' with their own function.
|
2327 |
|
2328 |
// Add a reference to the global object
|
2329 |
Local<Object> global = v8::Context::GetCurrent()->Global(); |
2330 |
Local<Value> args[1] = { Local<Value>::New(process_l) };
|
2331 |
|
2332 |
#if defined HAVE_DTRACE || defined HAVE_ETW
|
2333 |
InitDTrace(global); |
2334 |
#endif
|
2335 |
|
2336 |
f->Call(global, 1, args);
|
2337 |
|
2338 |
if (try_catch.HasCaught()) {
|
2339 |
ReportException(try_catch, true);
|
2340 |
exit(11);
|
2341 |
} |
2342 |
} |
2343 |
|
2344 |
static void PrintHelp(); |
2345 |
|
2346 |
static void ParseDebugOpt(const char* arg) { |
2347 |
const char *p = 0; |
2348 |
|
2349 |
use_debug_agent = true;
|
2350 |
if (!strcmp (arg, "--debug-brk")) { |
2351 |
debug_wait_connect = true;
|
2352 |
return;
|
2353 |
} else if (!strcmp(arg, "--debug")) { |
2354 |
return;
|
2355 |
} else if (strstr(arg, "--debug-brk=") == arg) { |
2356 |
debug_wait_connect = true;
|
2357 |
p = 1 + strchr(arg, '='); |
2358 |
debug_port = atoi(p); |
2359 |
} else if (strstr(arg, "--debug=") == arg) { |
2360 |
p = 1 + strchr(arg, '='); |
2361 |
debug_port = atoi(p); |
2362 |
} |
2363 |
if (p && debug_port > 1024 && debug_port < 65536) |
2364 |
return;
|
2365 |
|
2366 |
fprintf(stderr, "Bad debug option.\n");
|
2367 |
if (p) fprintf(stderr, "Debug port must be in range 1025 to 65535.\n"); |
2368 |
|
2369 |
PrintHelp(); |
2370 |
exit(1);
|
2371 |
} |
2372 |
|
2373 |
static void PrintHelp() { |
2374 |
printf("Usage: node [options] [ -e script | script.js ] [arguments] \n"
|
2375 |
" node debug script.js [arguments] \n"
|
2376 |
"\n"
|
2377 |
"Options:\n"
|
2378 |
" -v, --version print node's version\n"
|
2379 |
" -e, --eval script evaluate script\n"
|
2380 |
" -p, --print print result of --eval\n"
|
2381 |
" -i, --interactive always enter the REPL even if stdin\n"
|
2382 |
" does not appear to be a terminal\n"
|
2383 |
" --v8-options print v8 command line options\n"
|
2384 |
" --vars print various compiled-in variables\n"
|
2385 |
" --max-stack-size=val set max v8 stack size (bytes)\n"
|
2386 |
"\n"
|
2387 |
"Environment variables:\n"
|
2388 |
#ifdef _WIN32
|
2389 |
"NODE_PATH ';'-separated list of directories\n"
|
2390 |
#else
|
2391 |
"NODE_PATH ':'-separated list of directories\n"
|
2392 |
#endif
|
2393 |
" prefixed to the module search path.\n"
|
2394 |
"NODE_MODULE_CONTEXTS Set to 1 to load modules in their own\n"
|
2395 |
" global contexts.\n"
|
2396 |
"NODE_DISABLE_COLORS Set to 1 to disable colors in the REPL\n"
|
2397 |
"\n"
|
2398 |
"Documentation can be found at http://nodejs.org/\n");
|
2399 |
} |
2400 |
|
2401 |
// Parse node command line arguments.
|
2402 |
static void ParseArgs(int argc, char **argv) { |
2403 |
int i;
|
2404 |
|
2405 |
// TODO use parse opts
|
2406 |
for (i = 1; i < argc; i++) { |
2407 |
const char *arg = argv[i]; |
2408 |
if (strstr(arg, "--debug") == arg) { |
2409 |
ParseDebugOpt(arg); |
2410 |
argv[i] = const_cast<char*>(""); |
2411 |
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) { |
2412 |
printf("%s\n", NODE_VERSION);
|
2413 |
exit(0);
|
2414 |
} else if (strcmp(arg, "--vars") == 0) { |
2415 |
#ifdef NODE_PREFIX
|
2416 |
printf("NODE_PREFIX: %s\n", NODE_PREFIX);
|
2417 |
#endif
|
2418 |
#ifdef NODE_CFLAGS
|
2419 |
printf("NODE_CFLAGS: %s\n", NODE_CFLAGS);
|
2420 |
#endif
|
2421 |
exit(0);
|
2422 |
} else if (strstr(arg, "--max-stack-size=") == arg) { |
2423 |
const char *p = 0; |
2424 |
p = 1 + strchr(arg, '='); |
2425 |
max_stack_size = atoi(p); |
2426 |
argv[i] = const_cast<char*>(""); |
2427 |
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) { |
2428 |
PrintHelp(); |
2429 |
exit(0);
|
2430 |
} else if (strcmp(arg, "--eval") == 0 || strcmp(arg, "-e") == 0 || |
2431 |
strcmp(arg, "-pe") == 0) { |
2432 |
if (argc <= i + 1) { |
2433 |
fprintf(stderr, "Error: --eval requires an argument\n");
|
2434 |
exit(1);
|
2435 |
} |
2436 |
if (arg[1] == 'p') { |
2437 |
print_eval = true;
|
2438 |
} |
2439 |
argv[i] = const_cast<char*>(""); |
2440 |
eval_string = argv[++i]; |
2441 |
} else if (strcmp(arg, "--print") == 0 || strcmp(arg, "-p") == 0) { |
2442 |
print_eval = true;
|
2443 |
argv[i] = const_cast<char*>(""); |
2444 |
} else if (strcmp(arg, "--interactive") == 0 || strcmp(arg, "-i") == 0) { |
2445 |
force_repl = true;
|
2446 |
argv[i] = const_cast<char*>(""); |
2447 |
} else if (strcmp(arg, "--v8-options") == 0) { |
2448 |
argv[i] = const_cast<char*>("--help"); |
2449 |
} else if (argv[i][0] != '-') { |
2450 |
break;
|
2451 |
} |
2452 |
} |
2453 |
|
2454 |
option_end_index = i; |
2455 |
} |
2456 |
|
2457 |
|
2458 |
static Isolate* node_isolate = NULL; |
2459 |
static volatile bool debugger_running = false; |
2460 |
|
2461 |
static void EnableDebug(bool wait_connect) { |
2462 |
// If we're called from another thread, make sure to enter the right
|
2463 |
// v8 isolate.
|
2464 |
node_isolate->Enter(); |
2465 |
|
2466 |
// Start the debug thread and it's associated TCP server on port 5858.
|
2467 |
bool r = v8::Debug::EnableAgent("node " NODE_VERSION, |
2468 |
debug_port, |
2469 |
wait_connect); |
2470 |
|
2471 |
// Crappy check that everything went well. FIXME
|
2472 |
assert(r); |
2473 |
|
2474 |
// Print out some information.
|
2475 |
fprintf(stderr, "debugger listening on port %d\n", debug_port);
|
2476 |
fflush(stderr); |
2477 |
|
2478 |
debugger_running = true;
|
2479 |
|
2480 |
node_isolate->Exit(); |
2481 |
} |
2482 |
|
2483 |
|
2484 |
#ifdef __POSIX__
|
2485 |
static void EnableDebugSignalHandler(int signal) { |
2486 |
// Break once process will return execution to v8
|
2487 |
v8::Debug::DebugBreak(node_isolate); |
2488 |
|
2489 |
if (!debugger_running) {
|
2490 |
fprintf(stderr, "Hit SIGUSR1 - starting debugger agent.\n");
|
2491 |
EnableDebug(false);
|
2492 |
} |
2493 |
} |
2494 |
|
2495 |
|
2496 |
static void RegisterSignalHandler(int signal, void (*handler)(int)) { |
2497 |
struct sigaction sa;
|
2498 |
|
2499 |
memset(&sa, 0, sizeof(sa)); |
2500 |
sa.sa_handler = handler; |
2501 |
sigfillset(&sa.sa_mask); |
2502 |
sigaction(signal, &sa, NULL);
|
2503 |
} |
2504 |
|
2505 |
|
2506 |
Handle<Value> DebugProcess(const Arguments& args) {
|
2507 |
HandleScope scope; |
2508 |
|
2509 |
if (args.Length() != 1) { |
2510 |
return ThrowException(Exception::Error(
|
2511 |
String::New("Invalid number of arguments.")));
|
2512 |
} |
2513 |
|
2514 |
pid_t pid; |
2515 |
int r;
|
2516 |
|
2517 |
pid = args[0]->IntegerValue();
|
2518 |
r = kill(pid, SIGUSR1); |
2519 |
if (r != 0) { |
2520 |
return ThrowException(ErrnoException(errno, "kill")); |
2521 |
} |
2522 |
|
2523 |
return Undefined();
|
2524 |
} |
2525 |
#endif // __POSIX__ |
2526 |
|
2527 |
|
2528 |
#ifdef _WIN32
|
2529 |
DWORD WINAPI EnableDebugThreadProc(void* arg) {
|
2530 |
// Break once process will return execution to v8
|
2531 |
if (!debugger_running) {
|
2532 |
for (int i = 0; i < 1; i++) { |
2533 |
fprintf(stderr, "Starting debugger agent.\r\n");
|
2534 |
fflush(stderr); |
2535 |
EnableDebug(false);
|
2536 |
} |
2537 |
} |
2538 |
|
2539 |
v8::Debug::DebugBreak(); |
2540 |
|
2541 |
return 0; |
2542 |
} |
2543 |
|
2544 |
|
2545 |
static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf, |
2546 |
size_t buf_len) { |
2547 |
return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid); |
2548 |
} |
2549 |
|
2550 |
|
2551 |
static int RegisterDebugSignalHandler() { |
2552 |
wchar_t mapping_name[32]; |
2553 |
HANDLE mapping_handle; |
2554 |
DWORD pid; |
2555 |
LPTHREAD_START_ROUTINE* handler; |
2556 |
|
2557 |
pid = GetCurrentProcessId(); |
2558 |
|
2559 |
if (GetDebugSignalHandlerMappingName(pid,
|
2560 |
mapping_name, |
2561 |
ARRAY_SIZE(mapping_name)) < 0) {
|
2562 |
return -1; |
2563 |
} |
2564 |
|
2565 |
mapping_handle = CreateFileMappingW(INVALID_HANDLE_VALUE, |
2566 |
NULL,
|
2567 |
PAGE_READWRITE, |
2568 |
0,
|
2569 |
sizeof *handler,
|
2570 |
mapping_name); |
2571 |
if (mapping_handle == NULL) { |
2572 |
return -1; |
2573 |
} |
2574 |
|
2575 |
handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
|
2576 |
MapViewOfFile(mapping_handle, |
2577 |
FILE_MAP_ALL_ACCESS, |
2578 |
0,
|
2579 |
0,
|
2580 |
sizeof *handler));
|
2581 |
if (handler == NULL) { |
2582 |
CloseHandle(mapping_handle); |
2583 |
return -1; |
2584 |
} |
2585 |
|
2586 |
*handler = EnableDebugThreadProc; |
2587 |
|
2588 |
UnmapViewOfFile((void*) handler);
|
2589 |
|
2590 |
return 0; |
2591 |
} |
2592 |
|
2593 |
|
2594 |
static Handle<Value> DebugProcess(const Arguments& args) { |
2595 |
HandleScope scope; |
2596 |
Handle<Value> rv = Undefined(); |
2597 |
DWORD pid; |
2598 |
HANDLE process = NULL;
|
2599 |
HANDLE thread = NULL;
|
2600 |
HANDLE mapping = NULL;
|
2601 |
wchar_t mapping_name[32]; |
2602 |
LPTHREAD_START_ROUTINE* handler = NULL;
|
2603 |
|
2604 |
if (args.Length() != 1) { |
2605 |
rv = ThrowException(Exception::Error(String::New("Invalid number of arguments.")));
|
2606 |
goto out;
|
2607 |
} |
2608 |
|
2609 |
pid = (DWORD) args[0]->IntegerValue();
|
2610 |
|
2611 |
process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | |
2612 |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | |
2613 |
PROCESS_VM_READ, |
2614 |
FALSE, |
2615 |
pid); |
2616 |
if (process == NULL) { |
2617 |
rv = ThrowException(WinapiErrnoException(GetLastError(), "OpenProcess"));
|
2618 |
goto out;
|
2619 |
} |
2620 |
|
2621 |
if (GetDebugSignalHandlerMappingName(pid,
|
2622 |
mapping_name, |
2623 |
ARRAY_SIZE(mapping_name)) < 0) {
|
2624 |
rv = ThrowException(ErrnoException(errno, "sprintf"));
|
2625 |
goto out;
|
2626 |
} |
2627 |
|
2628 |
mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name); |
2629 |
if (mapping == NULL) { |
2630 |
rv = ThrowException(WinapiErrnoException(GetLastError(), |
2631 |
"OpenFileMappingW"));
|
2632 |
goto out;
|
2633 |
} |
2634 |
|
2635 |
handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
|
2636 |
MapViewOfFile(mapping, |
2637 |
FILE_MAP_READ, |
2638 |
0,
|
2639 |
0,
|
2640 |
sizeof *handler));
|
2641 |
if (handler == NULL || *handler == NULL) { |
2642 |
rv = ThrowException(WinapiErrnoException(GetLastError(), "MapViewOfFile"));
|
2643 |
goto out;
|
2644 |
} |
2645 |
|
2646 |
thread = CreateRemoteThread(process, |
2647 |
NULL,
|
2648 |
0,
|
2649 |
*handler, |
2650 |
NULL,
|
2651 |
0,
|
2652 |
NULL);
|
2653 |
if (thread == NULL) { |
2654 |
rv = ThrowException(WinapiErrnoException(GetLastError(), |
2655 |
"CreateRemoteThread"));
|
2656 |
goto out;
|
2657 |
} |
2658 |
|
2659 |
// Wait for the thread to terminate
|
2660 |
if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
|
2661 |
rv = ThrowException(WinapiErrnoException(GetLastError(), |
2662 |
"WaitForSingleObject"));
|
2663 |
goto out;
|
2664 |
} |
2665 |
|
2666 |
out:
|
2667 |
if (process != NULL) { |
2668 |
CloseHandle(process); |
2669 |
} |
2670 |
if (thread != NULL) { |
2671 |
CloseHandle(thread); |
2672 |
} |
2673 |
if (handler != NULL) { |
2674 |
UnmapViewOfFile(handler); |
2675 |
} |
2676 |
if (mapping != NULL) { |
2677 |
CloseHandle(mapping); |
2678 |
} |
2679 |
|
2680 |
return Undefined();
|
2681 |
} |
2682 |
#endif // _WIN32 |
2683 |
|
2684 |
|
2685 |
static Handle<Value> DebugPause(const Arguments& args) { |
2686 |
v8::Debug::DebugBreak(node_isolate); |
2687 |
return Undefined();
|
2688 |
} |
2689 |
|
2690 |
|
2691 |
static Handle<Value> DebugEnd(const Arguments& args) { |
2692 |
if (debugger_running) {
|
2693 |
v8::Debug::DisableAgent(); |
2694 |
debugger_running = false;
|
2695 |
} |
2696 |
|
2697 |
return Undefined();
|
2698 |
} |
2699 |
|
2700 |
|
2701 |
char** Init(int argc, char *argv[]) { |
2702 |
// Initialize prog_start_time to get relative uptime.
|
2703 |
uv_uptime(&prog_start_time); |
2704 |
|
2705 |
// Parse a few arguments which are specific to Node.
|
2706 |
node::ParseArgs(argc, argv); |
2707 |
// Parse the rest of the args (up to the 'option_end_index' (where '--' was
|
2708 |
// in the command line))
|
2709 |
int v8argc = option_end_index;
|
2710 |
char **v8argv = argv;
|
2711 |
|
2712 |
if (debug_wait_connect) {
|
2713 |
// v8argv is a copy of argv up to the script file argument +2 if --debug-brk
|
2714 |
// to expose the v8 debugger js object so that node.js can set
|
2715 |
// a breakpoint on the first line of the startup script
|
2716 |
v8argc += 2;
|
2717 |
v8argv = new char*[v8argc]; |
2718 |
memcpy(v8argv, argv, sizeof(argv) * option_end_index);
|
2719 |
v8argv[option_end_index] = const_cast<char*>("--expose_debug_as"); |
2720 |
v8argv[option_end_index + 1] = const_cast<char*>("v8debug"); |
2721 |
} |
2722 |
|
2723 |
// For the normal stack which moves from high to low addresses when frames
|
2724 |
// are pushed, we can compute the limit as stack_size bytes below the
|
2725 |
// the address of a stack variable (e.g. &stack_var) as an approximation
|
2726 |
// of the start of the stack (we're assuming that we haven't pushed a lot
|
2727 |
// of frames yet).
|
2728 |
if (max_stack_size != 0) { |
2729 |
uint32_t stack_var; |
2730 |
ResourceConstraints constraints; |
2731 |
|
2732 |
uint32_t *stack_limit = &stack_var - (max_stack_size / sizeof(uint32_t));
|
2733 |
constraints.set_stack_limit(stack_limit); |
2734 |
SetResourceConstraints(&constraints); // Must be done before V8::Initialize
|
2735 |
} |
2736 |
V8::SetFlagsFromCommandLine(&v8argc, v8argv, false);
|
2737 |
|
2738 |
#ifdef __POSIX__
|
2739 |
// Ignore SIGPIPE
|
2740 |
RegisterSignalHandler(SIGPIPE, SIG_IGN); |
2741 |
RegisterSignalHandler(SIGINT, SignalExit); |
2742 |
RegisterSignalHandler(SIGTERM, SignalExit); |
2743 |
#endif // __POSIX__ |
2744 |
|
2745 |
uv_prepare_init(uv_default_loop(), &prepare_tick_watcher); |
2746 |
uv_prepare_start(&prepare_tick_watcher, PrepareTick); |
2747 |
uv_unref(reinterpret_cast<uv_handle_t*>(&prepare_tick_watcher));
|
2748 |
|
2749 |
uv_check_init(uv_default_loop(), &check_tick_watcher); |
2750 |
uv_check_start(&check_tick_watcher, node::CheckTick); |
2751 |
uv_unref(reinterpret_cast<uv_handle_t*>(&check_tick_watcher));
|
2752 |
|
2753 |
uv_idle_init(uv_default_loop(), &tick_spinner); |
2754 |
|
2755 |
uv_check_init(uv_default_loop(), &gc_check); |
2756 |
uv_check_start(&gc_check, node::Check); |
2757 |
uv_unref(reinterpret_cast<uv_handle_t*>(&gc_check));
|
2758 |
|
2759 |
uv_idle_init(uv_default_loop(), &gc_idle); |
2760 |
uv_unref(reinterpret_cast<uv_handle_t*>(&gc_idle));
|
2761 |
|
2762 |
uv_timer_init(uv_default_loop(), &gc_timer); |
2763 |
uv_unref(reinterpret_cast<uv_handle_t*>(&gc_timer));
|
2764 |
|
2765 |
V8::SetFatalErrorHandler(node::OnFatalError); |
2766 |
|
2767 |
// Fetch a reference to the main isolate, so we have a reference to it
|
2768 |
// even when we need it to access it from another (debugger) thread.
|
2769 |
node_isolate = Isolate::GetCurrent(); |
2770 |
|
2771 |
// If the --debug flag was specified then initialize the debug thread.
|
2772 |
if (use_debug_agent) {
|
2773 |
EnableDebug(debug_wait_connect); |
2774 |
} else {
|
2775 |
#ifdef _WIN32
|
2776 |
RegisterDebugSignalHandler(); |
2777 |
#else // Posix |
2778 |
RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler); |
2779 |
#endif // __POSIX__ |
2780 |
} |
2781 |
|
2782 |
return argv;
|
2783 |
} |
2784 |
|
2785 |
|
2786 |
struct AtExitCallback {
|
2787 |
AtExitCallback* next_; |
2788 |
void (*cb_)(void* arg); |
2789 |
void* arg_;
|
2790 |
}; |
2791 |
|
2792 |
static AtExitCallback* at_exit_functions_;
|
2793 |
|
2794 |
|
2795 |
void RunAtExit() {
|
2796 |
AtExitCallback* p = at_exit_functions_; |
2797 |
at_exit_functions_ = NULL;
|
2798 |
|
2799 |
while (p) {
|
2800 |
AtExitCallback* q = p->next_; |
2801 |
p->cb_(p->arg_); |
2802 |
delete p;
|
2803 |
p = q; |
2804 |
} |
2805 |
} |
2806 |
|
2807 |
|
2808 |
void AtExit(void (*cb)(void* arg), void* arg) { |
2809 |
AtExitCallback* p = new AtExitCallback;
|
2810 |
p->cb_ = cb; |
2811 |
p->arg_ = arg; |
2812 |
p->next_ = at_exit_functions_; |
2813 |
at_exit_functions_ = p; |
2814 |
} |
2815 |
|
2816 |
|
2817 |
void EmitExit(v8::Handle<v8::Object> process_l) {
|
2818 |
// process.emit('exit')
|
2819 |
process_l->Set(String::NewSymbol("_exiting"), True());
|
2820 |
Local<Value> emit_v = process_l->Get(String::New("emit"));
|
2821 |
assert(emit_v->IsFunction()); |
2822 |
Local<Function> emit = Local<Function>::Cast(emit_v); |
2823 |
Local<Value> args[] = { String::New("exit"), Integer::New(0) }; |
2824 |
TryCatch try_catch; |
2825 |
emit->Call(process_l, 2, args);
|
2826 |
if (try_catch.HasCaught()) {
|
2827 |
FatalException(try_catch); |
2828 |
} |
2829 |
} |
2830 |
|
2831 |
static char **copy_argv(int argc, char **argv) { |
2832 |
size_t strlen_sum; |
2833 |
char **argv_copy;
|
2834 |
char *argv_data;
|
2835 |
size_t len; |
2836 |
int i;
|
2837 |
|
2838 |
strlen_sum = 0;
|
2839 |
for(i = 0; i < argc; i++) { |
2840 |
strlen_sum += strlen(argv[i]) + 1;
|
2841 |
} |
2842 |
|
2843 |
argv_copy = (char **) malloc(sizeof(char *) * (argc + 1) + strlen_sum); |
2844 |
if (!argv_copy) {
|
2845 |
return NULL; |
2846 |
} |
2847 |
|
2848 |
argv_data = (char *) argv_copy + sizeof(char *) * (argc + 1); |
2849 |
|
2850 |
for(i = 0; i < argc; i++) { |
2851 |
argv_copy[i] = argv_data; |
2852 |
len = strlen(argv[i]) + 1;
|
2853 |
memcpy(argv_data, argv[i], len); |
2854 |
argv_data += len; |
2855 |
} |
2856 |
|
2857 |
argv_copy[argc] = NULL;
|
2858 |
|
2859 |
return argv_copy;
|
2860 |
} |
2861 |
|
2862 |
int Start(int argc, char *argv[]) { |
2863 |
// Hack aroung with the argv pointer. Used for process.title = "blah".
|
2864 |
argv = uv_setup_args(argc, argv); |
2865 |
|
2866 |
// Logic to duplicate argv as Init() modifies arguments
|
2867 |
// that are passed into it.
|
2868 |
char **argv_copy = copy_argv(argc, argv);
|
2869 |
|
2870 |
// This needs to run *before* V8::Initialize()
|
2871 |
// Use copy here as to not modify the original argv:
|
2872 |
Init(argc, argv_copy); |
2873 |
|
2874 |
V8::Initialize(); |
2875 |
{ |
2876 |
Locker locker; |
2877 |
HandleScope handle_scope; |
2878 |
|
2879 |
// Create the one and only Context.
|
2880 |
Persistent<Context> context = Context::New(); |
2881 |
Context::Scope context_scope(context); |
2882 |
|
2883 |
process_symbol = NODE_PSYMBOL("process");
|
2884 |
domain_symbol = NODE_PSYMBOL("domain");
|
2885 |
|
2886 |
// Use original argv, as we're just copying values out of it.
|
2887 |
Handle<Object> process_l = SetupProcessObject(argc, argv); |
2888 |
v8_typed_array::AttachBindings(context->Global()); |
2889 |
|
2890 |
// Create all the objects, load modules, do everything.
|
2891 |
// so your next reading stop should be node::Load()!
|
2892 |
Load(process_l); |
2893 |
|
2894 |
// All our arguments are loaded. We've evaluated all of the scripts. We
|
2895 |
// might even have created TCP servers. Now we enter the main eventloop. If
|
2896 |
// there are no watchers on the loop (except for the ones that were
|
2897 |
// uv_unref'd) then this function exits. As long as there are active
|
2898 |
// watchers, it blocks.
|
2899 |
uv_run(uv_default_loop()); |
2900 |
|
2901 |
#ifdef HAVE_ETW
|
2902 |
shutdown_etw(); |
2903 |
#endif
|
2904 |
|
2905 |
EmitExit(process_l); |
2906 |
RunAtExit(); |
2907 |
|
2908 |
#ifndef NDEBUG
|
2909 |
context.Dispose(); |
2910 |
#endif
|
2911 |
} |
2912 |
|
2913 |
#ifndef NDEBUG
|
2914 |
// Clean up. Not strictly necessary.
|
2915 |
V8::Dispose(); |
2916 |
#endif // NDEBUG |
2917 |
|
2918 |
// Clean up the copy:
|
2919 |
free(argv_copy); |
2920 |
|
2921 |
return 0; |
2922 |
} |
2923 |
|
2924 |
|
2925 |
} // namespace node
|