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 @ f230a1cf
History | View | Annotate | Download (86.6 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 "node_buffer.h" |
24 |
#include "node_constants.h" |
25 |
#include "node_file.h" |
26 |
#include "node_http_parser.h" |
27 |
#include "node_javascript.h" |
28 |
#include "node_version.h" |
29 |
|
30 |
#if defined HAVE_PERFCTR
|
31 |
#include "node_counters.h" |
32 |
#endif
|
33 |
|
34 |
#if HAVE_OPENSSL
|
35 |
#include "node_crypto.h" |
36 |
#endif
|
37 |
|
38 |
#if defined HAVE_DTRACE || defined HAVE_ETW
|
39 |
#include "node_dtrace.h" |
40 |
#endif
|
41 |
|
42 |
#include "ares.h" |
43 |
#include "async-wrap.h" |
44 |
#include "async-wrap-inl.h" |
45 |
#include "env.h" |
46 |
#include "env-inl.h" |
47 |
#include "handle_wrap.h" |
48 |
#include "req_wrap.h" |
49 |
#include "string_bytes.h" |
50 |
#include "uv.h" |
51 |
#include "v8-debug.h" |
52 |
#include "v8-profiler.h" |
53 |
#include "zlib.h" |
54 |
|
55 |
#include <assert.h> |
56 |
#include <errno.h> |
57 |
#include <limits.h> // PATH_MAX |
58 |
#include <locale.h> |
59 |
#include <signal.h> |
60 |
#include <stdio.h> |
61 |
#include <stdlib.h> |
62 |
#include <string.h> |
63 |
#include <sys/types.h> |
64 |
|
65 |
#if defined(_MSC_VER)
|
66 |
#include <direct.h> |
67 |
#include <io.h> |
68 |
#include <process.h> |
69 |
#define strcasecmp _stricmp
|
70 |
#define getpid _getpid
|
71 |
#define umask _umask
|
72 |
typedef int mode_t; |
73 |
#else
|
74 |
#include <sys/resource.h> // getrlimit, setrlimit |
75 |
#include <unistd.h> // setuid, getuid |
76 |
#endif
|
77 |
|
78 |
#if defined(__POSIX__) && !defined(__ANDROID__)
|
79 |
#include <pwd.h> // getpwnam() |
80 |
#include <grp.h> // getgrnam() |
81 |
#endif
|
82 |
|
83 |
#ifdef __APPLE__
|
84 |
#include <crt_externs.h> |
85 |
#define environ (*_NSGetEnviron())
|
86 |
#elif !defined(_MSC_VER)
|
87 |
extern char **environ; |
88 |
#endif
|
89 |
|
90 |
namespace node {
|
91 |
|
92 |
using v8::Array;
|
93 |
using v8::ArrayBuffer;
|
94 |
using v8::Boolean;
|
95 |
using v8::Context;
|
96 |
using v8::Exception;
|
97 |
using v8::Function;
|
98 |
using v8::FunctionCallbackInfo;
|
99 |
using v8::FunctionTemplate;
|
100 |
using v8::Handle;
|
101 |
using v8::HandleScope;
|
102 |
using v8::HeapStatistics;
|
103 |
using v8::Integer;
|
104 |
using v8::Isolate;
|
105 |
using v8::Local;
|
106 |
using v8::Locker;
|
107 |
using v8::Message;
|
108 |
using v8::Number;
|
109 |
using v8::Object;
|
110 |
using v8::ObjectTemplate;
|
111 |
using v8::PropertyCallbackInfo;
|
112 |
using v8::String;
|
113 |
using v8::ThrowException;
|
114 |
using v8::TryCatch;
|
115 |
using v8::Uint32;
|
116 |
using v8::V8;
|
117 |
using v8::Value;
|
118 |
using v8::kExternalUnsignedIntArray;
|
119 |
|
120 |
// FIXME(bnoordhuis) Make these per-context?
|
121 |
QUEUE handle_wrap_queue = { &handle_wrap_queue, &handle_wrap_queue }; |
122 |
QUEUE req_wrap_queue = { &req_wrap_queue, &req_wrap_queue }; |
123 |
|
124 |
static bool print_eval = false; |
125 |
static bool force_repl = false; |
126 |
static bool trace_deprecation = false; |
127 |
static bool throw_deprecation = false; |
128 |
static const char* eval_string = NULL; |
129 |
static bool use_debug_agent = false; |
130 |
static bool debug_wait_connect = false; |
131 |
static int debug_port = 5858; |
132 |
static bool v8_is_profiling = false; |
133 |
|
134 |
// used by C++ modules as well
|
135 |
bool no_deprecation = false; |
136 |
|
137 |
// process-relative uptime base, initialized at start-up
|
138 |
static double prog_start_time; |
139 |
static bool debugger_running; |
140 |
static uv_async_t dispatch_debug_messages_async;
|
141 |
|
142 |
// Declared in node_internals.h
|
143 |
Isolate* node_isolate = NULL;
|
144 |
|
145 |
|
146 |
class ArrayBufferAllocator : public ArrayBuffer::Allocator { |
147 |
public:
|
148 |
// Impose an upper limit to avoid out of memory errors that bring down
|
149 |
// the process.
|
150 |
static const size_t kMaxLength = 0x3fffffff; |
151 |
static ArrayBufferAllocator the_singleton;
|
152 |
virtual ~ArrayBufferAllocator() {}
|
153 |
virtual void* Allocate(size_t length); |
154 |
virtual void* AllocateUninitialized(size_t length); |
155 |
virtual void Free(void* data, size_t length); |
156 |
private:
|
157 |
ArrayBufferAllocator() {} |
158 |
ArrayBufferAllocator(const ArrayBufferAllocator&);
|
159 |
void operator=(const ArrayBufferAllocator&); |
160 |
}; |
161 |
|
162 |
ArrayBufferAllocator ArrayBufferAllocator::the_singleton; |
163 |
|
164 |
|
165 |
void* ArrayBufferAllocator::Allocate(size_t length) {
|
166 |
if (length > kMaxLength)
|
167 |
return NULL; |
168 |
return new char[length]; |
169 |
} |
170 |
|
171 |
|
172 |
void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
|
173 |
if (length > kMaxLength)
|
174 |
return NULL; |
175 |
return new char[length]; |
176 |
} |
177 |
|
178 |
|
179 |
void ArrayBufferAllocator::Free(void* data, size_t length) { |
180 |
delete[] static_cast<char*>(data); |
181 |
} |
182 |
|
183 |
|
184 |
static void CheckImmediate(uv_check_t* handle, int status) { |
185 |
Environment* env = Environment::from_immediate_check_handle(handle); |
186 |
Context::Scope context_scope(env->context()); |
187 |
MakeCallback(env, env->process_object(), env->immediate_callback_string()); |
188 |
} |
189 |
|
190 |
|
191 |
static void IdleImmediateDummy(uv_idle_t*, int) { |
192 |
// Do nothing. Only for maintaining event loop.
|
193 |
// TODO(bnoordhuis) Maybe make libuv accept NULL idle callbacks.
|
194 |
} |
195 |
|
196 |
|
197 |
static inline const char *errno_string(int errorno) { |
198 |
#define ERRNO_CASE(e) case e: return #e; |
199 |
switch (errorno) {
|
200 |
#ifdef EACCES
|
201 |
ERRNO_CASE(EACCES); |
202 |
#endif
|
203 |
|
204 |
#ifdef EADDRINUSE
|
205 |
ERRNO_CASE(EADDRINUSE); |
206 |
#endif
|
207 |
|
208 |
#ifdef EADDRNOTAVAIL
|
209 |
ERRNO_CASE(EADDRNOTAVAIL); |
210 |
#endif
|
211 |
|
212 |
#ifdef EAFNOSUPPORT
|
213 |
ERRNO_CASE(EAFNOSUPPORT); |
214 |
#endif
|
215 |
|
216 |
#ifdef EAGAIN
|
217 |
ERRNO_CASE(EAGAIN); |
218 |
#endif
|
219 |
|
220 |
#ifdef EWOULDBLOCK
|
221 |
# if EAGAIN != EWOULDBLOCK
|
222 |
ERRNO_CASE(EWOULDBLOCK); |
223 |
# endif
|
224 |
#endif
|
225 |
|
226 |
#ifdef EALREADY
|
227 |
ERRNO_CASE(EALREADY); |
228 |
#endif
|
229 |
|
230 |
#ifdef EBADF
|
231 |
ERRNO_CASE(EBADF); |
232 |
#endif
|
233 |
|
234 |
#ifdef EBADMSG
|
235 |
ERRNO_CASE(EBADMSG); |
236 |
#endif
|
237 |
|
238 |
#ifdef EBUSY
|
239 |
ERRNO_CASE(EBUSY); |
240 |
#endif
|
241 |
|
242 |
#ifdef ECANCELED
|
243 |
ERRNO_CASE(ECANCELED); |
244 |
#endif
|
245 |
|
246 |
#ifdef ECHILD
|
247 |
ERRNO_CASE(ECHILD); |
248 |
#endif
|
249 |
|
250 |
#ifdef ECONNABORTED
|
251 |
ERRNO_CASE(ECONNABORTED); |
252 |
#endif
|
253 |
|
254 |
#ifdef ECONNREFUSED
|
255 |
ERRNO_CASE(ECONNREFUSED); |
256 |
#endif
|
257 |
|
258 |
#ifdef ECONNRESET
|
259 |
ERRNO_CASE(ECONNRESET); |
260 |
#endif
|
261 |
|
262 |
#ifdef EDEADLK
|
263 |
ERRNO_CASE(EDEADLK); |
264 |
#endif
|
265 |
|
266 |
#ifdef EDESTADDRREQ
|
267 |
ERRNO_CASE(EDESTADDRREQ); |
268 |
#endif
|
269 |
|
270 |
#ifdef EDOM
|
271 |
ERRNO_CASE(EDOM); |
272 |
#endif
|
273 |
|
274 |
#ifdef EDQUOT
|
275 |
ERRNO_CASE(EDQUOT); |
276 |
#endif
|
277 |
|
278 |
#ifdef EEXIST
|
279 |
ERRNO_CASE(EEXIST); |
280 |
#endif
|
281 |
|
282 |
#ifdef EFAULT
|
283 |
ERRNO_CASE(EFAULT); |
284 |
#endif
|
285 |
|
286 |
#ifdef EFBIG
|
287 |
ERRNO_CASE(EFBIG); |
288 |
#endif
|
289 |
|
290 |
#ifdef EHOSTUNREACH
|
291 |
ERRNO_CASE(EHOSTUNREACH); |
292 |
#endif
|
293 |
|
294 |
#ifdef EIDRM
|
295 |
ERRNO_CASE(EIDRM); |
296 |
#endif
|
297 |
|
298 |
#ifdef EILSEQ
|
299 |
ERRNO_CASE(EILSEQ); |
300 |
#endif
|
301 |
|
302 |
#ifdef EINPROGRESS
|
303 |
ERRNO_CASE(EINPROGRESS); |
304 |
#endif
|
305 |
|
306 |
#ifdef EINTR
|
307 |
ERRNO_CASE(EINTR); |
308 |
#endif
|
309 |
|
310 |
#ifdef EINVAL
|
311 |
ERRNO_CASE(EINVAL); |
312 |
#endif
|
313 |
|
314 |
#ifdef EIO
|
315 |
ERRNO_CASE(EIO); |
316 |
#endif
|
317 |
|
318 |
#ifdef EISCONN
|
319 |
ERRNO_CASE(EISCONN); |
320 |
#endif
|
321 |
|
322 |
#ifdef EISDIR
|
323 |
ERRNO_CASE(EISDIR); |
324 |
#endif
|
325 |
|
326 |
#ifdef ELOOP
|
327 |
ERRNO_CASE(ELOOP); |
328 |
#endif
|
329 |
|
330 |
#ifdef EMFILE
|
331 |
ERRNO_CASE(EMFILE); |
332 |
#endif
|
333 |
|
334 |
#ifdef EMLINK
|
335 |
ERRNO_CASE(EMLINK); |
336 |
#endif
|
337 |
|
338 |
#ifdef EMSGSIZE
|
339 |
ERRNO_CASE(EMSGSIZE); |
340 |
#endif
|
341 |
|
342 |
#ifdef EMULTIHOP
|
343 |
ERRNO_CASE(EMULTIHOP); |
344 |
#endif
|
345 |
|
346 |
#ifdef ENAMETOOLONG
|
347 |
ERRNO_CASE(ENAMETOOLONG); |
348 |
#endif
|
349 |
|
350 |
#ifdef ENETDOWN
|
351 |
ERRNO_CASE(ENETDOWN); |
352 |
#endif
|
353 |
|
354 |
#ifdef ENETRESET
|
355 |
ERRNO_CASE(ENETRESET); |
356 |
#endif
|
357 |
|
358 |
#ifdef ENETUNREACH
|
359 |
ERRNO_CASE(ENETUNREACH); |
360 |
#endif
|
361 |
|
362 |
#ifdef ENFILE
|
363 |
ERRNO_CASE(ENFILE); |
364 |
#endif
|
365 |
|
366 |
#ifdef ENOBUFS
|
367 |
ERRNO_CASE(ENOBUFS); |
368 |
#endif
|
369 |
|
370 |
#ifdef ENODATA
|
371 |
ERRNO_CASE(ENODATA); |
372 |
#endif
|
373 |
|
374 |
#ifdef ENODEV
|
375 |
ERRNO_CASE(ENODEV); |
376 |
#endif
|
377 |
|
378 |
#ifdef ENOENT
|
379 |
ERRNO_CASE(ENOENT); |
380 |
#endif
|
381 |
|
382 |
#ifdef ENOEXEC
|
383 |
ERRNO_CASE(ENOEXEC); |
384 |
#endif
|
385 |
|
386 |
#ifdef ENOLINK
|
387 |
ERRNO_CASE(ENOLINK); |
388 |
#endif
|
389 |
|
390 |
#ifdef ENOLCK
|
391 |
# if ENOLINK != ENOLCK
|
392 |
ERRNO_CASE(ENOLCK); |
393 |
# endif
|
394 |
#endif
|
395 |
|
396 |
#ifdef ENOMEM
|
397 |
ERRNO_CASE(ENOMEM); |
398 |
#endif
|
399 |
|
400 |
#ifdef ENOMSG
|
401 |
ERRNO_CASE(ENOMSG); |
402 |
#endif
|
403 |
|
404 |
#ifdef ENOPROTOOPT
|
405 |
ERRNO_CASE(ENOPROTOOPT); |
406 |
#endif
|
407 |
|
408 |
#ifdef ENOSPC
|
409 |
ERRNO_CASE(ENOSPC); |
410 |
#endif
|
411 |
|
412 |
#ifdef ENOSR
|
413 |
ERRNO_CASE(ENOSR); |
414 |
#endif
|
415 |
|
416 |
#ifdef ENOSTR
|
417 |
ERRNO_CASE(ENOSTR); |
418 |
#endif
|
419 |
|
420 |
#ifdef ENOSYS
|
421 |
ERRNO_CASE(ENOSYS); |
422 |
#endif
|
423 |
|
424 |
#ifdef ENOTCONN
|
425 |
ERRNO_CASE(ENOTCONN); |
426 |
#endif
|
427 |
|
428 |
#ifdef ENOTDIR
|
429 |
ERRNO_CASE(ENOTDIR); |
430 |
#endif
|
431 |
|
432 |
#ifdef ENOTEMPTY
|
433 |
ERRNO_CASE(ENOTEMPTY); |
434 |
#endif
|
435 |
|
436 |
#ifdef ENOTSOCK
|
437 |
ERRNO_CASE(ENOTSOCK); |
438 |
#endif
|
439 |
|
440 |
#ifdef ENOTSUP
|
441 |
ERRNO_CASE(ENOTSUP); |
442 |
#else
|
443 |
# ifdef EOPNOTSUPP
|
444 |
ERRNO_CASE(EOPNOTSUPP); |
445 |
# endif
|
446 |
#endif
|
447 |
|
448 |
#ifdef ENOTTY
|
449 |
ERRNO_CASE(ENOTTY); |
450 |
#endif
|
451 |
|
452 |
#ifdef ENXIO
|
453 |
ERRNO_CASE(ENXIO); |
454 |
#endif
|
455 |
|
456 |
|
457 |
#ifdef EOVERFLOW
|
458 |
ERRNO_CASE(EOVERFLOW); |
459 |
#endif
|
460 |
|
461 |
#ifdef EPERM
|
462 |
ERRNO_CASE(EPERM); |
463 |
#endif
|
464 |
|
465 |
#ifdef EPIPE
|
466 |
ERRNO_CASE(EPIPE); |
467 |
#endif
|
468 |
|
469 |
#ifdef EPROTO
|
470 |
ERRNO_CASE(EPROTO); |
471 |
#endif
|
472 |
|
473 |
#ifdef EPROTONOSUPPORT
|
474 |
ERRNO_CASE(EPROTONOSUPPORT); |
475 |
#endif
|
476 |
|
477 |
#ifdef EPROTOTYPE
|
478 |
ERRNO_CASE(EPROTOTYPE); |
479 |
#endif
|
480 |
|
481 |
#ifdef ERANGE
|
482 |
ERRNO_CASE(ERANGE); |
483 |
#endif
|
484 |
|
485 |
#ifdef EROFS
|
486 |
ERRNO_CASE(EROFS); |
487 |
#endif
|
488 |
|
489 |
#ifdef ESPIPE
|
490 |
ERRNO_CASE(ESPIPE); |
491 |
#endif
|
492 |
|
493 |
#ifdef ESRCH
|
494 |
ERRNO_CASE(ESRCH); |
495 |
#endif
|
496 |
|
497 |
#ifdef ESTALE
|
498 |
ERRNO_CASE(ESTALE); |
499 |
#endif
|
500 |
|
501 |
#ifdef ETIME
|
502 |
ERRNO_CASE(ETIME); |
503 |
#endif
|
504 |
|
505 |
#ifdef ETIMEDOUT
|
506 |
ERRNO_CASE(ETIMEDOUT); |
507 |
#endif
|
508 |
|
509 |
#ifdef ETXTBSY
|
510 |
ERRNO_CASE(ETXTBSY); |
511 |
#endif
|
512 |
|
513 |
#ifdef EXDEV
|
514 |
ERRNO_CASE(EXDEV); |
515 |
#endif
|
516 |
|
517 |
default: return ""; |
518 |
} |
519 |
} |
520 |
|
521 |
const char *signo_string(int signo) { |
522 |
#define SIGNO_CASE(e) case e: return #e; |
523 |
switch (signo) {
|
524 |
#ifdef SIGHUP
|
525 |
SIGNO_CASE(SIGHUP); |
526 |
#endif
|
527 |
|
528 |
#ifdef SIGINT
|
529 |
SIGNO_CASE(SIGINT); |
530 |
#endif
|
531 |
|
532 |
#ifdef SIGQUIT
|
533 |
SIGNO_CASE(SIGQUIT); |
534 |
#endif
|
535 |
|
536 |
#ifdef SIGILL
|
537 |
SIGNO_CASE(SIGILL); |
538 |
#endif
|
539 |
|
540 |
#ifdef SIGTRAP
|
541 |
SIGNO_CASE(SIGTRAP); |
542 |
#endif
|
543 |
|
544 |
#ifdef SIGABRT
|
545 |
SIGNO_CASE(SIGABRT); |
546 |
#endif
|
547 |
|
548 |
#ifdef SIGIOT
|
549 |
# if SIGABRT != SIGIOT
|
550 |
SIGNO_CASE(SIGIOT); |
551 |
# endif
|
552 |
#endif
|
553 |
|
554 |
#ifdef SIGBUS
|
555 |
SIGNO_CASE(SIGBUS); |
556 |
#endif
|
557 |
|
558 |
#ifdef SIGFPE
|
559 |
SIGNO_CASE(SIGFPE); |
560 |
#endif
|
561 |
|
562 |
#ifdef SIGKILL
|
563 |
SIGNO_CASE(SIGKILL); |
564 |
#endif
|
565 |
|
566 |
#ifdef SIGUSR1
|
567 |
SIGNO_CASE(SIGUSR1); |
568 |
#endif
|
569 |
|
570 |
#ifdef SIGSEGV
|
571 |
SIGNO_CASE(SIGSEGV); |
572 |
#endif
|
573 |
|
574 |
#ifdef SIGUSR2
|
575 |
SIGNO_CASE(SIGUSR2); |
576 |
#endif
|
577 |
|
578 |
#ifdef SIGPIPE
|
579 |
SIGNO_CASE(SIGPIPE); |
580 |
#endif
|
581 |
|
582 |
#ifdef SIGALRM
|
583 |
SIGNO_CASE(SIGALRM); |
584 |
#endif
|
585 |
|
586 |
SIGNO_CASE(SIGTERM); |
587 |
|
588 |
#ifdef SIGCHLD
|
589 |
SIGNO_CASE(SIGCHLD); |
590 |
#endif
|
591 |
|
592 |
#ifdef SIGSTKFLT
|
593 |
SIGNO_CASE(SIGSTKFLT); |
594 |
#endif
|
595 |
|
596 |
|
597 |
#ifdef SIGCONT
|
598 |
SIGNO_CASE(SIGCONT); |
599 |
#endif
|
600 |
|
601 |
#ifdef SIGSTOP
|
602 |
SIGNO_CASE(SIGSTOP); |
603 |
#endif
|
604 |
|
605 |
#ifdef SIGTSTP
|
606 |
SIGNO_CASE(SIGTSTP); |
607 |
#endif
|
608 |
|
609 |
#ifdef SIGBREAK
|
610 |
SIGNO_CASE(SIGBREAK); |
611 |
#endif
|
612 |
|
613 |
#ifdef SIGTTIN
|
614 |
SIGNO_CASE(SIGTTIN); |
615 |
#endif
|
616 |
|
617 |
#ifdef SIGTTOU
|
618 |
SIGNO_CASE(SIGTTOU); |
619 |
#endif
|
620 |
|
621 |
#ifdef SIGURG
|
622 |
SIGNO_CASE(SIGURG); |
623 |
#endif
|
624 |
|
625 |
#ifdef SIGXCPU
|
626 |
SIGNO_CASE(SIGXCPU); |
627 |
#endif
|
628 |
|
629 |
#ifdef SIGXFSZ
|
630 |
SIGNO_CASE(SIGXFSZ); |
631 |
#endif
|
632 |
|
633 |
#ifdef SIGVTALRM
|
634 |
SIGNO_CASE(SIGVTALRM); |
635 |
#endif
|
636 |
|
637 |
#ifdef SIGPROF
|
638 |
SIGNO_CASE(SIGPROF); |
639 |
#endif
|
640 |
|
641 |
#ifdef SIGWINCH
|
642 |
SIGNO_CASE(SIGWINCH); |
643 |
#endif
|
644 |
|
645 |
#ifdef SIGIO
|
646 |
SIGNO_CASE(SIGIO); |
647 |
#endif
|
648 |
|
649 |
#ifdef SIGPOLL
|
650 |
# if SIGPOLL != SIGIO
|
651 |
SIGNO_CASE(SIGPOLL); |
652 |
# endif
|
653 |
#endif
|
654 |
|
655 |
#ifdef SIGLOST
|
656 |
SIGNO_CASE(SIGLOST); |
657 |
#endif
|
658 |
|
659 |
#ifdef SIGPWR
|
660 |
# if SIGPWR != SIGLOST
|
661 |
SIGNO_CASE(SIGPWR); |
662 |
# endif
|
663 |
#endif
|
664 |
|
665 |
#ifdef SIGSYS
|
666 |
SIGNO_CASE(SIGSYS); |
667 |
#endif
|
668 |
|
669 |
default: return ""; |
670 |
} |
671 |
} |
672 |
|
673 |
|
674 |
Local<Value> ErrnoException(int errorno,
|
675 |
const char *syscall, |
676 |
const char *msg, |
677 |
const char *path) { |
678 |
Environment* env = Environment::GetCurrent(node_isolate); |
679 |
|
680 |
Local<Value> e; |
681 |
Local<String> estring = OneByteString(node_isolate, errno_string(errorno)); |
682 |
if (msg == NULL || msg[0] == '\0') { |
683 |
msg = strerror(errorno); |
684 |
} |
685 |
Local<String> message = OneByteString(node_isolate, msg); |
686 |
|
687 |
Local<String> cons1 = |
688 |
String::Concat(estring, FIXED_ONE_BYTE_STRING(node_isolate, ", "));
|
689 |
Local<String> cons2 = String::Concat(cons1, message); |
690 |
|
691 |
if (path) {
|
692 |
Local<String> cons3 = |
693 |
String::Concat(cons2, FIXED_ONE_BYTE_STRING(node_isolate, " '"));
|
694 |
Local<String> cons4 = |
695 |
String::Concat(cons3, String::NewFromUtf8(node_isolate, path)); |
696 |
Local<String> cons5 = |
697 |
String::Concat(cons4, FIXED_ONE_BYTE_STRING(node_isolate, "'"));
|
698 |
e = Exception::Error(cons5); |
699 |
} else {
|
700 |
e = Exception::Error(cons2); |
701 |
} |
702 |
|
703 |
Local<Object> obj = e->ToObject(); |
704 |
obj->Set(env->errno_string(), Integer::New(errorno, node_isolate)); |
705 |
obj->Set(env->code_string(), estring); |
706 |
|
707 |
if (path != NULL) { |
708 |
obj->Set(env->path_string(), String::NewFromUtf8(node_isolate, path)); |
709 |
} |
710 |
|
711 |
if (syscall != NULL) { |
712 |
obj->Set(env->syscall_string(), OneByteString(node_isolate, syscall)); |
713 |
} |
714 |
|
715 |
return e;
|
716 |
} |
717 |
|
718 |
|
719 |
// hack alert! copy of ErrnoException, tuned for uv errors
|
720 |
Local<Value> UVException(int errorno,
|
721 |
const char *syscall, |
722 |
const char *msg, |
723 |
const char *path) { |
724 |
Environment* env = Environment::GetCurrent(node_isolate); |
725 |
|
726 |
if (!msg || !msg[0]) |
727 |
msg = uv_strerror(errorno); |
728 |
|
729 |
Local<String> estring = OneByteString(node_isolate, uv_err_name(errorno)); |
730 |
Local<String> message = OneByteString(node_isolate, msg); |
731 |
Local<String> cons1 = |
732 |
String::Concat(estring, FIXED_ONE_BYTE_STRING(node_isolate, ", "));
|
733 |
Local<String> cons2 = String::Concat(cons1, message); |
734 |
|
735 |
Local<Value> e; |
736 |
|
737 |
Local<String> path_str; |
738 |
|
739 |
if (path) {
|
740 |
#ifdef _WIN32
|
741 |
if (strncmp(path, "\\\\?\\UNC\\", 8) == 0) { |
742 |
path_str = String::Concat(FIXED_ONE_BYTE_STRING(node_isolate, "\\\\"),
|
743 |
String::NewFromUtf8(node_isolate, path + 8));
|
744 |
} else if (strncmp(path, "\\\\?\\", 4) == 0) { |
745 |
path_str = String::NewFromUtf8(node_isolate, path + 4);
|
746 |
} else {
|
747 |
path_str = String::NewFromUtf8(node_isolate, path); |
748 |
} |
749 |
#else
|
750 |
path_str = String::NewFromUtf8(node_isolate, path); |
751 |
#endif
|
752 |
|
753 |
Local<String> cons3 = |
754 |
String::Concat(cons2, FIXED_ONE_BYTE_STRING(node_isolate, " '"));
|
755 |
Local<String> cons4 = |
756 |
String::Concat(cons3, path_str); |
757 |
Local<String> cons5 = |
758 |
String::Concat(cons4, FIXED_ONE_BYTE_STRING(node_isolate, "'"));
|
759 |
e = Exception::Error(cons5); |
760 |
} else {
|
761 |
e = Exception::Error(cons2); |
762 |
} |
763 |
|
764 |
Local<Object> obj = e->ToObject(); |
765 |
// TODO(piscisaureus) errno should probably go
|
766 |
obj->Set(env->errno_string(), Integer::New(errorno, node_isolate)); |
767 |
obj->Set(env->code_string(), estring); |
768 |
|
769 |
if (path != NULL) { |
770 |
obj->Set(env->path_string(), path_str); |
771 |
} |
772 |
|
773 |
if (syscall != NULL) { |
774 |
obj->Set(env->syscall_string(), OneByteString(node_isolate, syscall)); |
775 |
} |
776 |
|
777 |
return e;
|
778 |
} |
779 |
|
780 |
|
781 |
#ifdef _WIN32
|
782 |
// Does about the same as strerror(),
|
783 |
// but supports all windows error messages
|
784 |
static const char *winapi_strerror(const int errorno) { |
785 |
char *errmsg = NULL; |
786 |
|
787 |
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
788 |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
|
789 |
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errmsg, 0, NULL); |
790 |
|
791 |
if (errmsg) {
|
792 |
// Remove trailing newlines
|
793 |
for (int i = strlen(errmsg) - 1; |
794 |
i >= 0 && (errmsg[i] == '\n' || errmsg[i] == '\r'); i--) { |
795 |
errmsg[i] = '\0';
|
796 |
} |
797 |
|
798 |
return errmsg;
|
799 |
} else {
|
800 |
// FormatMessage failed
|
801 |
return "Unknown error"; |
802 |
} |
803 |
} |
804 |
|
805 |
|
806 |
Local<Value> WinapiErrnoException(int errorno,
|
807 |
const char* syscall, |
808 |
const char* msg, |
809 |
const char* path) { |
810 |
Environment* env = Environment::GetCurrent(node_isolate); |
811 |
|
812 |
Local<Value> e; |
813 |
if (!msg || !msg[0]) { |
814 |
msg = winapi_strerror(errorno); |
815 |
} |
816 |
Local<String> message = OneByteString(node_isolate, msg); |
817 |
|
818 |
if (path) {
|
819 |
Local<String> cons1 = |
820 |
String::Concat(message, FIXED_ONE_BYTE_STRING(node_isolate, " '"));
|
821 |
Local<String> cons2 = |
822 |
String::Concat(cons1, String::NewFromUtf8(node_isolate, path)); |
823 |
Local<String> cons3 = |
824 |
String::Concat(cons2, FIXED_ONE_BYTE_STRING(node_isolate, "'"));
|
825 |
e = Exception::Error(cons3); |
826 |
} else {
|
827 |
e = Exception::Error(message); |
828 |
} |
829 |
|
830 |
Local<Object> obj = e->ToObject(); |
831 |
obj->Set(env->errno_string(), Integer::New(errorno, node_isolate)); |
832 |
|
833 |
if (path != NULL) { |
834 |
obj->Set(env->path_string(), String::NewFromUtf8(node_isolate, path)); |
835 |
} |
836 |
|
837 |
if (syscall != NULL) { |
838 |
obj->Set(env->syscall_string(), OneByteString(node_isolate, syscall)); |
839 |
} |
840 |
|
841 |
return e;
|
842 |
} |
843 |
#endif
|
844 |
|
845 |
|
846 |
void SetupAsyncListener(const FunctionCallbackInfo<Value>& args) { |
847 |
Environment* env = Environment::GetCurrent(args.GetIsolate()); |
848 |
HandleScope handle_scope(args.GetIsolate()); |
849 |
|
850 |
assert(args[0]->IsObject());
|
851 |
assert(args[1]->IsFunction());
|
852 |
assert(args[2]->IsFunction());
|
853 |
assert(args[3]->IsFunction());
|
854 |
assert(args[4]->IsFunction());
|
855 |
assert(args[5]->IsFunction());
|
856 |
|
857 |
env->set_async_listener_run_function(args[1].As<Function>());
|
858 |
env->set_async_listener_load_function(args[2].As<Function>());
|
859 |
env->set_async_listener_unload_function(args[3].As<Function>());
|
860 |
env->set_async_listener_push_function(args[4].As<Function>());
|
861 |
env->set_async_listener_strip_function(args[5].As<Function>());
|
862 |
|
863 |
Local<Object> async_listener_flag_obj = args[0].As<Object>();
|
864 |
Environment::AsyncListener* async_listener = env->async_listener(); |
865 |
async_listener_flag_obj->SetIndexedPropertiesToExternalArrayData( |
866 |
async_listener->fields(), |
867 |
kExternalUnsignedIntArray, |
868 |
async_listener->fields_count()); |
869 |
|
870 |
// Do a little housekeeping.
|
871 |
env->process_object()->Delete( |
872 |
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupAsyncListener"));
|
873 |
} |
874 |
|
875 |
|
876 |
void SetupNextTick(const FunctionCallbackInfo<Value>& args) { |
877 |
Environment* env = Environment::GetCurrent(args.GetIsolate()); |
878 |
HandleScope handle_scope(args.GetIsolate()); |
879 |
|
880 |
assert(args[0]->IsObject() && args[1]->IsFunction()); |
881 |
|
882 |
// Values use to cross communicate with processNextTick.
|
883 |
Local<Object> tick_info_obj = args[0].As<Object>();
|
884 |
tick_info_obj->SetIndexedPropertiesToExternalArrayData( |
885 |
env->tick_info()->fields(), |
886 |
kExternalUnsignedIntArray, |
887 |
env->tick_info()->fields_count()); |
888 |
|
889 |
env->set_tick_callback_function(args[1].As<Function>());
|
890 |
|
891 |
// Do a little housekeeping.
|
892 |
env->process_object()->Delete( |
893 |
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupNextTick"));
|
894 |
} |
895 |
|
896 |
|
897 |
Handle<Value> MakeCallback(Environment* env, |
898 |
Handle<Object> object, |
899 |
const Handle<Function> callback,
|
900 |
int argc,
|
901 |
Handle<Value> argv[]) { |
902 |
// If you hit this assertion, you forgot to enter the v8::Context first.
|
903 |
assert(env->context() == env->isolate()->GetCurrentContext()); |
904 |
|
905 |
Local<Object> process = env->process_object(); |
906 |
|
907 |
TryCatch try_catch; |
908 |
try_catch.SetVerbose(true);
|
909 |
|
910 |
// TODO(trevnorris): This is sucky for performance. Fix it.
|
911 |
bool has_async_queue = object->Has(env->async_queue_string());
|
912 |
if (has_async_queue) {
|
913 |
Local<Value> argv[] = { object }; |
914 |
env->async_listener_load_function()->Call(process, ARRAY_SIZE(argv), argv); |
915 |
|
916 |
if (try_catch.HasCaught())
|
917 |
return Undefined(node_isolate);
|
918 |
} |
919 |
|
920 |
Local<Value> ret = callback->Call(object, argc, argv); |
921 |
|
922 |
if (try_catch.HasCaught()) {
|
923 |
return Undefined(node_isolate);
|
924 |
} |
925 |
|
926 |
if (has_async_queue) {
|
927 |
Local<Value> val = object.As<Value>(); |
928 |
env->async_listener_unload_function()->Call(process, 1, &val);
|
929 |
|
930 |
if (try_catch.HasCaught())
|
931 |
return Undefined(node_isolate);
|
932 |
} |
933 |
|
934 |
Environment::TickInfo* tick_info = env->tick_info(); |
935 |
|
936 |
if (tick_info->in_tick()) {
|
937 |
return ret;
|
938 |
} |
939 |
|
940 |
if (tick_info->length() == 0) { |
941 |
tick_info->set_index(0);
|
942 |
return ret;
|
943 |
} |
944 |
|
945 |
tick_info->set_in_tick(true);
|
946 |
|
947 |
// process nextTicks after call
|
948 |
env->tick_callback_function()->Call(process, 0, NULL); |
949 |
|
950 |
tick_info->set_in_tick(false);
|
951 |
|
952 |
if (try_catch.HasCaught()) {
|
953 |
tick_info->set_last_threw(true);
|
954 |
return Undefined(node_isolate);
|
955 |
} |
956 |
|
957 |
return ret;
|
958 |
} |
959 |
|
960 |
|
961 |
// Internal only.
|
962 |
Handle<Value> MakeCallback(Environment* env, |
963 |
const Handle<Object> object,
|
964 |
uint32_t index, |
965 |
int argc,
|
966 |
Handle<Value> argv[]) { |
967 |
Local<Function> callback = object->Get(index).As<Function>(); |
968 |
assert(callback->IsFunction()); |
969 |
|
970 |
return MakeCallback(env, object, callback, argc, argv);
|
971 |
} |
972 |
|
973 |
|
974 |
Handle<Value> MakeCallback(Environment* env, |
975 |
const Handle<Object> object,
|
976 |
const Handle<String> symbol,
|
977 |
int argc,
|
978 |
Handle<Value> argv[]) { |
979 |
Local<Function> callback = object->Get(symbol).As<Function>(); |
980 |
assert(callback->IsFunction()); |
981 |
return MakeCallback(env, object, callback, argc, argv);
|
982 |
} |
983 |
|
984 |
|
985 |
Handle<Value> MakeCallback(Environment* env, |
986 |
const Handle<Object> object,
|
987 |
const char* method, |
988 |
int argc,
|
989 |
Handle<Value> argv[]) { |
990 |
Local<String> method_string = OneByteString(node_isolate, method); |
991 |
return MakeCallback(env, object, method_string, argc, argv);
|
992 |
} |
993 |
|
994 |
|
995 |
Handle<Value> MakeCallback(const Handle<Object> object,
|
996 |
const char* method, |
997 |
int argc,
|
998 |
Handle<Value> argv[]) { |
999 |
Local<Context> context = object->CreationContext(); |
1000 |
Environment* env = Environment::GetCurrent(context); |
1001 |
Context::Scope context_scope(context); |
1002 |
HandleScope handle_scope(env->isolate()); |
1003 |
return handle_scope.Close(MakeCallback(env, object, method, argc, argv));
|
1004 |
} |
1005 |
|
1006 |
|
1007 |
Handle<Value> MakeCallback(const Handle<Object> object,
|
1008 |
const Handle<String> symbol,
|
1009 |
int argc,
|
1010 |
Handle<Value> argv[]) { |
1011 |
Local<Context> context = object->CreationContext(); |
1012 |
Environment* env = Environment::GetCurrent(context); |
1013 |
Context::Scope context_scope(context); |
1014 |
HandleScope handle_scope(env->isolate()); |
1015 |
return handle_scope.Close(MakeCallback(env, object, symbol, argc, argv));
|
1016 |
} |
1017 |
|
1018 |
|
1019 |
Handle<Value> MakeCallback(const Handle<Object> object,
|
1020 |
const Handle<Function> callback,
|
1021 |
int argc,
|
1022 |
Handle<Value> argv[]) { |
1023 |
Local<Context> context = object->CreationContext(); |
1024 |
Environment* env = Environment::GetCurrent(context); |
1025 |
Context::Scope context_scope(context); |
1026 |
HandleScope handle_scope(env->isolate()); |
1027 |
return handle_scope.Close(MakeCallback(env, object, callback, argc, argv));
|
1028 |
} |
1029 |
|
1030 |
|
1031 |
enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) { |
1032 |
HandleScope scope(node_isolate); |
1033 |
|
1034 |
if (!encoding_v->IsString())
|
1035 |
return _default;
|
1036 |
|
1037 |
String::Utf8Value encoding(encoding_v); |
1038 |
|
1039 |
if (strcasecmp(*encoding, "utf8") == 0) { |
1040 |
return UTF8;
|
1041 |
} else if (strcasecmp(*encoding, "utf-8") == 0) { |
1042 |
return UTF8;
|
1043 |
} else if (strcasecmp(*encoding, "ascii") == 0) { |
1044 |
return ASCII;
|
1045 |
} else if (strcasecmp(*encoding, "base64") == 0) { |
1046 |
return BASE64;
|
1047 |
} else if (strcasecmp(*encoding, "ucs2") == 0) { |
1048 |
return UCS2;
|
1049 |
} else if (strcasecmp(*encoding, "ucs-2") == 0) { |
1050 |
return UCS2;
|
1051 |
} else if (strcasecmp(*encoding, "utf16le") == 0) { |
1052 |
return UCS2;
|
1053 |
} else if (strcasecmp(*encoding, "utf-16le") == 0) { |
1054 |
return UCS2;
|
1055 |
} else if (strcasecmp(*encoding, "binary") == 0) { |
1056 |
return BINARY;
|
1057 |
} else if (strcasecmp(*encoding, "buffer") == 0) { |
1058 |
return BUFFER;
|
1059 |
} else if (strcasecmp(*encoding, "hex") == 0) { |
1060 |
return HEX;
|
1061 |
} else if (strcasecmp(*encoding, "raw") == 0) { |
1062 |
if (!no_deprecation) {
|
1063 |
fprintf(stderr, "'raw' (array of integers) has been removed. "
|
1064 |
"Use 'binary'.\n");
|
1065 |
} |
1066 |
return BINARY;
|
1067 |
} else if (strcasecmp(*encoding, "raws") == 0) { |
1068 |
if (!no_deprecation) {
|
1069 |
fprintf(stderr, "'raws' encoding has been renamed to 'binary'. "
|
1070 |
"Please update your code.\n");
|
1071 |
} |
1072 |
return BINARY;
|
1073 |
} else {
|
1074 |
return _default;
|
1075 |
} |
1076 |
} |
1077 |
|
1078 |
Local<Value> Encode(const void *buf, size_t len, enum encoding encoding) { |
1079 |
return StringBytes::Encode(static_cast<const char*>(buf), |
1080 |
len, |
1081 |
encoding); |
1082 |
} |
1083 |
|
1084 |
// Returns -1 if the handle was not valid for decoding
|
1085 |
ssize_t DecodeBytes(v8::Handle<v8::Value> val, enum encoding encoding) {
|
1086 |
HandleScope scope(node_isolate); |
1087 |
|
1088 |
if (val->IsArray()) {
|
1089 |
fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
|
1090 |
"Use 'binary'.\n");
|
1091 |
assert(0);
|
1092 |
return -1; |
1093 |
} |
1094 |
|
1095 |
return StringBytes::Size(val, encoding);
|
1096 |
} |
1097 |
|
1098 |
#ifndef MIN
|
1099 |
# define MIN(a, b) ((a) < (b) ? (a) : (b))
|
1100 |
#endif
|
1101 |
|
1102 |
// Returns number of bytes written.
|
1103 |
ssize_t DecodeWrite(char *buf,
|
1104 |
size_t buflen, |
1105 |
v8::Handle<v8::Value> val, |
1106 |
enum encoding encoding) {
|
1107 |
return StringBytes::Write(buf, buflen, val, encoding, NULL); |
1108 |
} |
1109 |
|
1110 |
void DisplayExceptionLine(Handle<Message> message) {
|
1111 |
// Prevent re-entry into this function. For example, if there is
|
1112 |
// a throw from a program in vm.runInThisContext(code, filename, true),
|
1113 |
// then we want to show the original failure, not the secondary one.
|
1114 |
static bool displayed_error = false; |
1115 |
|
1116 |
if (displayed_error)
|
1117 |
return;
|
1118 |
displayed_error = true;
|
1119 |
|
1120 |
uv_tty_reset_mode(); |
1121 |
|
1122 |
fprintf(stderr, "\n");
|
1123 |
|
1124 |
if (!message.IsEmpty()) {
|
1125 |
// Print (filename):(line number): (message).
|
1126 |
String::Utf8Value filename(message->GetScriptResourceName()); |
1127 |
const char* filename_string = *filename; |
1128 |
int linenum = message->GetLineNumber();
|
1129 |
fprintf(stderr, "%s:%i\n", filename_string, linenum);
|
1130 |
// Print line of source code.
|
1131 |
String::Utf8Value sourceline(message->GetSourceLine()); |
1132 |
const char* sourceline_string = *sourceline; |
1133 |
|
1134 |
// Because of how node modules work, all scripts are wrapped with a
|
1135 |
// "function (module, exports, __filename, ...) {"
|
1136 |
// to provide script local variables.
|
1137 |
//
|
1138 |
// When reporting errors on the first line of a script, this wrapper
|
1139 |
// function is leaked to the user. There used to be a hack here to
|
1140 |
// truncate off the first 62 characters, but it caused numerous other
|
1141 |
// problems when vm.runIn*Context() methods were used for non-module
|
1142 |
// code.
|
1143 |
//
|
1144 |
// If we ever decide to re-instate such a hack, the following steps
|
1145 |
// must be taken:
|
1146 |
//
|
1147 |
// 1. Pass a flag around to say "this code was wrapped"
|
1148 |
// 2. Update the stack frame output so that it is also correct.
|
1149 |
//
|
1150 |
// It would probably be simpler to add a line rather than add some
|
1151 |
// number of characters to the first line, since V8 truncates the
|
1152 |
// sourceline to 78 characters, and we end up not providing very much
|
1153 |
// useful debugging info to the user if we remove 62 characters.
|
1154 |
|
1155 |
int start = message->GetStartColumn();
|
1156 |
int end = message->GetEndColumn();
|
1157 |
|
1158 |
fprintf(stderr, "%s\n", sourceline_string);
|
1159 |
// Print wavy underline (GetUnderline is deprecated).
|
1160 |
for (int i = 0; i < start; i++) { |
1161 |
fputc((sourceline_string[i] == '\t') ? '\t' : ' ', stderr); |
1162 |
} |
1163 |
for (int i = start; i < end; i++) { |
1164 |
fputc('^', stderr);
|
1165 |
} |
1166 |
fputc('\n', stderr);
|
1167 |
} |
1168 |
} |
1169 |
|
1170 |
|
1171 |
static void ReportException(Handle<Value> er, Handle<Message> message) { |
1172 |
HandleScope scope(node_isolate); |
1173 |
|
1174 |
DisplayExceptionLine(message); |
1175 |
|
1176 |
Local<Value> trace_value( |
1177 |
er->ToObject()->Get(FIXED_ONE_BYTE_STRING(node_isolate, "stack")));
|
1178 |
String::Utf8Value trace(trace_value); |
1179 |
|
1180 |
// range errors have a trace member set to undefined
|
1181 |
if (trace.length() > 0 && !trace_value->IsUndefined()) { |
1182 |
fprintf(stderr, "%s\n", *trace);
|
1183 |
} else {
|
1184 |
// this really only happens for RangeErrors, since they're the only
|
1185 |
// kind that won't have all this info in the trace, or when non-Error
|
1186 |
// objects are thrown manually.
|
1187 |
Local<Value> message; |
1188 |
Local<Value> name; |
1189 |
|
1190 |
if (er->IsObject()) {
|
1191 |
Local<Object> err_obj = er.As<Object>(); |
1192 |
message = err_obj->Get(FIXED_ONE_BYTE_STRING(node_isolate, "message"));
|
1193 |
name = err_obj->Get(FIXED_ONE_BYTE_STRING(node_isolate, "name"));
|
1194 |
} |
1195 |
|
1196 |
if (message.IsEmpty() ||
|
1197 |
message->IsUndefined() || |
1198 |
name.IsEmpty() || |
1199 |
name->IsUndefined()) { |
1200 |
// Not an error object. Just print as-is.
|
1201 |
String::Utf8Value message(er); |
1202 |
fprintf(stderr, "%s\n", *message);
|
1203 |
} else {
|
1204 |
String::Utf8Value name_string(name); |
1205 |
String::Utf8Value message_string(message); |
1206 |
fprintf(stderr, "%s: %s\n", *name_string, *message_string);
|
1207 |
} |
1208 |
} |
1209 |
|
1210 |
fflush(stderr); |
1211 |
} |
1212 |
|
1213 |
|
1214 |
static void ReportException(const TryCatch& try_catch) { |
1215 |
ReportException(try_catch.Exception(), try_catch.Message()); |
1216 |
} |
1217 |
|
1218 |
|
1219 |
// Executes a str within the current v8 context.
|
1220 |
Local<Value> ExecuteString(Handle<String> source, Handle<Value> filename) { |
1221 |
HandleScope scope(node_isolate); |
1222 |
TryCatch try_catch; |
1223 |
|
1224 |
// try_catch must be nonverbose to disable FatalException() handler,
|
1225 |
// we will handle exceptions ourself.
|
1226 |
try_catch.SetVerbose(false);
|
1227 |
|
1228 |
Local<v8::Script> script = v8::Script::Compile(source, filename); |
1229 |
if (script.IsEmpty()) {
|
1230 |
ReportException(try_catch); |
1231 |
exit(3);
|
1232 |
} |
1233 |
|
1234 |
Local<Value> result = script->Run(); |
1235 |
if (result.IsEmpty()) {
|
1236 |
ReportException(try_catch); |
1237 |
exit(4);
|
1238 |
} |
1239 |
|
1240 |
return scope.Close(result);
|
1241 |
} |
1242 |
|
1243 |
|
1244 |
static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) { |
1245 |
HandleScope scope(node_isolate); |
1246 |
|
1247 |
Local<Array> ary = Array::New(); |
1248 |
QUEUE* q = NULL;
|
1249 |
int i = 0; |
1250 |
|
1251 |
QUEUE_FOREACH(q, &req_wrap_queue) { |
1252 |
ReqWrap<uv_req_t>* w = CONTAINER_OF(q, ReqWrap<uv_req_t>, req_wrap_queue_); |
1253 |
if (w->persistent().IsEmpty())
|
1254 |
continue;
|
1255 |
ary->Set(i++, w->object()); |
1256 |
} |
1257 |
|
1258 |
args.GetReturnValue().Set(ary); |
1259 |
} |
1260 |
|
1261 |
|
1262 |
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
|
1263 |
// implemented here for consistency with GetActiveRequests().
|
1264 |
void GetActiveHandles(const FunctionCallbackInfo<Value>& args) { |
1265 |
HandleScope scope(node_isolate); |
1266 |
|
1267 |
Local<Array> ary = Array::New(); |
1268 |
QUEUE* q = NULL;
|
1269 |
int i = 0; |
1270 |
|
1271 |
Local<String> owner_sym = FIXED_ONE_BYTE_STRING(node_isolate, "owner");
|
1272 |
|
1273 |
QUEUE_FOREACH(q, &handle_wrap_queue) { |
1274 |
HandleWrap* w = CONTAINER_OF(q, HandleWrap, handle_wrap_queue_); |
1275 |
if (w->persistent().IsEmpty() || (w->flags_ & HandleWrap::kUnref))
|
1276 |
continue;
|
1277 |
Local<Object> object = w->object(); |
1278 |
Local<Value> owner = object->Get(owner_sym); |
1279 |
if (owner->IsUndefined())
|
1280 |
owner = object; |
1281 |
ary->Set(i++, owner); |
1282 |
} |
1283 |
|
1284 |
args.GetReturnValue().Set(ary); |
1285 |
} |
1286 |
|
1287 |
|
1288 |
static void Abort(const FunctionCallbackInfo<Value>& args) { |
1289 |
abort(); |
1290 |
} |
1291 |
|
1292 |
|
1293 |
static void Chdir(const FunctionCallbackInfo<Value>& args) { |
1294 |
HandleScope scope(node_isolate); |
1295 |
|
1296 |
if (args.Length() != 1 || !args[0]->IsString()) { |
1297 |
return ThrowError("Bad argument."); // FIXME(bnoordhuis) ThrowTypeError? |
1298 |
} |
1299 |
|
1300 |
String::Utf8Value path(args[0]);
|
1301 |
int err = uv_chdir(*path);
|
1302 |
if (err) {
|
1303 |
return ThrowUVException(err, "uv_chdir"); |
1304 |
} |
1305 |
} |
1306 |
|
1307 |
|
1308 |
static void Cwd(const FunctionCallbackInfo<Value>& args) { |
1309 |
HandleScope scope(node_isolate); |
1310 |
#ifdef _WIN32
|
1311 |
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
|
1312 |
char buf[MAX_PATH * 4 + 1]; |
1313 |
#else
|
1314 |
char buf[PATH_MAX + 1]; |
1315 |
#endif
|
1316 |
|
1317 |
int err = uv_cwd(buf, ARRAY_SIZE(buf) - 1); |
1318 |
if (err) {
|
1319 |
return ThrowUVException(err, "uv_cwd"); |
1320 |
} |
1321 |
|
1322 |
buf[ARRAY_SIZE(buf) - 1] = '\0'; |
1323 |
Local<String> cwd = String::NewFromUtf8(node_isolate, buf); |
1324 |
|
1325 |
args.GetReturnValue().Set(cwd); |
1326 |
} |
1327 |
|
1328 |
|
1329 |
static void Umask(const FunctionCallbackInfo<Value>& args) { |
1330 |
HandleScope scope(node_isolate); |
1331 |
uint32_t old; |
1332 |
|
1333 |
if (args.Length() < 1 || args[0]->IsUndefined()) { |
1334 |
old = umask(0);
|
1335 |
umask(static_cast<mode_t>(old));
|
1336 |
} else if (!args[0]->IsInt32() && !args[0]->IsString()) { |
1337 |
return ThrowTypeError("argument must be an integer or octal string."); |
1338 |
} else {
|
1339 |
int oct;
|
1340 |
if (args[0]->IsInt32()) { |
1341 |
oct = args[0]->Uint32Value();
|
1342 |
} else {
|
1343 |
oct = 0;
|
1344 |
String::Utf8Value str(args[0]);
|
1345 |
|
1346 |
// Parse the octal string.
|
1347 |
for (int i = 0; i < str.length(); i++) { |
1348 |
char c = (*str)[i];
|
1349 |
if (c > '7' || c < '0') { |
1350 |
return ThrowTypeError("invalid octal string"); |
1351 |
} |
1352 |
oct *= 8;
|
1353 |
oct += c - '0';
|
1354 |
} |
1355 |
} |
1356 |
old = umask(static_cast<mode_t>(oct));
|
1357 |
} |
1358 |
|
1359 |
args.GetReturnValue().Set(old); |
1360 |
} |
1361 |
|
1362 |
|
1363 |
#if defined(__POSIX__) && !defined(__ANDROID__)
|
1364 |
|
1365 |
static const uid_t uid_not_found = static_cast<uid_t>(-1); |
1366 |
static const gid_t gid_not_found = static_cast<gid_t>(-1); |
1367 |
|
1368 |
|
1369 |
static uid_t uid_by_name(const char* name) { |
1370 |
struct passwd pwd;
|
1371 |
struct passwd* pp;
|
1372 |
char buf[8192]; |
1373 |
|
1374 |
errno = 0;
|
1375 |
pp = NULL;
|
1376 |
|
1377 |
if (getpwnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != NULL) { |
1378 |
return pp->pw_uid;
|
1379 |
} |
1380 |
|
1381 |
return uid_not_found;
|
1382 |
} |
1383 |
|
1384 |
|
1385 |
static char* name_by_uid(uid_t uid) { |
1386 |
struct passwd pwd;
|
1387 |
struct passwd* pp;
|
1388 |
char buf[8192]; |
1389 |
int rc;
|
1390 |
|
1391 |
errno = 0;
|
1392 |
pp = NULL;
|
1393 |
|
1394 |
if ((rc = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pp)) == 0 && pp != NULL) { |
1395 |
return strdup(pp->pw_name);
|
1396 |
} |
1397 |
|
1398 |
if (rc == 0) { |
1399 |
errno = ENOENT; |
1400 |
} |
1401 |
|
1402 |
return NULL; |
1403 |
} |
1404 |
|
1405 |
|
1406 |
static gid_t gid_by_name(const char* name) { |
1407 |
struct group pwd;
|
1408 |
struct group* pp;
|
1409 |
char buf[8192]; |
1410 |
|
1411 |
errno = 0;
|
1412 |
pp = NULL;
|
1413 |
|
1414 |
if (getgrnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != NULL) { |
1415 |
return pp->gr_gid;
|
1416 |
} |
1417 |
|
1418 |
return gid_not_found;
|
1419 |
} |
1420 |
|
1421 |
|
1422 |
#if 0 // For future use.
|
1423 |
static const char* name_by_gid(gid_t gid) {
|
1424 |
struct group pwd;
|
1425 |
struct group* pp;
|
1426 |
char buf[8192];
|
1427 |
int rc;
|
1428 |
|
1429 |
errno = 0;
|
1430 |
pp = NULL;
|
1431 |
|
1432 |
if ((rc = getgrgid_r(gid, &pwd, buf, sizeof(buf), &pp)) == 0 && pp != NULL) {
|
1433 |
return strdup(pp->gr_name);
|
1434 |
}
|
1435 |
|
1436 |
if (rc == 0) {
|
1437 |
errno = ENOENT;
|
1438 |
}
|
1439 |
|
1440 |
return NULL;
|
1441 |
}
|
1442 |
#endif
|
1443 |
|
1444 |
|
1445 |
static uid_t uid_by_name(Handle<Value> value) {
|
1446 |
if (value->IsUint32()) {
|
1447 |
return static_cast<uid_t>(value->Uint32Value()); |
1448 |
} else {
|
1449 |
String::Utf8Value name(value); |
1450 |
return uid_by_name(*name);
|
1451 |
} |
1452 |
} |
1453 |
|
1454 |
|
1455 |
static gid_t gid_by_name(Handle<Value> value) {
|
1456 |
if (value->IsUint32()) {
|
1457 |
return static_cast<gid_t>(value->Uint32Value()); |
1458 |
} else {
|
1459 |
String::Utf8Value name(value); |
1460 |
return gid_by_name(*name);
|
1461 |
} |
1462 |
} |
1463 |
|
1464 |
|
1465 |
static void GetUid(const FunctionCallbackInfo<Value>& args) { |
1466 |
// uid_t is an uint32_t on all supported platforms.
|
1467 |
args.GetReturnValue().Set(static_cast<uint32_t>(getuid()));
|
1468 |
} |
1469 |
|
1470 |
|
1471 |
static void GetGid(const FunctionCallbackInfo<Value>& args) { |
1472 |
// gid_t is an uint32_t on all supported platforms.
|
1473 |
args.GetReturnValue().Set(static_cast<uint32_t>(getgid()));
|
1474 |
} |
1475 |
|
1476 |
|
1477 |
static void SetGid(const FunctionCallbackInfo<Value>& args) { |
1478 |
HandleScope scope(node_isolate); |
1479 |
|
1480 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
1481 |
return ThrowTypeError("setgid argument must be a number or a string"); |
1482 |
} |
1483 |
|
1484 |
gid_t gid = gid_by_name(args[0]);
|
1485 |
|
1486 |
if (gid == gid_not_found) {
|
1487 |
return ThrowError("setgid group id does not exist"); |
1488 |
} |
1489 |
|
1490 |
if (setgid(gid)) {
|
1491 |
return ThrowErrnoException(errno, "setgid"); |
1492 |
} |
1493 |
} |
1494 |
|
1495 |
|
1496 |
static void SetUid(const FunctionCallbackInfo<Value>& args) { |
1497 |
HandleScope scope(node_isolate); |
1498 |
|
1499 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
1500 |
return ThrowTypeError("setuid argument must be a number or a string"); |
1501 |
} |
1502 |
|
1503 |
uid_t uid = uid_by_name(args[0]);
|
1504 |
|
1505 |
if (uid == uid_not_found) {
|
1506 |
return ThrowError("setuid user id does not exist"); |
1507 |
} |
1508 |
|
1509 |
if (setuid(uid)) {
|
1510 |
return ThrowErrnoException(errno, "setuid"); |
1511 |
} |
1512 |
} |
1513 |
|
1514 |
|
1515 |
static void GetGroups(const FunctionCallbackInfo<Value>& args) { |
1516 |
HandleScope scope(node_isolate); |
1517 |
|
1518 |
int ngroups = getgroups(0, NULL); |
1519 |
|
1520 |
if (ngroups == -1) { |
1521 |
return ThrowErrnoException(errno, "getgroups"); |
1522 |
} |
1523 |
|
1524 |
gid_t* groups = new gid_t[ngroups];
|
1525 |
|
1526 |
ngroups = getgroups(ngroups, groups); |
1527 |
|
1528 |
if (ngroups == -1) { |
1529 |
delete[] groups;
|
1530 |
return ThrowErrnoException(errno, "getgroups"); |
1531 |
} |
1532 |
|
1533 |
Local<Array> groups_list = Array::New(ngroups); |
1534 |
bool seen_egid = false; |
1535 |
gid_t egid = getegid(); |
1536 |
|
1537 |
for (int i = 0; i < ngroups; i++) { |
1538 |
groups_list->Set(i, Integer::New(groups[i], node_isolate)); |
1539 |
if (groups[i] == egid)
|
1540 |
seen_egid = true;
|
1541 |
} |
1542 |
|
1543 |
delete[] groups;
|
1544 |
|
1545 |
if (seen_egid == false) { |
1546 |
groups_list->Set(ngroups, Integer::New(egid, node_isolate)); |
1547 |
} |
1548 |
|
1549 |
args.GetReturnValue().Set(groups_list); |
1550 |
} |
1551 |
|
1552 |
|
1553 |
static void SetGroups(const FunctionCallbackInfo<Value>& args) { |
1554 |
HandleScope scope(node_isolate); |
1555 |
|
1556 |
if (!args[0]->IsArray()) { |
1557 |
return ThrowTypeError("argument 1 must be an array"); |
1558 |
} |
1559 |
|
1560 |
Local<Array> groups_list = args[0].As<Array>();
|
1561 |
size_t size = groups_list->Length(); |
1562 |
gid_t* groups = new gid_t[size];
|
1563 |
|
1564 |
for (size_t i = 0; i < size; i++) { |
1565 |
gid_t gid = gid_by_name(groups_list->Get(i)); |
1566 |
|
1567 |
if (gid == gid_not_found) {
|
1568 |
delete[] groups;
|
1569 |
return ThrowError("group name not found"); |
1570 |
} |
1571 |
|
1572 |
groups[i] = gid; |
1573 |
} |
1574 |
|
1575 |
int rc = setgroups(size, groups);
|
1576 |
delete[] groups;
|
1577 |
|
1578 |
if (rc == -1) { |
1579 |
return ThrowErrnoException(errno, "setgroups"); |
1580 |
} |
1581 |
} |
1582 |
|
1583 |
|
1584 |
static void InitGroups(const FunctionCallbackInfo<Value>& args) { |
1585 |
HandleScope scope(node_isolate); |
1586 |
|
1587 |
if (!args[0]->IsUint32() && !args[0]->IsString()) { |
1588 |
return ThrowTypeError("argument 1 must be a number or a string"); |
1589 |
} |
1590 |
|
1591 |
if (!args[1]->IsUint32() && !args[1]->IsString()) { |
1592 |
return ThrowTypeError("argument 2 must be a number or a string"); |
1593 |
} |
1594 |
|
1595 |
String::Utf8Value arg0(args[0]);
|
1596 |
gid_t extra_group; |
1597 |
bool must_free;
|
1598 |
char* user;
|
1599 |
|
1600 |
if (args[0]->IsUint32()) { |
1601 |
user = name_by_uid(args[0]->Uint32Value());
|
1602 |
must_free = true;
|
1603 |
} else {
|
1604 |
user = *arg0; |
1605 |
must_free = false;
|
1606 |
} |
1607 |
|
1608 |
if (user == NULL) { |
1609 |
return ThrowError("initgroups user not found"); |
1610 |
} |
1611 |
|
1612 |
extra_group = gid_by_name(args[1]);
|
1613 |
|
1614 |
if (extra_group == gid_not_found) {
|
1615 |
if (must_free)
|
1616 |
free(user); |
1617 |
return ThrowError("initgroups extra group not found"); |
1618 |
} |
1619 |
|
1620 |
int rc = initgroups(user, extra_group);
|
1621 |
|
1622 |
if (must_free) {
|
1623 |
free(user); |
1624 |
} |
1625 |
|
1626 |
if (rc) {
|
1627 |
return ThrowErrnoException(errno, "initgroups"); |
1628 |
} |
1629 |
} |
1630 |
|
1631 |
#endif // __POSIX__ && !defined(__ANDROID__) |
1632 |
|
1633 |
|
1634 |
void Exit(const FunctionCallbackInfo<Value>& args) { |
1635 |
HandleScope scope(node_isolate); |
1636 |
exit(args[0]->IntegerValue());
|
1637 |
} |
1638 |
|
1639 |
|
1640 |
static void Uptime(const FunctionCallbackInfo<Value>& args) { |
1641 |
HandleScope scope(node_isolate); |
1642 |
double uptime;
|
1643 |
if (uv_uptime(&uptime))
|
1644 |
return;
|
1645 |
args.GetReturnValue().Set(uptime - prog_start_time); |
1646 |
} |
1647 |
|
1648 |
|
1649 |
void MemoryUsage(const FunctionCallbackInfo<Value>& args) { |
1650 |
Environment* env = Environment::GetCurrent(args.GetIsolate()); |
1651 |
HandleScope handle_scope(args.GetIsolate()); |
1652 |
|
1653 |
size_t rss; |
1654 |
int err = uv_resident_set_memory(&rss);
|
1655 |
if (err) {
|
1656 |
return ThrowUVException(err, "uv_resident_set_memory"); |
1657 |
} |
1658 |
|
1659 |
// V8 memory usage
|
1660 |
HeapStatistics v8_heap_stats; |
1661 |
node_isolate->GetHeapStatistics(&v8_heap_stats); |
1662 |
|
1663 |
Local<Integer> heap_total = |
1664 |
Integer::NewFromUnsigned(v8_heap_stats.total_heap_size(), node_isolate); |
1665 |
Local<Integer> heap_used = |
1666 |
Integer::NewFromUnsigned(v8_heap_stats.used_heap_size(), node_isolate); |
1667 |
|
1668 |
Local<Object> info = Object::New(); |
1669 |
info->Set(env->rss_string(), Number::New(node_isolate, rss)); |
1670 |
info->Set(env->heap_total_string(), heap_total); |
1671 |
info->Set(env->heap_used_string(), heap_used); |
1672 |
|
1673 |
args.GetReturnValue().Set(info); |
1674 |
} |
1675 |
|
1676 |
|
1677 |
void Kill(const FunctionCallbackInfo<Value>& args) { |
1678 |
HandleScope scope(node_isolate); |
1679 |
|
1680 |
if (args.Length() != 2) { |
1681 |
return ThrowError("Bad argument."); |
1682 |
} |
1683 |
|
1684 |
int pid = args[0]->IntegerValue(); |
1685 |
int sig = args[1]->Int32Value(); |
1686 |
int err = uv_kill(pid, sig);
|
1687 |
args.GetReturnValue().Set(err); |
1688 |
} |
1689 |
|
1690 |
// used in Hrtime() below
|
1691 |
#define NANOS_PER_SEC 1000000000 |
1692 |
|
1693 |
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
|
1694 |
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
|
1695 |
// so this function instead returns an Array with 2 entries representing seconds
|
1696 |
// and nanoseconds, to avoid any integer overflow possibility.
|
1697 |
// Pass in an Array from a previous hrtime() call to instead get a time diff.
|
1698 |
void Hrtime(const FunctionCallbackInfo<Value>& args) { |
1699 |
HandleScope scope(node_isolate); |
1700 |
|
1701 |
uint64_t t = uv_hrtime(); |
1702 |
|
1703 |
if (args.Length() > 0) { |
1704 |
// return a time diff tuple
|
1705 |
if (!args[0]->IsArray()) { |
1706 |
return ThrowTypeError("process.hrtime() only accepts an Array tuple."); |
1707 |
} |
1708 |
Local<Array> inArray = Local<Array>::Cast(args[0]);
|
1709 |
uint64_t seconds = inArray->Get(0)->Uint32Value();
|
1710 |
uint64_t nanos = inArray->Get(1)->Uint32Value();
|
1711 |
t -= (seconds * NANOS_PER_SEC) + nanos; |
1712 |
} |
1713 |
|
1714 |
Local<Array> tuple = Array::New(2);
|
1715 |
tuple->Set(0, Integer::NewFromUnsigned(t / NANOS_PER_SEC, node_isolate));
|
1716 |
tuple->Set(1, Integer::NewFromUnsigned(t % NANOS_PER_SEC, node_isolate));
|
1717 |
args.GetReturnValue().Set(tuple); |
1718 |
} |
1719 |
|
1720 |
|
1721 |
typedef void (UV_DYNAMIC* extInit)(Handle<Object> exports); |
1722 |
|
1723 |
// DLOpen is process.dlopen(module, filename).
|
1724 |
// Used to load 'module.node' dynamically shared objects.
|
1725 |
//
|
1726 |
// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
|
1727 |
// when two contexts try to load the same shared object. Maybe have a shadow
|
1728 |
// cache that's a plain C list or hash table that's shared across contexts?
|
1729 |
void DLOpen(const FunctionCallbackInfo<Value>& args) { |
1730 |
Environment* env = Environment::GetCurrent(args.GetIsolate()); |
1731 |
HandleScope handle_scope(args.GetIsolate()); |
1732 |
char symbol[1024], *base, *pos; |
1733 |
uv_lib_t lib; |
1734 |
int r;
|
1735 |
|
1736 |
if (args.Length() < 2) { |
1737 |
return ThrowError("process.dlopen takes exactly 2 arguments."); |
1738 |
} |
1739 |
|
1740 |
Local<Object> module = args[0]->ToObject(); // Cast |
1741 |
String::Utf8Value filename(args[1]); // Cast |
1742 |
|
1743 |
Local<String> exports_string = env->exports_string(); |
1744 |
Local<Object> exports = module->Get(exports_string)->ToObject(); |
1745 |
|
1746 |
if (uv_dlopen(*filename, &lib)) {
|
1747 |
Local<String> errmsg = OneByteString(env->isolate(), uv_dlerror(&lib)); |
1748 |
#ifdef _WIN32
|
1749 |
// Windows needs to add the filename into the error message
|
1750 |
errmsg = String::Concat(errmsg, args[1]->ToString());
|
1751 |
#endif // _WIN32 |
1752 |
ThrowException(Exception::Error(errmsg)); |
1753 |
return;
|
1754 |
} |
1755 |
|
1756 |
String::Utf8Value path(args[1]);
|
1757 |
base = *path; |
1758 |
|
1759 |
/* Find the shared library filename within the full path. */
|
1760 |
#ifdef __POSIX__
|
1761 |
pos = strrchr(base, '/');
|
1762 |
if (pos != NULL) { |
1763 |
base = pos + 1;
|
1764 |
} |
1765 |
#else // Windows |
1766 |
for (;;) {
|
1767 |
pos = strpbrk(base, "\\/:");
|
1768 |
if (pos == NULL) { |
1769 |
break;
|
1770 |
} |
1771 |
base = pos + 1;
|
1772 |
} |
1773 |
#endif // __POSIX__ |
1774 |
|
1775 |
/* Strip the .node extension. */
|
1776 |
pos = strrchr(base, '.');
|
1777 |
if (pos != NULL) { |
1778 |
*pos = '\0';
|
1779 |
} |
1780 |
|
1781 |
/* Add the `_module` suffix to the extension name. */
|
1782 |
r = snprintf(symbol, sizeof symbol, "%s_module", base); |
1783 |
if (r <= 0 || static_cast<size_t>(r) >= sizeof symbol) { |
1784 |
return ThrowError("Out of memory."); |
1785 |
} |
1786 |
|
1787 |
/* Replace dashes with underscores. When loading foo-bar.node,
|
1788 |
* look for foo_bar_module, not foo-bar_module.
|
1789 |
*/
|
1790 |
for (pos = symbol; *pos != '\0'; ++pos) { |
1791 |
if (*pos == '-') |
1792 |
*pos = '_';
|
1793 |
} |
1794 |
|
1795 |
node_module_struct *mod; |
1796 |
if (uv_dlsym(&lib, symbol, reinterpret_cast<void**>(&mod))) { |
1797 |
char errmsg[1024]; |
1798 |
snprintf(errmsg, sizeof(errmsg), "Symbol %s not found.", symbol); |
1799 |
return ThrowError(errmsg);
|
1800 |
} |
1801 |
|
1802 |
if (mod->version != NODE_MODULE_VERSION) {
|
1803 |
char errmsg[1024]; |
1804 |
snprintf(errmsg, |
1805 |
sizeof(errmsg),
|
1806 |
"Module version mismatch. Expected %d, got %d.",
|
1807 |
NODE_MODULE_VERSION, mod->version); |
1808 |
return ThrowError(errmsg);
|
1809 |
} |
1810 |
|
1811 |
// Execute the C++ module
|
1812 |
if (mod->register_context_func != NULL) { |
1813 |
mod->register_context_func(exports, module, env->context()); |
1814 |
} else if (mod->register_func != NULL) { |
1815 |
mod->register_func(exports, module); |
1816 |
} else {
|
1817 |
return ThrowError("Module has no declared entry point."); |
1818 |
} |
1819 |
|
1820 |
// Tell coverity that 'handle' should not be freed when we return.
|
1821 |
// coverity[leaked_storage]
|
1822 |
} |
1823 |
|
1824 |
|
1825 |
static void OnFatalError(const char* location, const char* message) { |
1826 |
if (location) {
|
1827 |
fprintf(stderr, "FATAL ERROR: %s %s\n", location, message);
|
1828 |
} else {
|
1829 |
fprintf(stderr, "FATAL ERROR: %s\n", message);
|
1830 |
} |
1831 |
fflush(stderr); |
1832 |
#if defined(DEBUG)
|
1833 |
abort(); |
1834 |
#endif
|
1835 |
exit(5);
|
1836 |
} |
1837 |
|
1838 |
|
1839 |
NO_RETURN void FatalError(const char* location, const char* message) { |
1840 |
OnFatalError(location, message); |
1841 |
// to supress compiler warning
|
1842 |
abort(); |
1843 |
} |
1844 |
|
1845 |
|
1846 |
void FatalException(Handle<Value> error, Handle<Message> message) {
|
1847 |
HandleScope scope(node_isolate); |
1848 |
|
1849 |
Environment* env = Environment::GetCurrent(node_isolate); |
1850 |
Local<Object> process_object = env->process_object(); |
1851 |
Local<String> fatal_exception_string = env->fatal_exception_string(); |
1852 |
Local<Function> fatal_exception_function = |
1853 |
process_object->Get(fatal_exception_string).As<Function>(); |
1854 |
|
1855 |
if (!fatal_exception_function->IsFunction()) {
|
1856 |
// failed before the process._fatalException function was added!
|
1857 |
// this is probably pretty bad. Nothing to do but report and exit.
|
1858 |
ReportException(error, message); |
1859 |
exit(6);
|
1860 |
} |
1861 |
|
1862 |
TryCatch fatal_try_catch; |
1863 |
|
1864 |
// Do not call FatalException when _fatalException handler throws
|
1865 |
fatal_try_catch.SetVerbose(false);
|
1866 |
|
1867 |
// this will return true if the JS layer handled it, false otherwise
|
1868 |
Local<Value> caught = |
1869 |
fatal_exception_function->Call(process_object, 1, &error);
|
1870 |
|
1871 |
if (fatal_try_catch.HasCaught()) {
|
1872 |
// the fatal exception function threw, so we must exit
|
1873 |
ReportException(fatal_try_catch); |
1874 |
exit(7);
|
1875 |
} |
1876 |
|
1877 |
if (false == caught->BooleanValue()) { |
1878 |
ReportException(error, message); |
1879 |
exit(1);
|
1880 |
} |
1881 |
} |
1882 |
|
1883 |
|
1884 |
void FatalException(const TryCatch& try_catch) { |
1885 |
HandleScope scope(node_isolate); |
1886 |
// TODO(bajtos) do not call FatalException if try_catch is verbose
|
1887 |
// (requires V8 API to expose getter for try_catch.is_verbose_)
|
1888 |
FatalException(try_catch.Exception(), try_catch.Message()); |
1889 |
} |
1890 |
|
1891 |
|
1892 |
void OnMessage(Handle<Message> message, Handle<Value> error) {
|
1893 |
// The current version of V8 sends messages for errors only
|
1894 |
// (thus `error` is always set).
|
1895 |
FatalException(error, message); |
1896 |
} |
1897 |
|
1898 |
|
1899 |
static void Binding(const FunctionCallbackInfo<Value>& args) { |
1900 |
Environment* env = Environment::GetCurrent(args.GetIsolate()); |
1901 |
HandleScope handle_scope(args.GetIsolate()); |
1902 |
|
1903 |
Local<String> module = args[0]->ToString();
|
1904 |
String::Utf8Value module_v(module); |
1905 |
|
1906 |
Local<Object> cache = env->binding_cache_object(); |
1907 |
Local<Object> exports; |
1908 |
|
1909 |
if (cache->Has(module)) {
|
1910 |
exports = cache->Get(module)->ToObject(); |
1911 |
args.GetReturnValue().Set(exports); |
1912 |
return;
|
1913 |
} |
1914 |
|
1915 |
// Append a string to process.moduleLoadList
|
1916 |
char buf[1024]; |
1917 |
snprintf(buf, sizeof(buf), "Binding %s", *module_v); |
1918 |
|
1919 |
Local<Array> modules = env->module_load_list_array(); |
1920 |
uint32_t l = modules->Length(); |
1921 |
modules->Set(l, OneByteString(node_isolate, buf)); |
1922 |
|
1923 |
node_module_struct* mod = get_builtin_module(*module_v); |
1924 |
if (mod != NULL) { |
1925 |
exports = Object::New(); |
1926 |
// Internal bindings don't have a "module" object, only exports.
|
1927 |
assert(mod->register_func == NULL);
|
1928 |
assert(mod->register_context_func != NULL);
|
1929 |
Local<Value> unused = Undefined(env->isolate()); |
1930 |
mod->register_context_func(exports, unused, env->context()); |
1931 |
cache->Set(module, exports); |
1932 |
} else if (!strcmp(*module_v, "constants")) { |
1933 |
exports = Object::New(); |
1934 |
DefineConstants(exports); |
1935 |
cache->Set(module, exports); |
1936 |
} else if (!strcmp(*module_v, "natives")) { |
1937 |
exports = Object::New(); |
1938 |
DefineJavaScript(exports); |
1939 |
cache->Set(module, exports); |
1940 |
} else {
|
1941 |
return ThrowError("No such module"); |
1942 |
} |
1943 |
|
1944 |
args.GetReturnValue().Set(exports); |
1945 |
} |
1946 |
|
1947 |
|
1948 |
static void ProcessTitleGetter(Local<String> property, |
1949 |
const PropertyCallbackInfo<Value>& info) {
|
1950 |
HandleScope scope(node_isolate); |
1951 |
char buffer[512]; |
1952 |
uv_get_process_title(buffer, sizeof(buffer));
|
1953 |
info.GetReturnValue().Set(String::NewFromUtf8(node_isolate, buffer)); |
1954 |
} |
1955 |
|
1956 |
|
1957 |
static void ProcessTitleSetter(Local<String> property, |
1958 |
Local<Value> value, |
1959 |
const PropertyCallbackInfo<void>& info) { |
1960 |
HandleScope scope(node_isolate); |
1961 |
String::Utf8Value title(value); |
1962 |
// TODO(piscisaureus): protect with a lock
|
1963 |
uv_set_process_title(*title); |
1964 |
} |
1965 |
|
1966 |
|
1967 |
static void EnvGetter(Local<String> property, |
1968 |
const PropertyCallbackInfo<Value>& info) {
|
1969 |
HandleScope scope(node_isolate); |
1970 |
#ifdef __POSIX__
|
1971 |
String::Utf8Value key(property); |
1972 |
const char* val = getenv(*key); |
1973 |
if (val) {
|
1974 |
return info.GetReturnValue().Set(String::NewFromUtf8(node_isolate, val));
|
1975 |
} |
1976 |
#else // _WIN32 |
1977 |
String::Value key(property); |
1978 |
WCHAR buffer[32767]; // The maximum size allowed for environment variables. |
1979 |
DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key),
|
1980 |
buffer, |
1981 |
ARRAY_SIZE(buffer)); |
1982 |
// If result >= sizeof buffer the buffer was too small. That should never
|
1983 |
// happen. If result == 0 and result != ERROR_SUCCESS the variable was not
|
1984 |
// not found.
|
1985 |
if ((result > 0 || GetLastError() == ERROR_SUCCESS) && |
1986 |
result < ARRAY_SIZE(buffer)) { |
1987 |
const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer); |
1988 |
Local<String> rc = String::NewFromTwoByte(node_isolate, two_byte_buffer); |
1989 |
return info.GetReturnValue().Set(rc);
|
1990 |
} |
1991 |
#endif
|
1992 |
// Not found. Fetch from prototype.
|
1993 |
info.GetReturnValue().Set( |
1994 |
info.Data().As<Object>()->Get(property)); |
1995 |
} |
1996 |
|
1997 |
|
1998 |
static void EnvSetter(Local<String> property, |
1999 |
Local<Value> value, |
2000 |
const PropertyCallbackInfo<Value>& info) {
|
2001 |
HandleScope scope(node_isolate); |
2002 |
#ifdef __POSIX__
|
2003 |
String::Utf8Value key(property); |
2004 |
String::Utf8Value val(value); |
2005 |
setenv(*key, *val, 1);
|
2006 |
#else // _WIN32 |
2007 |
String::Value key(property); |
2008 |
String::Value val(value); |
2009 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
|
2010 |
// Environment variables that start with '=' are read-only.
|
2011 |
if (key_ptr[0] != L'=') { |
2012 |
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
|
2013 |
} |
2014 |
#endif
|
2015 |
// Whether it worked or not, always return rval.
|
2016 |
info.GetReturnValue().Set(value); |
2017 |
} |
2018 |
|
2019 |
|
2020 |
static void EnvQuery(Local<String> property, |
2021 |
const PropertyCallbackInfo<Integer>& info) {
|
2022 |
HandleScope scope(node_isolate); |
2023 |
int32_t rc = -1; // Not found unless proven otherwise. |
2024 |
#ifdef __POSIX__
|
2025 |
String::Utf8Value key(property); |
2026 |
if (getenv(*key))
|
2027 |
rc = 0;
|
2028 |
#else // _WIN32 |
2029 |
String::Value key(property); |
2030 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
|
2031 |
if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 || |
2032 |
GetLastError() == ERROR_SUCCESS) { |
2033 |
rc = 0;
|
2034 |
if (key_ptr[0] == L'=') { |
2035 |
// Environment variables that start with '=' are hidden and read-only.
|
2036 |
rc = static_cast<int32_t>(v8::ReadOnly) |
|
2037 |
static_cast<int32_t>(v8::DontDelete) |
|
2038 |
static_cast<int32_t>(v8::DontEnum);
|
2039 |
} |
2040 |
} |
2041 |
#endif
|
2042 |
if (rc != -1) |
2043 |
info.GetReturnValue().Set(rc); |
2044 |
} |
2045 |
|
2046 |
|
2047 |
static void EnvDeleter(Local<String> property, |
2048 |
const PropertyCallbackInfo<Boolean>& info) {
|
2049 |
HandleScope scope(node_isolate); |
2050 |
bool rc = true; |
2051 |
#ifdef __POSIX__
|
2052 |
String::Utf8Value key(property); |
2053 |
rc = getenv(*key) != NULL;
|
2054 |
if (rc)
|
2055 |
unsetenv(*key); |
2056 |
#else
|
2057 |
String::Value key(property); |
2058 |
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
|
2059 |
if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) { |
2060 |
// Deletion failed. Return true if the key wasn't there in the first place,
|
2061 |
// false if it is still there.
|
2062 |
rc = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 && |
2063 |
GetLastError() != ERROR_SUCCESS; |
2064 |
} |
2065 |
#endif
|
2066 |
info.GetReturnValue().Set(rc); |
2067 |
} |
2068 |
|
2069 |
|
2070 |
static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) { |
2071 |
HandleScope scope(node_isolate); |
2072 |
#ifdef __POSIX__
|
2073 |
int size = 0; |
2074 |
while (environ[size])
|
2075 |
size++; |
2076 |
|
2077 |
Local<Array> env = Array::New(size); |
2078 |
|
2079 |
for (int i = 0; i < size; ++i) { |
2080 |
const char* var = environ[i]; |
2081 |
const char* s = strchr(var, '='); |
2082 |
const int length = s ? s - var : strlen(var); |
2083 |
Local<String> name = String::NewFromUtf8(node_isolate, |
2084 |
var, |
2085 |
String::kNormalString, |
2086 |
length); |
2087 |
env->Set(i, name); |
2088 |
} |
2089 |
#else // _WIN32 |
2090 |
WCHAR* environment = GetEnvironmentStringsW(); |
2091 |
if (environment == NULL) |
2092 |
return; // This should not happen. |
2093 |
Local<Array> env = Array::New(); |
2094 |
WCHAR* p = environment; |
2095 |
int i = 0; |
2096 |
while (*p != NULL) { |
2097 |
WCHAR *s; |
2098 |
if (*p == L'=') { |
2099 |
// If the key starts with '=' it is a hidden environment variable.
|
2100 |
p += wcslen(p) + 1;
|
2101 |
continue;
|
2102 |
} else {
|
2103 |
s = wcschr(p, L'=');
|
2104 |
} |
2105 |
if (!s) {
|
2106 |
s = p + wcslen(p); |
2107 |
} |
2108 |
const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p); |
2109 |
const size_t two_byte_buffer_len = s - p;
|
2110 |
Local<String> value = String::NewFromTwoByte(node_isolate, |
2111 |
two_byte_buffer, |
2112 |
String::kNormalString, |
2113 |
two_byte_buffer_len); |
2114 |
env->Set(i++, value); |
2115 |
p = s + wcslen(s) + 1;
|
2116 |
} |
2117 |
FreeEnvironmentStringsW(environment); |
2118 |
#endif
|
2119 |
|
2120 |
info.GetReturnValue().Set(env); |
2121 |
} |
2122 |
|
2123 |
|
2124 |
static Handle<Object> GetFeatures() {
|
2125 |
HandleScope scope(node_isolate); |
2126 |
|
2127 |
Local<Object> obj = Object::New(); |
2128 |
#if defined(DEBUG) && DEBUG
|
2129 |
Local<Value> debug = True(node_isolate); |
2130 |
#else
|
2131 |
Local<Value> debug = False(node_isolate); |
2132 |
#endif // defined(DEBUG) && DEBUG |
2133 |
|
2134 |
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "debug"), debug);
|
2135 |
|
2136 |
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "uv"), True(node_isolate));
|
2137 |
// TODO(bnoordhuis) ping libuv
|
2138 |
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "ipv6"), True(node_isolate));
|
2139 |
|
2140 |
#ifdef OPENSSL_NPN_NEGOTIATED
|
2141 |
Local<Boolean> tls_npn = True(node_isolate); |
2142 |
#else
|
2143 |
Local<Boolean> tls_npn = False(node_isolate); |
2144 |
#endif
|
2145 |
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "tls_npn"), tls_npn);
|
2146 |
|
2147 |
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
2148 |
Local<Boolean> tls_sni = True(node_isolate); |
2149 |
#else
|
2150 |
Local<Boolean> tls_sni = False(node_isolate); |
2151 |
#endif
|
2152 |
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "tls_sni"), tls_sni);
|
2153 |
|
2154 |
obj->Set(FIXED_ONE_BYTE_STRING(node_isolate, "tls"),
|
2155 |
Boolean::New(get_builtin_module("crypto") != NULL)); |
2156 |
|
2157 |
return scope.Close(obj);
|
2158 |
} |
2159 |
|
2160 |
|
2161 |
static void DebugPortGetter(Local<String> property, |
2162 |
const PropertyCallbackInfo<Value>& info) {
|
2163 |
HandleScope scope(node_isolate); |
2164 |
info.GetReturnValue().Set(debug_port); |
2165 |
} |
2166 |
|
2167 |
|
2168 |
static void DebugPortSetter(Local<String> property, |
2169 |
Local<Value> value, |
2170 |
const PropertyCallbackInfo<void>& info) { |
2171 |
HandleScope scope(node_isolate); |
2172 |
debug_port = value->NumberValue(); |
2173 |
} |
2174 |
|
2175 |
|
2176 |
static void DebugProcess(const FunctionCallbackInfo<Value>& args); |
2177 |
static void DebugPause(const FunctionCallbackInfo<Value>& args); |
2178 |
static void DebugEnd(const FunctionCallbackInfo<Value>& args); |
2179 |
|
2180 |
|
2181 |
void NeedImmediateCallbackGetter(Local<String> property,
|
2182 |
const PropertyCallbackInfo<Value>& info) {
|
2183 |
Environment* env = Environment::GetCurrent(info.GetIsolate()); |
2184 |
const uv_check_t* immediate_check_handle = env->immediate_check_handle();
|
2185 |
bool active = uv_is_active(
|
2186 |
reinterpret_cast<const uv_handle_t*>(immediate_check_handle)); |
2187 |
info.GetReturnValue().Set(active); |
2188 |
} |
2189 |
|
2190 |
|
2191 |
static void NeedImmediateCallbackSetter( |
2192 |
Local<String> property, |
2193 |
Local<Value> value, |
2194 |
const PropertyCallbackInfo<void>& info) { |
2195 |
Environment* env = Environment::GetCurrent(info.GetIsolate()); |
2196 |
HandleScope handle_scope(info.GetIsolate()); |
2197 |
|
2198 |
uv_check_t* immediate_check_handle = env->immediate_check_handle(); |
2199 |
bool active = uv_is_active(
|
2200 |
reinterpret_cast<const uv_handle_t*>(immediate_check_handle)); |
2201 |
|
2202 |
if (active == value->BooleanValue())
|
2203 |
return;
|
2204 |
|
2205 |
uv_idle_t* immediate_idle_handle = env->immediate_idle_handle(); |
2206 |
|
2207 |
if (active) {
|
2208 |
uv_check_stop(immediate_check_handle); |
2209 |
uv_idle_stop(immediate_idle_handle); |
2210 |
} else {
|
2211 |
uv_check_start(immediate_check_handle, CheckImmediate); |
2212 |
// Idle handle is needed only to stop the event loop from blocking in poll.
|
2213 |
uv_idle_start(immediate_idle_handle, IdleImmediateDummy); |
2214 |
} |
2215 |
} |
2216 |
|
2217 |
|
2218 |
void SetIdle(uv_prepare_t* handle, int) { |
2219 |
Environment* env = Environment::from_idle_prepare_handle(handle); |
2220 |
env->isolate()->GetCpuProfiler()->SetIdle(true);
|
2221 |
} |
2222 |
|
2223 |
|
2224 |
void ClearIdle(uv_check_t* handle, int) { |
2225 |
Environment* env = Environment::from_idle_check_handle(handle); |
2226 |
env->isolate()->GetCpuProfiler()->SetIdle(false);
|
2227 |
} |
2228 |
|
2229 |
|
2230 |
void StartProfilerIdleNotifier(Environment* env) {
|
2231 |
uv_prepare_start(env->idle_prepare_handle(), SetIdle); |
2232 |
uv_check_start(env->idle_check_handle(), ClearIdle); |
2233 |
} |
2234 |
|
2235 |
|
2236 |
void StopProfilerIdleNotifier(Environment* env) {
|
2237 |
uv_prepare_stop(env->idle_prepare_handle()); |
2238 |
uv_check_stop(env->idle_check_handle()); |
2239 |
} |
2240 |
|
2241 |
|
2242 |
void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) { |
2243 |
StartProfilerIdleNotifier(Environment::GetCurrent(args.GetIsolate())); |
2244 |
} |
2245 |
|
2246 |
|
2247 |
void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) { |
2248 |
StopProfilerIdleNotifier(Environment::GetCurrent(args.GetIsolate())); |
2249 |
} |
2250 |
|
2251 |
|
2252 |
#define READONLY_PROPERTY(obj, str, var) \
|
2253 |
do { \
|
2254 |
obj->Set(OneByteString(node_isolate, str), var, v8::ReadOnly); \ |
2255 |
} while (0) |
2256 |
|
2257 |
|
2258 |
void SetupProcessObject(Environment* env,
|
2259 |
int argc,
|
2260 |
const char* const* argv, |
2261 |
int exec_argc,
|
2262 |
const char* const* exec_argv) { |
2263 |
HandleScope scope(node_isolate); |
2264 |
|
2265 |
Local<Object> process = env->process_object(); |
2266 |
|
2267 |
process->SetAccessor(FIXED_ONE_BYTE_STRING(node_isolate, "title"),
|
2268 |
ProcessTitleGetter, |
2269 |
ProcessTitleSetter); |
2270 |
|
2271 |
// process.version
|
2272 |
READONLY_PROPERTY(process, |
2273 |
"version",
|
2274 |
FIXED_ONE_BYTE_STRING(node_isolate, NODE_VERSION)); |
2275 |
|
2276 |
// process.moduleLoadList
|
2277 |
READONLY_PROPERTY(process, |
2278 |
"moduleLoadList",
|
2279 |
env->module_load_list_array()); |
2280 |
|
2281 |
// process.versions
|
2282 |
Local<Object> versions = Object::New(); |
2283 |
READONLY_PROPERTY(process, "versions", versions);
|
2284 |
|
2285 |
const char http_parser_version[] = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) |
2286 |
"."
|
2287 |
NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR); |
2288 |
READONLY_PROPERTY(versions, |
2289 |
"http_parser",
|
2290 |
FIXED_ONE_BYTE_STRING(node_isolate, http_parser_version)); |
2291 |
|
2292 |
// +1 to get rid of the leading 'v'
|
2293 |
READONLY_PROPERTY(versions, |
2294 |
"node",
|
2295 |
OneByteString(node_isolate, NODE_VERSION + 1));
|
2296 |
READONLY_PROPERTY(versions, |
2297 |
"v8",
|
2298 |
OneByteString(node_isolate, V8::GetVersion())); |
2299 |
READONLY_PROPERTY(versions, |
2300 |
"uv",
|
2301 |
OneByteString(node_isolate, uv_version_string())); |
2302 |
READONLY_PROPERTY(versions, |
2303 |
"zlib",
|
2304 |
FIXED_ONE_BYTE_STRING(node_isolate, ZLIB_VERSION)); |
2305 |
|
2306 |
const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION); |
2307 |
READONLY_PROPERTY(versions, |
2308 |
"modules",
|
2309 |
FIXED_ONE_BYTE_STRING(node_isolate, node_modules_version)); |
2310 |
|
2311 |
#if HAVE_OPENSSL
|
2312 |
// Stupid code to slice out the version string.
|
2313 |
{ // NOLINT(whitespace/braces)
|
2314 |
size_t i, j, k; |
2315 |
int c;
|
2316 |
for (i = j = 0, k = sizeof(OPENSSL_VERSION_TEXT) - 1; i < k; ++i) { |
2317 |
c = OPENSSL_VERSION_TEXT[i]; |
2318 |
if ('0' <= c && c <= '9') { |
2319 |
for (j = i + 1; j < k; ++j) { |
2320 |
c = OPENSSL_VERSION_TEXT[j]; |
2321 |
if (c == ' ') |
2322 |
break;
|
2323 |
} |
2324 |
break;
|
2325 |
} |
2326 |
} |
2327 |
READONLY_PROPERTY( |
2328 |
versions, |
2329 |
"openssl",
|
2330 |
OneByteString(node_isolate, &OPENSSL_VERSION_TEXT[i], j - i)); |
2331 |
} |
2332 |
#endif
|
2333 |
|
2334 |
// process.arch
|
2335 |
READONLY_PROPERTY(process, "arch", OneByteString(node_isolate, ARCH));
|
2336 |
|
2337 |
// process.platform
|
2338 |
READONLY_PROPERTY(process, |
2339 |
"platform",
|
2340 |
OneByteString(node_isolate, PLATFORM)); |
2341 |
|
2342 |
// process.argv
|
2343 |
Local<Array> arguments = Array::New(argc); |
2344 |
for (int i = 0; i < argc; ++i) { |
2345 |
arguments->Set(i, String::NewFromUtf8(node_isolate, argv[i])); |
2346 |
} |
2347 |
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "argv"), arguments);
|
2348 |
|
2349 |
// process.execArgv
|
2350 |
Local<Array> exec_arguments = Array::New(exec_argc); |
2351 |
for (int i = 0; i < exec_argc; ++i) { |
2352 |
exec_arguments->Set(i, String::NewFromUtf8(node_isolate, exec_argv[i])); |
2353 |
} |
2354 |
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "execArgv"), exec_arguments);
|
2355 |
|
2356 |
// create process.env
|
2357 |
Local<ObjectTemplate> process_env_template = ObjectTemplate::New(); |
2358 |
process_env_template->SetNamedPropertyHandler(EnvGetter, |
2359 |
EnvSetter, |
2360 |
EnvQuery, |
2361 |
EnvDeleter, |
2362 |
EnvEnumerator, |
2363 |
Object::New()); |
2364 |
Local<Object> process_env = process_env_template->NewInstance(); |
2365 |
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "env"), process_env);
|
2366 |
|
2367 |
READONLY_PROPERTY(process, "pid", Integer::New(getpid(), node_isolate));
|
2368 |
READONLY_PROPERTY(process, "features", GetFeatures());
|
2369 |
process->SetAccessor( |
2370 |
FIXED_ONE_BYTE_STRING(node_isolate, "_needImmediateCallback"),
|
2371 |
NeedImmediateCallbackGetter, |
2372 |
NeedImmediateCallbackSetter); |
2373 |
|
2374 |
// -e, --eval
|
2375 |
if (eval_string) {
|
2376 |
READONLY_PROPERTY(process, |
2377 |
"_eval",
|
2378 |
String::NewFromUtf8(node_isolate, eval_string)); |
2379 |
} |
2380 |
|
2381 |
// -p, --print
|
2382 |
if (print_eval) {
|
2383 |
READONLY_PROPERTY(process, "_print_eval", True(node_isolate));
|
2384 |
} |
2385 |
|
2386 |
// -i, --interactive
|
2387 |
if (force_repl) {
|
2388 |
READONLY_PROPERTY(process, "_forceRepl", True(node_isolate));
|
2389 |
} |
2390 |
|
2391 |
// --no-deprecation
|
2392 |
if (no_deprecation) {
|
2393 |
READONLY_PROPERTY(process, "noDeprecation", True(node_isolate));
|
2394 |
} |
2395 |
|
2396 |
// --throw-deprecation
|
2397 |
if (throw_deprecation) {
|
2398 |
READONLY_PROPERTY(process, "throwDeprecation", True(node_isolate));
|
2399 |
} |
2400 |
|
2401 |
// --trace-deprecation
|
2402 |
if (trace_deprecation) {
|
2403 |
READONLY_PROPERTY(process, "traceDeprecation", True(node_isolate));
|
2404 |
} |
2405 |
|
2406 |
size_t exec_path_len = 2 * PATH_MAX;
|
2407 |
char* exec_path = new char[exec_path_len]; |
2408 |
Local<String> exec_path_value; |
2409 |
if (uv_exepath(exec_path, &exec_path_len) == 0) { |
2410 |
exec_path_value = String::NewFromUtf8(node_isolate, |
2411 |
exec_path, |
2412 |
String::kNormalString, |
2413 |
exec_path_len); |
2414 |
} else {
|
2415 |
exec_path_value = String::NewFromUtf8(node_isolate, argv[0]);
|
2416 |
} |
2417 |
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "execPath"),
|
2418 |
exec_path_value); |
2419 |
delete[] exec_path;
|
2420 |
|
2421 |
process->SetAccessor(FIXED_ONE_BYTE_STRING(node_isolate, "debugPort"),
|
2422 |
DebugPortGetter, |
2423 |
DebugPortSetter); |
2424 |
|
2425 |
// define various internal methods
|
2426 |
NODE_SET_METHOD(process, |
2427 |
"_startProfilerIdleNotifier",
|
2428 |
StartProfilerIdleNotifier); |
2429 |
NODE_SET_METHOD(process, |
2430 |
"_stopProfilerIdleNotifier",
|
2431 |
StopProfilerIdleNotifier); |
2432 |
NODE_SET_METHOD(process, "_getActiveRequests", GetActiveRequests);
|
2433 |
NODE_SET_METHOD(process, "_getActiveHandles", GetActiveHandles);
|
2434 |
NODE_SET_METHOD(process, "reallyExit", Exit);
|
2435 |
NODE_SET_METHOD(process, "abort", Abort);
|
2436 |
NODE_SET_METHOD(process, "chdir", Chdir);
|
2437 |
NODE_SET_METHOD(process, "cwd", Cwd);
|
2438 |
|
2439 |
NODE_SET_METHOD(process, "umask", Umask);
|
2440 |
|
2441 |
#if defined(__POSIX__) && !defined(__ANDROID__)
|
2442 |
NODE_SET_METHOD(process, "getuid", GetUid);
|
2443 |
NODE_SET_METHOD(process, "setuid", SetUid);
|
2444 |
|
2445 |
NODE_SET_METHOD(process, "setgid", SetGid);
|
2446 |
NODE_SET_METHOD(process, "getgid", GetGid);
|
2447 |
|
2448 |
NODE_SET_METHOD(process, "getgroups", GetGroups);
|
2449 |
NODE_SET_METHOD(process, "setgroups", SetGroups);
|
2450 |
NODE_SET_METHOD(process, "initgroups", InitGroups);
|
2451 |
#endif // __POSIX__ && !defined(__ANDROID__) |
2452 |
|
2453 |
NODE_SET_METHOD(process, "_kill", Kill);
|
2454 |
|
2455 |
NODE_SET_METHOD(process, "_debugProcess", DebugProcess);
|
2456 |
NODE_SET_METHOD(process, "_debugPause", DebugPause);
|
2457 |
NODE_SET_METHOD(process, "_debugEnd", DebugEnd);
|
2458 |
|
2459 |
NODE_SET_METHOD(process, "hrtime", Hrtime);
|
2460 |
|
2461 |
NODE_SET_METHOD(process, "dlopen", DLOpen);
|
2462 |
|
2463 |
NODE_SET_METHOD(process, "uptime", Uptime);
|
2464 |
NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
|
2465 |
|
2466 |
NODE_SET_METHOD(process, "binding", Binding);
|
2467 |
|
2468 |
NODE_SET_METHOD(process, "_setupAsyncListener", SetupAsyncListener);
|
2469 |
NODE_SET_METHOD(process, "_setupNextTick", SetupNextTick);
|
2470 |
|
2471 |
// values use to cross communicate with processNextTick
|
2472 |
Local<Object> tick_info_obj = Object::New(); |
2473 |
tick_info_obj->SetIndexedPropertiesToExternalArrayData( |
2474 |
env->tick_info()->fields(), |
2475 |
kExternalUnsignedIntArray, |
2476 |
env->tick_info()->fields_count()); |
2477 |
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_tickInfo"), tick_info_obj);
|
2478 |
|
2479 |
// pre-set _events object for faster emit checks
|
2480 |
process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_events"), Object::New());
|
2481 |
} |
2482 |
|
2483 |
|
2484 |
#undef READONLY_PROPERTY
|
2485 |
|
2486 |
|
2487 |
static void AtExit() { |
2488 |
uv_tty_reset_mode(); |
2489 |
} |
2490 |
|
2491 |
|
2492 |
static void SignalExit(int signal) { |
2493 |
uv_tty_reset_mode(); |
2494 |
_exit(128 + signal);
|
2495 |
} |
2496 |
|
2497 |
|
2498 |
// Most of the time, it's best to use `console.error` to write
|
2499 |
// to the process.stderr stream. However, in some cases, such as
|
2500 |
// when debugging the stream.Writable class or the process.nextTick
|
2501 |
// function, it is useful to bypass JavaScript entirely.
|
2502 |
static void RawDebug(const FunctionCallbackInfo<Value>& args) { |
2503 |
HandleScope scope(node_isolate); |
2504 |
|
2505 |
assert(args.Length() == 1 && args[0]->IsString() && |
2506 |
"must be called with a single string");
|
2507 |
|
2508 |
String::Utf8Value message(args[0]);
|
2509 |
fprintf(stderr, "%s\n", *message);
|
2510 |
fflush(stderr); |
2511 |
} |
2512 |
|
2513 |
|
2514 |
void Load(Environment* env) {
|
2515 |
HandleScope handle_scope(node_isolate); |
2516 |
|
2517 |
// Compile, execute the src/node.js file. (Which was included as static C
|
2518 |
// string in node_natives.h. 'natve_node' is the string containing that
|
2519 |
// source code.)
|
2520 |
|
2521 |
// The node.js file returns a function 'f'
|
2522 |
atexit(AtExit); |
2523 |
|
2524 |
TryCatch try_catch; |
2525 |
|
2526 |
// Disable verbose mode to stop FatalException() handler from trying
|
2527 |
// to handle the exception. Errors this early in the start-up phase
|
2528 |
// are not safe to ignore.
|
2529 |
try_catch.SetVerbose(false);
|
2530 |
|
2531 |
Local<String> script_name = FIXED_ONE_BYTE_STRING(node_isolate, "node.js");
|
2532 |
Local<Value> f_value = ExecuteString(MainSource(), script_name); |
2533 |
if (try_catch.HasCaught()) {
|
2534 |
ReportException(try_catch); |
2535 |
exit(10);
|
2536 |
} |
2537 |
assert(f_value->IsFunction()); |
2538 |
Local<Function> f = Local<Function>::Cast(f_value); |
2539 |
|
2540 |
// Now we call 'f' with the 'process' variable that we've built up with
|
2541 |
// all our bindings. Inside node.js we'll take care of assigning things to
|
2542 |
// their places.
|
2543 |
|
2544 |
// We start the process this way in order to be more modular. Developers
|
2545 |
// who do not like how 'src/node.js' setups the module system but do like
|
2546 |
// Node's I/O bindings may want to replace 'f' with their own function.
|
2547 |
|
2548 |
// Add a reference to the global object
|
2549 |
Local<Object> global = env->context()->Global(); |
2550 |
|
2551 |
#if defined HAVE_DTRACE || defined HAVE_ETW
|
2552 |
InitDTrace(global); |
2553 |
#endif
|
2554 |
|
2555 |
#if defined HAVE_PERFCTR
|
2556 |
InitPerfCounters(global); |
2557 |
#endif
|
2558 |
|
2559 |
// Enable handling of uncaught exceptions
|
2560 |
// (FatalException(), break on uncaught exception in debugger)
|
2561 |
//
|
2562 |
// This is not strictly necessary since it's almost impossible
|
2563 |
// to attach the debugger fast enought to break on exception
|
2564 |
// thrown during process startup.
|
2565 |
try_catch.SetVerbose(true);
|
2566 |
|
2567 |
NODE_SET_METHOD(env->process_object(), "_rawDebug", RawDebug);
|
2568 |
|
2569 |
Local<Value> arg = env->process_object(); |
2570 |
f->Call(global, 1, &arg);
|
2571 |
} |
2572 |
|
2573 |
static void PrintHelp(); |
2574 |
|
2575 |
static void ParseDebugOpt(const char* arg) { |
2576 |
const char *p = 0; |
2577 |
|
2578 |
if (strstr(arg, "--debug-port=") == arg) { |
2579 |
p = 1 + strchr(arg, '='); |
2580 |
debug_port = atoi(p); |
2581 |
} else {
|
2582 |
use_debug_agent = true;
|
2583 |
if (!strcmp(arg, "--debug-brk")) { |
2584 |
debug_wait_connect = true;
|
2585 |
return;
|
2586 |
} else if (!strcmp(arg, "--debug")) { |
2587 |
return;
|
2588 |
} else if (strstr(arg, "--debug-brk=") == arg) { |
2589 |
debug_wait_connect = true;
|
2590 |
p = 1 + strchr(arg, '='); |
2591 |
debug_port = atoi(p); |
2592 |
} else if (strstr(arg, "--debug=") == arg) { |
2593 |
p = 1 + strchr(arg, '='); |
2594 |
debug_port = atoi(p); |
2595 |
} |
2596 |
} |
2597 |
if (p && debug_port > 1024 && debug_port < 65536) |
2598 |
return;
|
2599 |
|
2600 |
fprintf(stderr, "Bad debug option.\n");
|
2601 |
if (p)
|
2602 |
fprintf(stderr, "Debug port must be in range 1025 to 65535.\n");
|
2603 |
|
2604 |
PrintHelp(); |
2605 |
exit(12);
|
2606 |
} |
2607 |
|
2608 |
static void PrintHelp() { |
2609 |
printf("Usage: node [options] [ -e script | script.js ] [arguments] \n"
|
2610 |
" node debug script.js [arguments] \n"
|
2611 |
"\n"
|
2612 |
"Options:\n"
|
2613 |
" -v, --version print node's version\n"
|
2614 |
" -e, --eval script evaluate script\n"
|
2615 |
" -p, --print evaluate script and print result\n"
|
2616 |
" -i, --interactive always enter the REPL even if stdin\n"
|
2617 |
" does not appear to be a terminal\n"
|
2618 |
" --no-deprecation silence deprecation warnings\n"
|
2619 |
" --trace-deprecation show stack traces on deprecations\n"
|
2620 |
" --v8-options print v8 command line options\n"
|
2621 |
" --max-stack-size=val set max v8 stack size (bytes)\n"
|
2622 |
"\n"
|
2623 |
"Environment variables:\n"
|
2624 |
#ifdef _WIN32
|
2625 |
"NODE_PATH ';'-separated list of directories\n"
|
2626 |
#else
|
2627 |
"NODE_PATH ':'-separated list of directories\n"
|
2628 |
#endif
|
2629 |
" prefixed to the module search path.\n"
|
2630 |
"NODE_MODULE_CONTEXTS Set to 1 to load modules in their own\n"
|
2631 |
" global contexts.\n"
|
2632 |
"NODE_DISABLE_COLORS Set to 1 to disable colors in the REPL\n"
|
2633 |
"\n"
|
2634 |
"Documentation can be found at http://nodejs.org/\n");
|
2635 |
} |
2636 |
|
2637 |
|
2638 |
// Parse command line arguments.
|
2639 |
//
|
2640 |
// argv is modified in place. exec_argv and v8_argv are out arguments that
|
2641 |
// ParseArgs() allocates memory for and stores a pointer to the output
|
2642 |
// vector in. The caller should free them with delete[].
|
2643 |
//
|
2644 |
// On exit:
|
2645 |
//
|
2646 |
// * argv contains the arguments with node and V8 options filtered out.
|
2647 |
// * exec_argv contains both node and V8 options and nothing else.
|
2648 |
// * v8_argv contains argv[0] plus any V8 options
|
2649 |
static void ParseArgs(int* argc, |
2650 |
const char** argv, |
2651 |
int* exec_argc,
|
2652 |
const char*** exec_argv, |
2653 |
int* v8_argc,
|
2654 |
const char*** v8_argv) { |
2655 |
const unsigned int nargs = static_cast<unsigned int>(*argc); |
2656 |
const char** new_exec_argv = new const char*[nargs]; |
2657 |
const char** new_v8_argv = new const char*[nargs]; |
2658 |
const char** new_argv = new const char*[nargs]; |
2659 |
|
2660 |
for (unsigned int i = 0; i < nargs; ++i) { |
2661 |
new_exec_argv[i] = NULL;
|
2662 |
new_v8_argv[i] = NULL;
|
2663 |
new_argv[i] = NULL;
|
2664 |
} |
2665 |
|
2666 |
// exec_argv starts with the first option, the other two start with argv[0].
|
2667 |
unsigned int new_exec_argc = 0; |
2668 |
unsigned int new_v8_argc = 1; |
2669 |
unsigned int new_argc = 1; |
2670 |
new_v8_argv[0] = argv[0]; |
2671 |
new_argv[0] = argv[0]; |
2672 |
|
2673 |
unsigned int index = 1; |
2674 |
while (index < nargs && argv[index][0] == '-') { |
2675 |
const char* const arg = argv[index]; |
2676 |
unsigned int args_consumed = 1; |
2677 |
|
2678 |
if (strstr(arg, "--debug") == arg) { |
2679 |
ParseDebugOpt(arg); |
2680 |
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) { |
2681 |
printf("%s\n", NODE_VERSION);
|
2682 |
exit(0);
|
2683 |
} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) { |
2684 |
PrintHelp(); |
2685 |
exit(0);
|
2686 |
} else if (strcmp(arg, "--eval") == 0 || |
2687 |
strcmp(arg, "-e") == 0 || |
2688 |
strcmp(arg, "--print") == 0 || |
2689 |
strcmp(arg, "-pe") == 0 || |
2690 |
strcmp(arg, "-p") == 0) { |
2691 |
bool is_eval = strchr(arg, 'e') != NULL; |
2692 |
bool is_print = strchr(arg, 'p') != NULL; |
2693 |
print_eval = print_eval || is_print; |
2694 |
// --eval, -e and -pe always require an argument.
|
2695 |
if (is_eval == true) { |
2696 |
args_consumed += 1;
|
2697 |
eval_string = argv[index + 1];
|
2698 |
if (eval_string == NULL) { |
2699 |
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg); |
2700 |
exit(9);
|
2701 |
} |
2702 |
} else if (argv[index + 1] != NULL && argv[index + 1][0] != '-') { |
2703 |
args_consumed += 1;
|
2704 |
eval_string = argv[index + 1];
|
2705 |
if (strncmp(eval_string, "\\-", 2) == 0) { |
2706 |
// Starts with "\\-": escaped expression, drop the backslash.
|
2707 |
eval_string += 1;
|
2708 |
} |
2709 |
} |
2710 |
} else if (strcmp(arg, "--interactive") == 0 || strcmp(arg, "-i") == 0) { |
2711 |
force_repl = true;
|
2712 |
} else if (strcmp(arg, "--no-deprecation") == 0) { |
2713 |
no_deprecation = true;
|
2714 |
} else if (strcmp(arg, "--trace-deprecation") == 0) { |
2715 |
trace_deprecation = true;
|
2716 |
} else if (strcmp(arg, "--throw-deprecation") == 0) { |
2717 |
throw_deprecation = true;
|
2718 |
} else if (strcmp(arg, "--v8-options") == 0) { |
2719 |
new_v8_argv[new_v8_argc] = "--help";
|
2720 |
new_v8_argc += 1;
|
2721 |
} else {
|
2722 |
// V8 option. Pass through as-is.
|
2723 |
new_v8_argv[new_v8_argc] = arg; |
2724 |
new_v8_argc += 1;
|
2725 |
} |
2726 |
|
2727 |
memcpy(new_exec_argv + new_exec_argc, |
2728 |
argv + index, |
2729 |
args_consumed * sizeof(*argv));
|
2730 |
|
2731 |
new_exec_argc += args_consumed; |
2732 |
index += args_consumed; |
2733 |
} |
2734 |
|
2735 |
// Copy remaining arguments.
|
2736 |
const unsigned int args_left = nargs - index; |
2737 |
memcpy(new_argv + new_argc, argv + index, args_left * sizeof(*argv));
|
2738 |
new_argc += args_left; |
2739 |
|
2740 |
*exec_argc = new_exec_argc; |
2741 |
*exec_argv = new_exec_argv; |
2742 |
*v8_argc = new_v8_argc; |
2743 |
*v8_argv = new_v8_argv; |
2744 |
|
2745 |
// Copy new_argv over argv and update argc.
|
2746 |
memcpy(argv, new_argv, new_argc * sizeof(*argv));
|
2747 |
delete[] new_argv;
|
2748 |
*argc = static_cast<int>(new_argc); |
2749 |
} |
2750 |
|
2751 |
|
2752 |
// Called from V8 Debug Agent TCP thread.
|
2753 |
static void DispatchMessagesDebugAgentCallback() { |
2754 |
uv_async_send(&dispatch_debug_messages_async); |
2755 |
} |
2756 |
|
2757 |
|
2758 |
// Called from the main thread.
|
2759 |
static void EnableDebug(bool wait_connect) { |
2760 |
assert(debugger_running == false);
|
2761 |
Isolate* isolate = node_isolate; // TODO(bnoordhuis) Multi-isolate support.
|
2762 |
Isolate::Scope isolate_scope(isolate); |
2763 |
v8::Debug::SetDebugMessageDispatchHandler(DispatchMessagesDebugAgentCallback, |
2764 |
false);
|
2765 |
debugger_running = v8::Debug::EnableAgent("node " NODE_VERSION,
|
2766 |
debug_port, |
2767 |
wait_connect); |
2768 |
if (debugger_running == false) { |
2769 |
fprintf(stderr, "Starting debugger on port %d failed\n", debug_port);
|
2770 |
fflush(stderr); |
2771 |
return;
|
2772 |
} |
2773 |
fprintf(stderr, "Debugger listening on port %d\n", debug_port);
|
2774 |
fflush(stderr); |
2775 |
|
2776 |
Environment* env = Environment::GetCurrentChecked(isolate); |
2777 |
if (env == NULL) |
2778 |
return; // Still starting up. |
2779 |
|
2780 |
Context::Scope context_scope(env->context()); |
2781 |
HandleScope handle_scope(env->isolate()); |
2782 |
Local<Object> message = Object::New(); |
2783 |
message->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "cmd"),
|
2784 |
FIXED_ONE_BYTE_STRING(env->isolate(), "NODE_DEBUG_ENABLED"));
|
2785 |
Local<Value> argv[] = { |
2786 |
FIXED_ONE_BYTE_STRING(env->isolate(), "internalMessage"),
|
2787 |
message |
2788 |
}; |
2789 |
MakeCallback(env, env->process_object(), "emit", ARRAY_SIZE(argv), argv);
|
2790 |
} |
2791 |
|
2792 |
|
2793 |
// Called from the main thread.
|
2794 |
static void DispatchDebugMessagesAsyncCallback(uv_async_t* handle, int status) { |
2795 |
if (debugger_running == false) { |
2796 |
fprintf(stderr, "Starting debugger agent.\n");
|
2797 |
EnableDebug(false);
|
2798 |
} |
2799 |
Isolate::Scope isolate_scope(node_isolate); |
2800 |
v8::Debug::ProcessDebugMessages(); |
2801 |
} |
2802 |
|
2803 |
|
2804 |
#ifdef __POSIX__
|
2805 |
static volatile sig_atomic_t caught_early_debug_signal; |
2806 |
|
2807 |
|
2808 |
static void EarlyDebugSignalHandler(int signo) { |
2809 |
caught_early_debug_signal = 1;
|
2810 |
} |
2811 |
|
2812 |
|
2813 |
static void InstallEarlyDebugSignalHandler() { |
2814 |
struct sigaction sa;
|
2815 |
memset(&sa, 0, sizeof(sa)); |
2816 |
sa.sa_handler = EarlyDebugSignalHandler; |
2817 |
sigaction(SIGUSR1, &sa, NULL);
|
2818 |
} |
2819 |
|
2820 |
|
2821 |
static void EnableDebugSignalHandler(int signo) { |
2822 |
// Call only async signal-safe functions here!
|
2823 |
v8::Debug::DebugBreak(*static_cast<Isolate* volatile*>(&node_isolate)); |
2824 |
uv_async_send(&dispatch_debug_messages_async); |
2825 |
} |
2826 |
|
2827 |
|
2828 |
static void RegisterSignalHandler(int signal, void (*handler)(int signal)) { |
2829 |
struct sigaction sa;
|
2830 |
memset(&sa, 0, sizeof(sa)); |
2831 |
sa.sa_handler = handler; |
2832 |
sigfillset(&sa.sa_mask); |
2833 |
sigaction(signal, &sa, NULL);
|
2834 |
} |
2835 |
|
2836 |
|
2837 |
void DebugProcess(const FunctionCallbackInfo<Value>& args) { |
2838 |
HandleScope scope(node_isolate); |
2839 |
|
2840 |
if (args.Length() != 1) { |
2841 |
return ThrowError("Invalid number of arguments."); |
2842 |
} |
2843 |
|
2844 |
pid_t pid; |
2845 |
int r;
|
2846 |
|
2847 |
pid = args[0]->IntegerValue();
|
2848 |
r = kill(pid, SIGUSR1); |
2849 |
if (r != 0) { |
2850 |
return ThrowErrnoException(errno, "kill"); |
2851 |
} |
2852 |
} |
2853 |
|
2854 |
|
2855 |
static int RegisterDebugSignalHandler() { |
2856 |
// FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
|
2857 |
RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler); |
2858 |
// If we caught a SIGUSR1 during the bootstrap process, re-raise it
|
2859 |
// now that the debugger infrastructure is in place.
|
2860 |
if (caught_early_debug_signal)
|
2861 |
raise(SIGUSR1); |
2862 |
return 0; |
2863 |
} |
2864 |
#endif // __POSIX__ |
2865 |
|
2866 |
|
2867 |
#ifdef _WIN32
|
2868 |
DWORD WINAPI EnableDebugThreadProc(void* arg) {
|
2869 |
v8::Debug::DebugBreak(*static_cast<Isolate* volatile*>(&node_isolate)); |
2870 |
uv_async_send(&dispatch_debug_messages_async); |
2871 |
return 0; |
2872 |
} |
2873 |
|
2874 |
|
2875 |
static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf, |
2876 |
size_t buf_len) { |
2877 |
return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid); |
2878 |
} |
2879 |
|
2880 |
|
2881 |
static int RegisterDebugSignalHandler() { |
2882 |
wchar_t mapping_name[32]; |
2883 |
HANDLE mapping_handle; |
2884 |
DWORD pid; |
2885 |
LPTHREAD_START_ROUTINE* handler; |
2886 |
|
2887 |
pid = GetCurrentProcessId(); |
2888 |
|
2889 |
if (GetDebugSignalHandlerMappingName(pid,
|
2890 |
mapping_name, |
2891 |
ARRAY_SIZE(mapping_name)) < 0) {
|
2892 |
return -1; |
2893 |
} |
2894 |
|
2895 |
mapping_handle = CreateFileMappingW(INVALID_HANDLE_VALUE, |
2896 |
NULL,
|
2897 |
PAGE_READWRITE, |
2898 |
0,
|
2899 |
sizeof *handler,
|
2900 |
mapping_name); |
2901 |
if (mapping_handle == NULL) { |
2902 |
return -1; |
2903 |
} |
2904 |
|
2905 |
handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
|
2906 |
MapViewOfFile(mapping_handle, |
2907 |
FILE_MAP_ALL_ACCESS, |
2908 |
0,
|
2909 |
0,
|
2910 |
sizeof *handler));
|
2911 |
if (handler == NULL) { |
2912 |
CloseHandle(mapping_handle); |
2913 |
return -1; |
2914 |
} |
2915 |
|
2916 |
*handler = EnableDebugThreadProc; |
2917 |
|
2918 |
UnmapViewOfFile(static_cast<void*>(handler)); |
2919 |
|
2920 |
return 0; |
2921 |
} |
2922 |
|
2923 |
|
2924 |
static void DebugProcess(const FunctionCallbackInfo<Value>& args) { |
2925 |
HandleScope scope(node_isolate); |
2926 |
DWORD pid; |
2927 |
HANDLE process = NULL;
|
2928 |
HANDLE thread = NULL;
|
2929 |
HANDLE mapping = NULL;
|
2930 |
wchar_t mapping_name[32]; |
2931 |
LPTHREAD_START_ROUTINE* handler = NULL;
|
2932 |
|
2933 |
if (args.Length() != 1) { |
2934 |
ThrowError("Invalid number of arguments.");
|
2935 |
goto out;
|
2936 |
} |
2937 |
|
2938 |
pid = (DWORD) args[0]->IntegerValue();
|
2939 |
|
2940 |
process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | |
2941 |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | |
2942 |
PROCESS_VM_READ, |
2943 |
FALSE, |
2944 |
pid); |
2945 |
if (process == NULL) { |
2946 |
ThrowException(WinapiErrnoException(GetLastError(), "OpenProcess"));
|
2947 |
goto out;
|
2948 |
} |
2949 |
|
2950 |
if (GetDebugSignalHandlerMappingName(pid,
|
2951 |
mapping_name, |
2952 |
ARRAY_SIZE(mapping_name)) < 0) {
|
2953 |
ThrowErrnoException(errno, "sprintf");
|
2954 |
goto out;
|
2955 |
} |
2956 |
|
2957 |
mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name); |
2958 |
if (mapping == NULL) { |
2959 |
ThrowException(WinapiErrnoException(GetLastError(), "OpenFileMappingW"));
|
2960 |
goto out;
|
2961 |
} |
2962 |
|
2963 |
handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
|
2964 |
MapViewOfFile(mapping, |
2965 |
FILE_MAP_READ, |
2966 |
0,
|
2967 |
0,
|
2968 |
sizeof *handler));
|
2969 |
if (handler == NULL || *handler == NULL) { |
2970 |
ThrowException(WinapiErrnoException(GetLastError(), "MapViewOfFile"));
|
2971 |
goto out;
|
2972 |
} |
2973 |
|
2974 |
thread = CreateRemoteThread(process, |
2975 |
NULL,
|
2976 |
0,
|
2977 |
*handler, |
2978 |
NULL,
|
2979 |
0,
|
2980 |
NULL);
|
2981 |
if (thread == NULL) { |
2982 |
ThrowException(WinapiErrnoException(GetLastError(), "CreateRemoteThread"));
|
2983 |
goto out;
|
2984 |
} |
2985 |
|
2986 |
// Wait for the thread to terminate
|
2987 |
if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
|
2988 |
ThrowException(WinapiErrnoException(GetLastError(), "WaitForSingleObject"));
|
2989 |
goto out;
|
2990 |
} |
2991 |
|
2992 |
out:
|
2993 |
if (process != NULL) |
2994 |
CloseHandle(process); |
2995 |
if (thread != NULL) |
2996 |
CloseHandle(thread); |
2997 |
if (handler != NULL) |
2998 |
UnmapViewOfFile(handler); |
2999 |
if (mapping != NULL) |
3000 |
CloseHandle(mapping); |
3001 |
} |
3002 |
#endif // _WIN32 |
3003 |
|
3004 |
|
3005 |
static void DebugPause(const FunctionCallbackInfo<Value>& args) { |
3006 |
v8::Debug::DebugBreak(node_isolate); |
3007 |
} |
3008 |
|
3009 |
|
3010 |
static void DebugEnd(const FunctionCallbackInfo<Value>& args) { |
3011 |
if (debugger_running) {
|
3012 |
v8::Debug::DisableAgent(); |
3013 |
debugger_running = false;
|
3014 |
} |
3015 |
} |
3016 |
|
3017 |
|
3018 |
void Init(int* argc, |
3019 |
const char** argv, |
3020 |
int* exec_argc,
|
3021 |
const char*** exec_argv) { |
3022 |
// Initialize prog_start_time to get relative uptime.
|
3023 |
uv_uptime(&prog_start_time); |
3024 |
|
3025 |
// Make inherited handles noninheritable.
|
3026 |
uv_disable_stdio_inheritance(); |
3027 |
|
3028 |
// init async debug messages dispatching
|
3029 |
// FIXME(bnoordhuis) Should be per-isolate or per-context, not global.
|
3030 |
uv_async_init(uv_default_loop(), |
3031 |
&dispatch_debug_messages_async, |
3032 |
DispatchDebugMessagesAsyncCallback); |
3033 |
uv_unref(reinterpret_cast<uv_handle_t*>(&dispatch_debug_messages_async));
|
3034 |
|
3035 |
// Parse a few arguments which are specific to Node.
|
3036 |
int v8_argc;
|
3037 |
const char** v8_argv; |
3038 |
ParseArgs(argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv); |
3039 |
|
3040 |
// TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
|
3041 |
// manually? That would give us a little more control over its runtime
|
3042 |
// behavior but it could also interfere with the user's intentions in ways
|
3043 |
// we fail to anticipate. Dillema.
|
3044 |
for (int i = 1; i < v8_argc; ++i) { |
3045 |
if (strncmp(v8_argv[i], "--prof", sizeof("--prof") - 1) == 0) { |
3046 |
v8_is_profiling = true;
|
3047 |
break;
|
3048 |
} |
3049 |
} |
3050 |
|
3051 |
// The const_cast doesn't violate conceptual const-ness. V8 doesn't modify
|
3052 |
// the argv array or the elements it points to.
|
3053 |
V8::SetFlagsFromCommandLine(&v8_argc, const_cast<char**>(v8_argv), true); |
3054 |
|
3055 |
// Anything that's still in v8_argv is not a V8 or a node option.
|
3056 |
for (int i = 1; i < v8_argc; i++) { |
3057 |
fprintf(stderr, "%s: bad option: %s\n", argv[0], v8_argv[i]); |
3058 |
} |
3059 |
delete[] v8_argv;
|
3060 |
v8_argv = NULL;
|
3061 |
|
3062 |
if (v8_argc > 1) { |
3063 |
exit(9);
|
3064 |
} |
3065 |
|
3066 |
if (debug_wait_connect) {
|
3067 |
const char expose_debug_as[] = "--expose_debug_as=v8debug"; |
3068 |
V8::SetFlagsFromString(expose_debug_as, sizeof(expose_debug_as) - 1); |
3069 |
} |
3070 |
|
3071 |
V8::SetArrayBufferAllocator(&ArrayBufferAllocator::the_singleton); |
3072 |
|
3073 |
// Fetch a reference to the main isolate, so we have a reference to it
|
3074 |
// even when we need it to access it from another (debugger) thread.
|
3075 |
node_isolate = Isolate::GetCurrent(); |
3076 |
|
3077 |
#ifdef __POSIX__
|
3078 |
// Raise the open file descriptor limit.
|
3079 |
{ // NOLINT (whitespace/braces)
|
3080 |
struct rlimit lim;
|
3081 |
if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) { |
3082 |
// Do a binary search for the limit.
|
3083 |
rlim_t min = lim.rlim_cur; |
3084 |
rlim_t max = 1 << 20; |
3085 |
// But if there's a defined upper bound, don't search, just set it.
|
3086 |
if (lim.rlim_max != RLIM_INFINITY) {
|
3087 |
min = lim.rlim_max; |
3088 |
max = lim.rlim_max; |
3089 |
} |
3090 |
do {
|
3091 |
lim.rlim_cur = min + (max - min) / 2;
|
3092 |
if (setrlimit(RLIMIT_NOFILE, &lim)) {
|
3093 |
max = lim.rlim_cur; |
3094 |
} else {
|
3095 |
min = lim.rlim_cur; |
3096 |
} |
3097 |
} while (min + 1 < max); |
3098 |
} |
3099 |
} |
3100 |
// Ignore SIGPIPE
|
3101 |
RegisterSignalHandler(SIGPIPE, SIG_IGN); |
3102 |
RegisterSignalHandler(SIGINT, SignalExit); |
3103 |
RegisterSignalHandler(SIGTERM, SignalExit); |
3104 |
#endif // __POSIX__ |
3105 |
|
3106 |
V8::SetFatalErrorHandler(node::OnFatalError); |
3107 |
V8::AddMessageListener(OnMessage); |
3108 |
|
3109 |
// If the --debug flag was specified then initialize the debug thread.
|
3110 |
if (use_debug_agent) {
|
3111 |
EnableDebug(debug_wait_connect); |
3112 |
} else {
|
3113 |
RegisterDebugSignalHandler(); |
3114 |
} |
3115 |
} |
3116 |
|
3117 |
|
3118 |
struct AtExitCallback {
|
3119 |
AtExitCallback* next_; |
3120 |
void (*cb_)(void* arg); |
3121 |
void* arg_;
|
3122 |
}; |
3123 |
|
3124 |
static AtExitCallback* at_exit_functions_;
|
3125 |
|
3126 |
|
3127 |
// TODO(bnoordhuis) Turn into per-context event.
|
3128 |
void RunAtExit(Environment* env) {
|
3129 |
AtExitCallback* p = at_exit_functions_; |
3130 |
at_exit_functions_ = NULL;
|
3131 |
|
3132 |
while (p) {
|
3133 |
AtExitCallback* q = p->next_; |
3134 |
p->cb_(p->arg_); |
3135 |
delete p;
|
3136 |
p = q; |
3137 |
} |
3138 |
} |
3139 |
|
3140 |
|
3141 |
void AtExit(void (*cb)(void* arg), void* arg) { |
3142 |
AtExitCallback* p = new AtExitCallback;
|
3143 |
p->cb_ = cb; |
3144 |
p->arg_ = arg; |
3145 |
p->next_ = at_exit_functions_; |
3146 |
at_exit_functions_ = p; |
3147 |
} |
3148 |
|
3149 |
|
3150 |
void EmitExit(Environment* env) {
|
3151 |
// process.emit('exit')
|
3152 |
Context::Scope context_scope(env->context()); |
3153 |
HandleScope handle_scope(env->isolate()); |
3154 |
Local<Object> process_object = env->process_object(); |
3155 |
process_object->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_exiting"),
|
3156 |
True(node_isolate)); |
3157 |
|
3158 |
Handle<String> exitCode = FIXED_ONE_BYTE_STRING(node_isolate, "exitCode");
|
3159 |
int code = process_object->Get(exitCode)->IntegerValue();
|
3160 |
|
3161 |
Local<Value> args[] = { |
3162 |
FIXED_ONE_BYTE_STRING(node_isolate, "exit"),
|
3163 |
Integer::New(code, node_isolate) |
3164 |
}; |
3165 |
|
3166 |
MakeCallback(env, process_object, "emit", ARRAY_SIZE(args), args);
|
3167 |
exit(code); |
3168 |
} |
3169 |
|
3170 |
|
3171 |
Environment* CreateEnvironment(Isolate* isolate, |
3172 |
int argc,
|
3173 |
const char* const* argv, |
3174 |
int exec_argc,
|
3175 |
const char* const* exec_argv) { |
3176 |
HandleScope handle_scope(isolate); |
3177 |
|
3178 |
Local<Context> context = Context::New(isolate); |
3179 |
Context::Scope context_scope(context); |
3180 |
Environment* env = Environment::New(context); |
3181 |
|
3182 |
uv_check_init(env->event_loop(), env->immediate_check_handle()); |
3183 |
uv_unref( |
3184 |
reinterpret_cast<uv_handle_t*>(env->immediate_check_handle()));
|
3185 |
uv_idle_init(env->event_loop(), env->immediate_idle_handle()); |
3186 |
|
3187 |
// Inform V8's CPU profiler when we're idle. The profiler is sampling-based
|
3188 |
// but not all samples are created equal; mark the wall clock time spent in
|
3189 |
// epoll_wait() and friends so profiling tools can filter it out. The samples
|
3190 |
// still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
|
3191 |
// TODO(bnoordhuis) Depends on a libuv implementation detail that we should
|
3192 |
// probably fortify in the API contract, namely that the last started prepare
|
3193 |
// or check watcher runs first. It's not 100% foolproof; if an add-on starts
|
3194 |
// a prepare or check watcher after us, any samples attributed to its callback
|
3195 |
// will be recorded with state=IDLE.
|
3196 |
uv_prepare_init(env->event_loop(), env->idle_prepare_handle()); |
3197 |
uv_check_init(env->event_loop(), env->idle_check_handle()); |
3198 |
uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_prepare_handle()));
|
3199 |
uv_unref(reinterpret_cast<uv_handle_t*>(env->idle_check_handle()));
|
3200 |
|
3201 |
if (v8_is_profiling) {
|
3202 |
StartProfilerIdleNotifier(env); |
3203 |
} |
3204 |
|
3205 |
Local<FunctionTemplate> process_template = FunctionTemplate::New(); |
3206 |
process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process"));
|
3207 |
|
3208 |
Local<Object> process_object = process_template->GetFunction()->NewInstance(); |
3209 |
env->set_process_object(process_object); |
3210 |
|
3211 |
SetupProcessObject(env, argc, argv, exec_argc, exec_argv); |
3212 |
Load(env); |
3213 |
|
3214 |
return env;
|
3215 |
} |
3216 |
|
3217 |
|
3218 |
int Start(int argc, char** argv) { |
3219 |
#if !defined(_WIN32)
|
3220 |
// Try hard not to lose SIGUSR1 signals during the bootstrap process.
|
3221 |
InstallEarlyDebugSignalHandler(); |
3222 |
#endif
|
3223 |
|
3224 |
assert(argc > 0);
|
3225 |
|
3226 |
// Hack around with the argv pointer. Used for process.title = "blah".
|
3227 |
argv = uv_setup_args(argc, argv); |
3228 |
|
3229 |
// This needs to run *before* V8::Initialize(). The const_cast is not
|
3230 |
// optional, in case you're wondering.
|
3231 |
int exec_argc;
|
3232 |
const char** exec_argv; |
3233 |
Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv); |
3234 |
|
3235 |
#if HAVE_OPENSSL
|
3236 |
// V8 on Windows doesn't have a good source of entropy. Seed it from
|
3237 |
// OpenSSL's pool.
|
3238 |
V8::SetEntropySource(crypto::EntropySource); |
3239 |
#endif
|
3240 |
|
3241 |
V8::Initialize(); |
3242 |
{ |
3243 |
Locker locker(node_isolate); |
3244 |
Environment* env = |
3245 |
CreateEnvironment(node_isolate, argc, argv, exec_argc, exec_argv); |
3246 |
Context::Scope context_scope(env->context()); |
3247 |
HandleScope handle_scope(env->isolate()); |
3248 |
uv_run(env->event_loop(), UV_RUN_DEFAULT); |
3249 |
EmitExit(env); |
3250 |
RunAtExit(env); |
3251 |
env->Dispose(); |
3252 |
env = NULL;
|
3253 |
} |
3254 |
|
3255 |
#ifndef NDEBUG
|
3256 |
// Clean up. Not strictly necessary.
|
3257 |
V8::Dispose(); |
3258 |
#endif // NDEBUG |
3259 |
|
3260 |
delete[] exec_argv;
|
3261 |
exec_argv = NULL;
|
3262 |
|
3263 |
return 0; |
3264 |
} |
3265 |
|
3266 |
|
3267 |
} // namespace node
|