~ubuntu-branches/ubuntu/precise/nodejs/precise

« back to all changes in this revision

Viewing changes to src/node.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jérémy Lal
  • Date: 2010-08-20 11:49:04 UTC
  • mfrom: (7.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100820114904-lz22w6fkth7yh179
Tags: 0.2.0-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#include <pwd.h> /* getpwnam() */
18
18
#include <grp.h> /* getgrnam() */
19
19
 
 
20
#include "platform.h"
 
21
 
20
22
#include <node_buffer.h>
21
23
#include <node_io_watcher.h>
22
24
#include <node_net.h>
43
45
 
44
46
#include <v8-debug.h>
45
47
 
 
48
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
49
 
46
50
using namespace v8;
47
51
 
48
52
extern char **environ;
55
59
static Persistent<String> syscall_symbol;
56
60
static Persistent<String> errpath_symbol;
57
61
 
58
 
static Persistent<String> dev_symbol;
59
 
static Persistent<String> ino_symbol;
60
 
static Persistent<String> mode_symbol;
61
 
static Persistent<String> nlink_symbol;
62
 
static Persistent<String> uid_symbol;
63
 
static Persistent<String> gid_symbol;
64
 
static Persistent<String> rdev_symbol;
65
 
static Persistent<String> size_symbol;
66
 
static Persistent<String> blksize_symbol;
67
 
static Persistent<String> blocks_symbol;
68
 
static Persistent<String> atime_symbol;
69
 
static Persistent<String> mtime_symbol;
70
 
static Persistent<String> ctime_symbol;
71
 
 
72
62
static Persistent<String> rss_symbol;
73
63
static Persistent<String> vsize_symbol;
74
64
static Persistent<String> heap_total_symbol;
92
82
static ev_async eio_done_poll_notifier;
93
83
static ev_idle  eio_poller;
94
84
 
95
 
// Buffer for getpwnam_r(), getgrpam_r(); keep this scoped at file-level rather
96
 
// than method-level to avoid excess stack usage.
97
 
static char getbuf[1024];
 
85
// Buffer for getpwnam_r(), getgrpam_r() and other misc callers; keep this
 
86
// scoped at file-level rather than method-level to avoid excess stack usage.
 
87
static char getbuf[PATH_MAX + 1];
98
88
 
99
89
// We need to notify V8 when we're idle so that it can run the garbage
100
90
// collector. The interface to this is V8::IdleNotification(). It returns
730
720
#endif
731
721
 
732
722
#ifdef SIGPWR
 
723
# if SIGPWR != SIGLOST
733
724
  SIGNO_CASE(SIGPWR);
 
725
# endif
734
726
#endif
735
727
 
736
728
#ifdef SIGSYS
791
783
    return UTF8;
792
784
  } else if (strcasecmp(*encoding, "ascii") == 0) {
793
785
    return ASCII;
 
786
  } else if (strcasecmp(*encoding, "base64") == 0) {
 
787
    return BASE64;
794
788
  } else if (strcasecmp(*encoding, "binary") == 0) {
795
789
    return BINARY;
796
790
  } else if (strcasecmp(*encoding, "raw") == 0) {
901
895
  return buflen;
902
896
}
903
897
 
904
 
static Persistent<FunctionTemplate> stats_constructor_template;
905
 
 
906
 
Local<Object> BuildStatsObject(struct stat * s) {
907
 
  HandleScope scope;
908
 
 
909
 
  if (dev_symbol.IsEmpty()) {
910
 
    dev_symbol = NODE_PSYMBOL("dev");
911
 
    ino_symbol = NODE_PSYMBOL("ino");
912
 
    mode_symbol = NODE_PSYMBOL("mode");
913
 
    nlink_symbol = NODE_PSYMBOL("nlink");
914
 
    uid_symbol = NODE_PSYMBOL("uid");
915
 
    gid_symbol = NODE_PSYMBOL("gid");
916
 
    rdev_symbol = NODE_PSYMBOL("rdev");
917
 
    size_symbol = NODE_PSYMBOL("size");
918
 
    blksize_symbol = NODE_PSYMBOL("blksize");
919
 
    blocks_symbol = NODE_PSYMBOL("blocks");
920
 
    atime_symbol = NODE_PSYMBOL("atime");
921
 
    mtime_symbol = NODE_PSYMBOL("mtime");
922
 
    ctime_symbol = NODE_PSYMBOL("ctime");
923
 
  }
924
 
 
925
 
  Local<Object> stats =
926
 
    stats_constructor_template->GetFunction()->NewInstance();
927
 
 
928
 
  /* ID of device containing file */
929
 
  stats->Set(dev_symbol, Integer::New(s->st_dev));
930
 
 
931
 
  /* inode number */
932
 
  stats->Set(ino_symbol, Integer::New(s->st_ino));
933
 
 
934
 
  /* protection */
935
 
  stats->Set(mode_symbol, Integer::New(s->st_mode));
936
 
 
937
 
  /* number of hard links */
938
 
  stats->Set(nlink_symbol, Integer::New(s->st_nlink));
939
 
 
940
 
  /* user ID of owner */
941
 
  stats->Set(uid_symbol, Integer::New(s->st_uid));
942
 
 
943
 
  /* group ID of owner */
944
 
  stats->Set(gid_symbol, Integer::New(s->st_gid));
945
 
 
946
 
  /* device ID (if special file) */
947
 
  stats->Set(rdev_symbol, Integer::New(s->st_rdev));
948
 
 
949
 
  /* total size, in bytes */
950
 
  stats->Set(size_symbol, Number::New(s->st_size));
951
 
 
952
 
  /* blocksize for filesystem I/O */
953
 
  stats->Set(blksize_symbol, Integer::New(s->st_blksize));
954
 
 
955
 
  /* number of blocks allocated */
956
 
  stats->Set(blocks_symbol, Integer::New(s->st_blocks));
957
 
 
958
 
  /* time of last access */
959
 
  stats->Set(atime_symbol, NODE_UNIXTIME_V8(s->st_atime));
960
 
 
961
 
  /* time of last modification */
962
 
  stats->Set(mtime_symbol, NODE_UNIXTIME_V8(s->st_mtime));
963
 
 
964
 
  /* time of last status change */
965
 
  stats->Set(ctime_symbol, NODE_UNIXTIME_V8(s->st_ctime));
966
 
 
967
 
  return scope.Close(stats);
968
 
}
969
 
 
970
 
 
971
898
// Extracts a C str from a V8 Utf8Value.
972
899
const char* ToCString(const v8::String::Utf8Value& value) {
973
900
  return *value ? *value : "<str conversion failed>";
976
903
static void ReportException(TryCatch &try_catch, bool show_line) {
977
904
  Handle<Message> message = try_catch.Message();
978
905
 
 
906
  node::Stdio::DisableRawMode(STDIN_FILENO);
 
907
  fprintf(stderr, "\n");
 
908
 
979
909
  if (show_line && !message.IsEmpty()) {
980
910
    // Print (filename):(line number): (message).
981
911
    String::Utf8Value filename(message->GetScriptResourceName());
996
926
    //
997
927
    // When reporting errors on the first line of a script, this wrapper
998
928
    // function is leaked to the user. This HACK is to remove it. The length
999
 
    // of the wrapper is 62. That wrapper is defined in lib/module.js
 
929
    // of the wrapper is 62. That wrapper is defined in src/node.js
1000
930
    //
1001
931
    // If that wrapper is ever changed, then this number also has to be
1002
932
    // updated. Or - someone could clean this up so that the two peices
1064
994
  assert(args.Length() == 0);
1065
995
 
1066
996
  // TODO Probably don't need to start this each time.
1067
 
  // Avoids failing on test/mjsunit/test-eio-race3.js though
 
997
  // Avoids failing on test/simple/test-eio-race3.js though
1068
998
  ev_idle_start(EV_DEFAULT_UC_ &eio_poller);
1069
999
 
1070
1000
  ev_loop(EV_DEFAULT_UC_ 0);
1107
1037
  HandleScope scope;
1108
1038
  assert(args.Length() == 0);
1109
1039
 
1110
 
  char output[PATH_MAX];
1111
 
  char *r = getcwd(output, PATH_MAX);
 
1040
  char *r = getcwd(getbuf, ARRAY_SIZE(getbuf) - 1);
1112
1041
  if (r == NULL) {
1113
1042
    return ThrowException(Exception::Error(String::New(strerror(errno))));
1114
1043
  }
1115
 
  Local<String> cwd = String::New(output);
 
1044
 
 
1045
  getbuf[ARRAY_SIZE(getbuf) - 1] = '\0';
 
1046
  Local<String> cwd = String::New(r);
1116
1047
 
1117
1048
  return scope.Close(cwd);
1118
1049
}
1159
1090
  }
1160
1091
 
1161
1092
  int gid;
1162
 
 
 
1093
 
1163
1094
  if (args[0]->IsNumber()) {
1164
1095
    gid = args[0]->Int32Value();
1165
1096
  } else if (args[0]->IsString()) {
1167
1098
    struct group grp, *grpp = NULL;
1168
1099
    int err;
1169
1100
 
1170
 
    if ((err = getgrnam_r(*grpnam, &grp, getbuf, sizeof(getbuf), &grpp)) ||
 
1101
    if ((err = getgrnam_r(*grpnam, &grp, getbuf, ARRAY_SIZE(getbuf), &grpp)) ||
1171
1102
        grpp == NULL) {
1172
1103
      return ThrowException(ErrnoException(errno, "getgrnam_r"));
1173
1104
    }
1202
1133
    struct passwd pwd, *pwdp = NULL;
1203
1134
    int err;
1204
1135
 
1205
 
    if ((err = getpwnam_r(*pwnam, &pwd, getbuf, sizeof(getbuf), &pwdp)) ||
 
1136
    if ((err = getpwnam_r(*pwnam, &pwd, getbuf, ARRAY_SIZE(getbuf), &pwdp)) ||
1206
1137
        pwdp == NULL) {
1207
1138
      return ThrowException(ErrnoException(errno, "getpwnam_r"));
1208
1139
    }
1223
1154
 
1224
1155
v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
1225
1156
  HandleScope scope;
1226
 
  fflush(stderr);
1227
 
  Stdio::Flush();
1228
1157
  exit(args[0]->IntegerValue());
1229
1158
  return Undefined();
1230
1159
}
1231
1160
 
1232
 
#ifdef __sun
1233
 
#define HAVE_GETMEM 1
1234
 
#include <unistd.h> /* getpagesize() */
1235
 
 
1236
 
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
1237
 
#define PROCFS_FILE_OFFSET_BITS_HACK 1
1238
 
#undef _FILE_OFFSET_BITS
1239
 
#else
1240
 
#define PROCFS_FILE_OFFSET_BITS_HACK 0
1241
 
#endif
1242
 
 
1243
 
#include <procfs.h>
1244
 
 
1245
 
#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
1246
 
#define _FILE_OFFSET_BITS 64
1247
 
#endif
1248
 
 
1249
 
int getmem(size_t *rss, size_t *vsize) {
1250
 
  pid_t pid = getpid();
1251
 
 
1252
 
  size_t page_size = getpagesize();
1253
 
  char pidpath[1024];
1254
 
  sprintf(pidpath, "/proc/%d/psinfo", pid);
1255
 
 
1256
 
  psinfo_t psinfo;
1257
 
  FILE *f = fopen(pidpath, "r");
1258
 
  if (!f) return -1;
1259
 
 
1260
 
  if (fread(&psinfo, sizeof(psinfo_t), 1, f) != 1) {
1261
 
    fclose (f);
1262
 
    return -1;
1263
 
  }
1264
 
 
1265
 
  /* XXX correct? */
1266
 
 
1267
 
  *vsize = (size_t) psinfo.pr_size * page_size;
1268
 
  *rss = (size_t) psinfo.pr_rssize * 1024;
1269
 
 
1270
 
  fclose (f);
1271
 
 
1272
 
  return 0;
1273
 
}
1274
 
#endif
1275
 
 
1276
 
 
1277
 
#ifdef __FreeBSD__
1278
 
#define HAVE_GETMEM 1
1279
 
#include <kvm.h>
1280
 
#include <sys/param.h>
1281
 
#include <sys/sysctl.h>
1282
 
#include <sys/user.h>
1283
 
#include <paths.h>
1284
 
#include <fcntl.h>
1285
 
#include <unistd.h>
1286
 
 
1287
 
int getmem(size_t *rss, size_t *vsize) {
1288
 
  kvm_t *kd = NULL;
1289
 
  struct kinfo_proc *kinfo = NULL;
1290
 
  pid_t pid;
1291
 
  int nprocs;
1292
 
  size_t page_size = getpagesize();
1293
 
 
1294
 
  pid = getpid();
1295
 
 
1296
 
  kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
1297
 
  if (kd == NULL) goto error;
1298
 
 
1299
 
  kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
1300
 
  if (kinfo == NULL) goto error;
1301
 
 
1302
 
  *rss = kinfo->ki_rssize * page_size;
1303
 
  *vsize = kinfo->ki_size;
1304
 
 
1305
 
  kvm_close(kd);
1306
 
 
1307
 
  return 0;
1308
 
 
1309
 
error:
1310
 
  if (kd) kvm_close(kd);
1311
 
  return -1;
1312
 
}
1313
 
#endif  // __FreeBSD__
1314
 
 
1315
 
 
1316
 
#ifdef __APPLE__
1317
 
#define HAVE_GETMEM 1
1318
 
/* Researched by Tim Becker and Michael Knight
1319
 
 * http://blog.kuriositaet.de/?p=257
1320
 
 */
1321
 
 
1322
 
#include <mach/task.h>
1323
 
#include <mach/mach_init.h>
1324
 
 
1325
 
int getmem(size_t *rss, size_t *vsize) {
1326
 
  struct task_basic_info t_info;
1327
 
  mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
1328
 
 
1329
 
  int r = task_info(mach_task_self(),
1330
 
                    TASK_BASIC_INFO,
1331
 
                    (task_info_t)&t_info,
1332
 
                    &t_info_count);
1333
 
 
1334
 
  if (r != KERN_SUCCESS) return -1;
1335
 
 
1336
 
  *rss = t_info.resident_size;
1337
 
  *vsize  = t_info.virtual_size;
1338
 
 
1339
 
  return 0;
1340
 
}
1341
 
#endif  // __APPLE__
1342
 
 
1343
 
#ifdef __linux__
1344
 
# define HAVE_GETMEM 1
1345
 
# include <sys/param.h> /* for MAXPATHLEN */
1346
 
 
1347
 
int getmem(size_t *rss, size_t *vsize) {
1348
 
  FILE *f = fopen("/proc/self/stat", "r");
1349
 
  if (!f) return -1;
1350
 
 
1351
 
  int itmp;
1352
 
  char ctmp;
1353
 
  char buffer[MAXPATHLEN];
1354
 
  size_t page_size = getpagesize();
1355
 
 
1356
 
  /* PID */
1357
 
  if (fscanf(f, "%d ", &itmp) == 0) goto error;
1358
 
  /* Exec file */
1359
 
  if (fscanf (f, "%s ", &buffer[0]) == 0) goto error;
1360
 
  /* State */
1361
 
  if (fscanf (f, "%c ", &ctmp) == 0) goto error;
1362
 
  /* Parent process */
1363
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1364
 
  /* Process group */
1365
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1366
 
  /* Session id */
1367
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1368
 
  /* TTY */
1369
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1370
 
  /* TTY owner process group */
1371
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1372
 
  /* Flags */
1373
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1374
 
  /* Minor faults (no memory page) */
1375
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1376
 
  /* Minor faults, children */
1377
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1378
 
  /* Major faults (memory page faults) */
1379
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1380
 
  /* Major faults, children */
1381
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1382
 
  /* utime */
1383
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1384
 
  /* stime */
1385
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1386
 
  /* utime, children */
1387
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1388
 
  /* stime, children */
1389
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1390
 
  /* jiffies remaining in current time slice */
1391
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1392
 
  /* 'nice' value */
1393
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1394
 
  /* jiffies until next timeout */
1395
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1396
 
  /* jiffies until next SIGALRM */
1397
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1398
 
  /* start time (jiffies since system boot) */
1399
 
  if (fscanf (f, "%d ", &itmp) == 0) goto error;
1400
 
 
1401
 
  /* Virtual memory size */
1402
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1403
 
  *vsize = (size_t) itmp;
1404
 
 
1405
 
  /* Resident set size */
1406
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1407
 
  *rss = (size_t) itmp * page_size;
1408
 
 
1409
 
  /* rlim */
1410
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1411
 
  /* Start of text */
1412
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1413
 
  /* End of text */
1414
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1415
 
  /* Start of stack */
1416
 
  if (fscanf (f, "%u ", &itmp) == 0) goto error;
1417
 
 
1418
 
  fclose (f);
1419
 
 
1420
 
  return 0;
1421
 
 
1422
 
error:
1423
 
  fclose (f);
1424
 
  return -1;
1425
 
}
1426
 
#endif  // __linux__
1427
 
 
1428
1161
 
1429
1162
static void CheckStatus(EV_P_ ev_timer *watcher, int revents) {
1430
1163
  assert(watcher == &gc_timer);
1431
 
  assert(revents == EV_TIMER);
 
1164
  assert(revents == EV_TIMEOUT);
1432
1165
 
1433
 
#if HAVE_GETMEM
1434
1166
  // check memory
1435
1167
  size_t rss, vsize;
1436
 
  if (!ev_is_active(&gc_idle) && getmem(&rss, &vsize) == 0) {
 
1168
  if (!ev_is_active(&gc_idle) && OS::GetMemory(&rss, &vsize) == 0) {
1437
1169
    if (rss > 1024*1024*128) {
1438
1170
      // larger than 128 megs, just start the idle watcher
1439
1171
      ev_idle_start(EV_A_ &gc_idle);
1440
1172
      return;
1441
1173
    }
1442
1174
  }
1443
 
#endif // HAVE_GETMEM
1444
1175
 
1445
1176
  double d = ev_now(EV_DEFAULT_UC) - TICK_TIME(3);
1446
1177
 
1457
1188
  HandleScope scope;
1458
1189
  assert(args.Length() == 0);
1459
1190
 
1460
 
#ifndef HAVE_GETMEM
1461
 
  return ThrowException(Exception::Error(String::New("Not support on your platform. (Talk to Ryan.)")));
1462
 
#else
1463
1191
  size_t rss, vsize;
1464
1192
 
1465
 
  int r = getmem(&rss, &vsize);
 
1193
  int r = OS::GetMemory(&rss, &vsize);
1466
1194
 
1467
1195
  if (r != 0) {
1468
1196
    return ThrowException(Exception::Error(String::New(strerror(errno))));
1489
1217
            Integer::NewFromUnsigned(v8_heap_stats.used_heap_size()));
1490
1218
 
1491
1219
  return scope.Close(info);
1492
 
#endif
1493
1220
}
1494
1221
 
1495
1222
 
1551
1278
    return ThrowException(exception);
1552
1279
  }
1553
1280
 
 
1281
  String::Utf8Value symbol(args[0]->ToString());
 
1282
  char *symstr = NULL;
 
1283
  {
 
1284
    char *sym = *symbol;
 
1285
    char *p = strrchr(sym, '/');
 
1286
    if (p != NULL) {
 
1287
      sym = p+1;
 
1288
    }
 
1289
 
 
1290
    p = strrchr(sym, '.');
 
1291
    if (p != NULL) {
 
1292
      *p = '\0';
 
1293
    }
 
1294
 
 
1295
    size_t slen = strlen(sym);
 
1296
    symstr = static_cast<char*>(calloc(1, slen + sizeof("_module") + 1));
 
1297
    memcpy(symstr, sym, slen);
 
1298
    memcpy(symstr+slen, "_module", sizeof("_module") + 1);
 
1299
  }
 
1300
 
1554
1301
  // Get the init() function from the dynamically shared object.
1555
 
  void *init_handle = dlsym(handle, "init");
 
1302
  node_module_struct *mod = static_cast<node_module_struct *>(dlsym(handle, symstr));
 
1303
  free(symstr);
1556
1304
  // Error out if not found.
1557
 
  if (init_handle == NULL) {
 
1305
  if (mod == NULL) {
 
1306
    /* Start Compatibility hack: Remove once everyone is using NODE_MODULE macro */
 
1307
    node_module_struct compat_mod;
 
1308
    mod = &compat_mod;
 
1309
    mod->version = NODE_MODULE_VERSION;
 
1310
 
 
1311
    void *init_handle = dlsym(handle, "init");
 
1312
    if (init_handle == NULL) {
 
1313
      dlclose(handle);
 
1314
      Local<Value> exception =
 
1315
        Exception::Error(String::New("No module symbol found in module."));
 
1316
      return ThrowException(exception);
 
1317
    }
 
1318
    mod->register_func = (extInit)(init_handle);
 
1319
    /* End Compatibility hack */
 
1320
  }
 
1321
 
 
1322
  if (mod->version != NODE_MODULE_VERSION) {
1558
1323
    Local<Value> exception =
1559
 
      Exception::Error(String::New("No 'init' symbol found in module."));
 
1324
      Exception::Error(String::New("Module version mismatch, refusing to load."));
1560
1325
    return ThrowException(exception);
1561
1326
  }
1562
 
  extInit init = (extInit)(init_handle); // Cast
1563
1327
 
1564
1328
  // Execute the C++ module
1565
 
  init(target);
 
1329
  mod->register_func(target);
1566
1330
 
 
1331
  // Tell coverity that 'handle' should not be freed when we return.
 
1332
  // coverity[leaked_storage]
1567
1333
  return Undefined();
1568
1334
}
1569
1335
 
1660
1426
 
1661
1427
 
1662
1428
static ev_async debug_watcher;
1663
 
volatile static bool debugger_msg_pending = false;
1664
1429
 
1665
1430
static void DebugMessageCallback(EV_P_ ev_async *watcher, int revents) {
1666
1431
  HandleScope scope;
1675
1440
 
1676
1441
  // Send a signal to our main thread saying that it should enter V8 to
1677
1442
  // handle the message.
1678
 
  debugger_msg_pending = true;
1679
1443
  ev_async_send(EV_DEFAULT_UC_ &debug_watcher);
1680
1444
}
1681
1445
 
1682
 
static Handle<Value> CheckBreak(const Arguments& args) {
1683
 
  HandleScope scope;
1684
 
  assert(args.Length() == 0);
1685
 
 
1686
 
  // TODO FIXME This function is a hack to wait until V8 is ready to accept
1687
 
  // commands. There seems to be a bug in EnableAgent( _ , _ , true) which
1688
 
  // makes it unusable here. Ideally we'd be able to bind EnableAgent and
1689
 
  // get it to halt until Eclipse connects.
1690
 
 
1691
 
  if (!debug_wait_connect)
1692
 
    return Undefined();
1693
 
 
1694
 
  printf("Waiting for remote debugger connection...\n");
1695
 
 
1696
 
  const int halfSecond = 50;
1697
 
  const int tenMs=10000;
1698
 
  debugger_msg_pending = false;
1699
 
  for (;;) {
1700
 
    if (debugger_msg_pending) {
1701
 
      Debug::DebugBreak();
1702
 
      Debug::ProcessDebugMessages();
1703
 
      debugger_msg_pending = false;
1704
 
 
1705
 
      // wait for 500 msec of silence from remote debugger
1706
 
      int cnt = halfSecond;
1707
 
        while (cnt --) {
1708
 
        debugger_msg_pending = false;
1709
 
        usleep(tenMs);
1710
 
        if (debugger_msg_pending) {
1711
 
          debugger_msg_pending = false;
1712
 
          cnt = halfSecond;
1713
 
        }
1714
 
      }
1715
 
      break;
1716
 
    }
1717
 
    usleep(tenMs);
1718
 
  }
1719
 
  return Undefined();
 
1446
static void DebugBreakMessageHandler(const Debug::Message& message) {
 
1447
  // do nothing with debug messages.
 
1448
  // The message handler will get changed by DebuggerAgent::CreateSession in
 
1449
  // debug-agent.cc of v8/src when a new session is created
1720
1450
}
1721
1451
 
1722
1452
Persistent<Object> binding_cache;
1726
1456
 
1727
1457
  Local<String> module = args[0]->ToString();
1728
1458
  String::Utf8Value module_v(module);
 
1459
  node_module_struct* modp;
1729
1460
 
1730
1461
  if (binding_cache.IsEmpty()) {
1731
1462
    binding_cache = Persistent<Object>::New(Object::New());
1733
1464
 
1734
1465
  Local<Object> exports;
1735
1466
 
1736
 
  // TODO DRY THIS UP!
1737
 
 
1738
 
  if (!strcmp(*module_v, "stdio")) {
1739
 
    if (binding_cache->Has(module)) {
1740
 
      exports = binding_cache->Get(module)->ToObject();
1741
 
    } else {
1742
 
      exports = Object::New();
1743
 
      Stdio::Initialize(exports);
1744
 
      binding_cache->Set(module, exports);
1745
 
    }
1746
 
 
1747
 
  } else if (!strcmp(*module_v, "cares")) {
1748
 
    if (binding_cache->Has(module)) {
1749
 
      exports = binding_cache->Get(module)->ToObject();
1750
 
    } else {
1751
 
      exports = Object::New();
1752
 
      Cares::Initialize(exports);
1753
 
      binding_cache->Set(module, exports);
1754
 
    }
1755
 
 
1756
 
  } else if (!strcmp(*module_v, "fs")) {
1757
 
    if (binding_cache->Has(module)) {
1758
 
      exports = binding_cache->Get(module)->ToObject();
1759
 
    } else {
1760
 
      exports = Object::New();
1761
 
 
1762
 
      // Initialize the stats object
1763
 
      Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
1764
 
      stats_constructor_template = Persistent<FunctionTemplate>::New(stat_templ);
1765
 
      exports->Set(String::NewSymbol("Stats"),
1766
 
                   stats_constructor_template->GetFunction());
1767
 
      StatWatcher::Initialize(exports);
1768
 
      File::Initialize(exports);
1769
 
      binding_cache->Set(module, exports);
1770
 
    }
1771
 
 
1772
 
  } else if (!strcmp(*module_v, "signal_watcher")) {
1773
 
    if (binding_cache->Has(module)) {
1774
 
      exports = binding_cache->Get(module)->ToObject();
1775
 
    } else {
1776
 
      exports = Object::New();
1777
 
      SignalWatcher::Initialize(exports);
1778
 
      binding_cache->Set(module, exports);
1779
 
    }
1780
 
 
1781
 
  } else if (!strcmp(*module_v, "net")) {
1782
 
    if (binding_cache->Has(module)) {
1783
 
      exports = binding_cache->Get(module)->ToObject();
1784
 
    } else {
1785
 
      exports = Object::New();
1786
 
      InitNet(exports);
1787
 
      binding_cache->Set(module, exports);
1788
 
    }
1789
 
 
1790
 
  } else if (!strcmp(*module_v, "http_parser")) {
1791
 
    if (binding_cache->Has(module)) {
1792
 
      exports = binding_cache->Get(module)->ToObject();
1793
 
    } else {
1794
 
      exports = Object::New();
1795
 
      InitHttpParser(exports);
1796
 
      binding_cache->Set(module, exports);
1797
 
    }
1798
 
 
1799
 
  } else if (!strcmp(*module_v, "child_process")) {
1800
 
    if (binding_cache->Has(module)) {
1801
 
      exports = binding_cache->Get(module)->ToObject();
1802
 
    } else {
1803
 
      exports = Object::New();
1804
 
      ChildProcess::Initialize(exports);
1805
 
      binding_cache->Set(module, exports);
1806
 
    }
1807
 
 
1808
 
  } else if (!strcmp(*module_v, "buffer")) {
1809
 
    if (binding_cache->Has(module)) {
1810
 
      exports = binding_cache->Get(module)->ToObject();
1811
 
    } else {
1812
 
      exports = Object::New();
1813
 
      Buffer::Initialize(exports);
1814
 
      binding_cache->Set(module, exports);
1815
 
    }
1816
 
  #ifdef HAVE_OPENSSL
1817
 
  } else if (!strcmp(*module_v, "crypto")) {
1818
 
    if (binding_cache->Has(module)) {
1819
 
      exports = binding_cache->Get(module)->ToObject();
1820
 
    } else {
1821
 
      exports = Object::New();
1822
 
      InitCrypto(exports);
1823
 
      binding_cache->Set(module, exports);
1824
 
    }
1825
 
  #endif
1826
 
  } else if (!strcmp(*module_v, "evals")) {
1827
 
    if (binding_cache->Has(module)) {
1828
 
      exports = binding_cache->Get(module)->ToObject();
1829
 
    } else {
1830
 
      exports = Object::New();
1831
 
      node::Script::Initialize(exports);
1832
 
      binding_cache->Set(module, exports);
1833
 
    }
1834
 
 
 
1467
  if (binding_cache->Has(module)) {
 
1468
    exports = binding_cache->Get(module)->ToObject();
 
1469
  }
 
1470
  else if ((modp = get_builtin_module(*module_v)) != NULL) {
 
1471
    exports = Object::New();
 
1472
    modp->register_func(exports);
 
1473
    binding_cache->Set(module, exports);
1835
1474
  } else if (!strcmp(*module_v, "natives")) {
1836
 
    if (binding_cache->Has(module)) {
1837
 
      exports = binding_cache->Get(module)->ToObject();
1838
 
    } else {
1839
 
      exports = Object::New();
1840
 
      // Explicitly define native sources.
1841
 
      // TODO DRY/automate this?
1842
 
      exports->Set(String::New("assert"),       String::New(native_assert));
1843
 
      exports->Set(String::New("buffer"),       String::New(native_buffer));
1844
 
      exports->Set(String::New("child_process"),String::New(native_child_process));
1845
 
      exports->Set(String::New("dns"),          String::New(native_dns));
1846
 
      exports->Set(String::New("events"),       String::New(native_events));
1847
 
      exports->Set(String::New("file"),         String::New(native_file));
1848
 
      exports->Set(String::New("freelist"),     String::New(native_freelist));
1849
 
      exports->Set(String::New("fs"),           String::New(native_fs));
1850
 
      exports->Set(String::New("http"),         String::New(native_http));
1851
 
      exports->Set(String::New("crypto"),       String::New(native_crypto));
1852
 
      exports->Set(String::New("ini"),          String::New(native_ini));
1853
 
      exports->Set(String::New("mjsunit"),      String::New(native_mjsunit));
1854
 
      exports->Set(String::New("net"),          String::New(native_net));
1855
 
      exports->Set(String::New("posix"),        String::New(native_posix));
1856
 
      exports->Set(String::New("querystring"),  String::New(native_querystring));
1857
 
      exports->Set(String::New("repl"),         String::New(native_repl));
1858
 
      exports->Set(String::New("sys"),          String::New(native_sys));
1859
 
      exports->Set(String::New("tcp"),          String::New(native_tcp));
1860
 
      exports->Set(String::New("uri"),          String::New(native_uri));
1861
 
      exports->Set(String::New("url"),          String::New(native_url));
1862
 
      exports->Set(String::New("utils"),        String::New(native_utils));
1863
 
      exports->Set(String::New("path"),         String::New(native_path));
1864
 
      exports->Set(String::New("module"),       String::New(native_module));
1865
 
      exports->Set(String::New("utf8decoder"),  String::New(native_utf8decoder));
1866
 
      binding_cache->Set(module, exports);
1867
 
    }
1868
 
 
 
1475
    exports = Object::New();
 
1476
    // Explicitly define native sources.
 
1477
    // TODO DRY/automate this?
 
1478
    exports->Set(String::New("assert"),       String::New(native_assert));
 
1479
    exports->Set(String::New("buffer"),       String::New(native_buffer));
 
1480
    exports->Set(String::New("child_process"),String::New(native_child_process));
 
1481
    exports->Set(String::New("dgram"),        String::New(native_dgram));
 
1482
    exports->Set(String::New("dns"),          String::New(native_dns));
 
1483
    exports->Set(String::New("events"),       String::New(native_events));
 
1484
    exports->Set(String::New("file"),         String::New(native_file));
 
1485
    exports->Set(String::New("freelist"),     String::New(native_freelist));
 
1486
    exports->Set(String::New("fs"),           String::New(native_fs));
 
1487
    exports->Set(String::New("http"),         String::New(native_http));
 
1488
    exports->Set(String::New("crypto"),       String::New(native_crypto));
 
1489
    exports->Set(String::New("net"),          String::New(native_net));
 
1490
    exports->Set(String::New("posix"),        String::New(native_posix));
 
1491
    exports->Set(String::New("querystring"),  String::New(native_querystring));
 
1492
    exports->Set(String::New("repl"),         String::New(native_repl));
 
1493
    exports->Set(String::New("readline"),     String::New(native_readline));
 
1494
    exports->Set(String::New("sys"),          String::New(native_sys));
 
1495
    exports->Set(String::New("tcp"),          String::New(native_tcp));
 
1496
    exports->Set(String::New("url"),          String::New(native_url));
 
1497
    exports->Set(String::New("utils"),        String::New(native_utils));
 
1498
    exports->Set(String::New("path"),         String::New(native_path));
 
1499
    exports->Set(String::New("string_decoder"), String::New(native_string_decoder));
 
1500
    binding_cache->Set(module, exports);
1869
1501
  } else {
1870
1502
    return ThrowException(Exception::Error(String::New("No such module")));
1871
1503
  }
1874
1506
}
1875
1507
 
1876
1508
 
 
1509
static Handle<Value> ProcessTitleGetter(Local<String> property,
 
1510
                                        const AccessorInfo& info) {
 
1511
  HandleScope scope;
 
1512
  int len;
 
1513
  const char *s = OS::GetProcessTitle(&len);
 
1514
  return scope.Close(s ? String::New(s, len) : String::Empty());
 
1515
}
 
1516
 
 
1517
 
 
1518
static void ProcessTitleSetter(Local<String> property,
 
1519
                               Local<Value> value,
 
1520
                               const AccessorInfo& info) {
 
1521
  HandleScope scope;
 
1522
  String::Utf8Value title(value->ToString());
 
1523
  OS::SetProcessTitle(*title);
 
1524
}
 
1525
 
 
1526
 
1877
1527
static void Load(int argc, char *argv[]) {
1878
1528
  HandleScope scope;
1879
1529
 
1882
1532
 
1883
1533
  process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
1884
1534
 
 
1535
 
 
1536
  process->SetAccessor(String::New("title"),
 
1537
                       ProcessTitleGetter,
 
1538
                       ProcessTitleSetter);
 
1539
 
 
1540
 
1885
1541
  // Add a reference to the global object
1886
 
  Local<Object> global = Context::GetCurrent()->Global();
 
1542
  Local<Object> global = v8::Context::GetCurrent()->Global();
1887
1543
  process->Set(String::NewSymbol("global"), global);
1888
1544
 
1889
1545
  // process.version
1890
1546
  process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
 
1547
 
1891
1548
  // process.installPrefix
1892
1549
  process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
1893
1550
 
 
1551
  Local<Object> versions = Object::New();
 
1552
  char buf[20];
 
1553
  process->Set(String::NewSymbol("versions"), versions);
 
1554
  // +1 to get rid of the leading 'v'
 
1555
  versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1));
 
1556
  versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));
 
1557
  versions->Set(String::NewSymbol("ares"), String::New(ARES_VERSION_STR));
 
1558
  snprintf(buf, 20, "%d.%d", ev_version_major(), ev_version_minor());
 
1559
  versions->Set(String::NewSymbol("ev"), String::New(buf));
 
1560
 
 
1561
 
 
1562
 
1894
1563
  // process.platform
1895
 
#define xstr(s) str(s)
1896
 
#define str(s) #s
1897
 
  process->Set(String::NewSymbol("platform"), String::New(xstr(PLATFORM)));
 
1564
  process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
1898
1565
 
1899
1566
  // process.argv
1900
1567
  int i, j;
1901
1568
  Local<Array> arguments = Array::New(argc - option_end_index + 1);
1902
1569
  arguments->Set(Integer::New(0), String::New(argv[0]));
1903
 
  for (j = 1, i = option_end_index + 1; i < argc; j++, i++) {
 
1570
  for (j = 1, i = option_end_index; i < argc; j++, i++) {
1904
1571
    Local<String> arg = String::New(argv[i]);
1905
1572
    arguments->Set(Integer::New(j), arg);
1906
1573
  }
1928
1595
 
1929
1596
  process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
1930
1597
 
 
1598
  size_t size = 2*PATH_MAX;
 
1599
  char execPath[size];
 
1600
  if (OS::GetExecutablePath(execPath, &size) != 0) {
 
1601
    // as a last ditch effort, fallback on argv[0] ?
 
1602
    process->Set(String::NewSymbol("execPath"), String::New(argv[0]));
 
1603
  } else {
 
1604
    process->Set(String::NewSymbol("execPath"), String::New(execPath));
 
1605
  }
 
1606
 
 
1607
 
1931
1608
  // define various internal methods
1932
1609
  NODE_SET_METHOD(process, "loop", Loop);
1933
1610
  NODE_SET_METHOD(process, "unloop", Unloop);
1947
1624
  NODE_SET_METHOD(process, "dlopen", DLOpen);
1948
1625
  NODE_SET_METHOD(process, "kill", Kill);
1949
1626
  NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
1950
 
  NODE_SET_METHOD(process, "checkBreak", CheckBreak);
1951
1627
 
1952
1628
  NODE_SET_METHOD(process, "binding", Binding);
1953
1629
 
1961
1637
  // Not in use at the moment.
1962
1638
  //IdleWatcher::Initialize(process);            // idle_watcher.cc
1963
1639
  Timer::Initialize(process);                  // timer.cc
 
1640
  // coverity[stack_use_callee]
1964
1641
  DefineConstants(process);                    // constants.cc
1965
1642
 
1966
1643
  // Compile, execute the src/node.js file. (Which was included as static C
2043
1720
         "                     prefixed to the module search path,\n"
2044
1721
         "                     require.paths.\n"
2045
1722
         "NODE_DEBUG           Print additional debugging output.\n"
 
1723
         "NODE_MODULE_CONTEXTS Set to 1 to load modules in their own\n"
 
1724
         "                     global contexts.\n"
2046
1725
         "\n"
2047
1726
         "Documentation can be found at http://nodejs.org/api.html"
2048
1727
         " or with 'man node'\n");
2050
1729
 
2051
1730
// Parse node command line arguments.
2052
1731
static void ParseArgs(int *argc, char **argv) {
 
1732
  int i;
 
1733
 
2053
1734
  // TODO use parse opts
2054
 
  for (int i = 1; i < *argc; i++) {
 
1735
  for (i = 1; i < *argc; i++) {
2055
1736
    const char *arg = argv[i];
2056
1737
    if (strstr(arg, "--debug") == arg) {
2057
1738
      ParseDebugOpt(arg);
2058
1739
      argv[i] = const_cast<char*>("");
2059
 
      option_end_index = i;
2060
1740
    } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
2061
1741
      printf("%s\n", NODE_VERSION);
2062
1742
      exit(0);
2069
1749
      exit(0);
2070
1750
    } else if (strcmp(arg, "--v8-options") == 0) {
2071
1751
      argv[i] = const_cast<char*>("--help");
2072
 
      option_end_index = i+1;
2073
1752
    } else if (argv[i][0] != '-') {
2074
 
      option_end_index = i-1;
2075
1753
      break;
2076
1754
    }
2077
1755
  }
2078
 
}
 
1756
 
 
1757
  option_end_index = i;
 
1758
}
 
1759
 
 
1760
 
 
1761
static void AtExit() {
 
1762
  node::Stdio::Flush();
 
1763
  node::Stdio::DisableRawMode(STDIN_FILENO);
 
1764
}
 
1765
 
2079
1766
 
2080
1767
}  // namespace node
2081
1768
 
2082
1769
 
2083
1770
int main(int argc, char *argv[]) {
 
1771
  // Hack aroung with the argv pointer. Used for process.title = "blah".
 
1772
  argv = node::OS::SetupArgs(argc, argv);
 
1773
 
2084
1774
  // Parse a few arguments which are specific to Node.
2085
1775
  node::ParseArgs(&argc, argv);
2086
1776
  // Parse the rest of the args (up to the 'option_end_index' (where '--' was
2087
1777
  // in the command line))
2088
 
  V8::SetFlagsFromCommandLine(&node::option_end_index, argv, false);
 
1778
  int v8argc = node::option_end_index;
 
1779
  char **v8argv = argv;
2089
1780
 
2090
 
  // Error out if we don't have a script argument.
2091
 
  if (argc < 2) {
2092
 
    fprintf(stderr, "No script was specified.\n");
2093
 
    node::PrintHelp();
2094
 
    return 1;
 
1781
  if (node::debug_wait_connect) {
 
1782
    // v8argv is a copy of argv up to the script file argument +2 if --debug-brk
 
1783
    // to expose the v8 debugger js object so that node.js can set
 
1784
    // a breakpoint on the first line of the startup script
 
1785
    v8argc += 2;
 
1786
    v8argv = new char*[v8argc];
 
1787
    memcpy(v8argv, argv, sizeof(argv) * node::option_end_index);
 
1788
    v8argv[node::option_end_index] = const_cast<char*>("--expose_debug_as");
 
1789
    v8argv[node::option_end_index + 1] = const_cast<char*>("v8debug");
2095
1790
  }
2096
 
 
 
1791
  V8::SetFlagsFromCommandLine(&v8argc, v8argv, false);
2097
1792
 
2098
1793
  // Ignore SIGPIPE
2099
1794
  struct sigaction sa;
2103
1798
 
2104
1799
 
2105
1800
  // Initialize the default ev loop.
2106
 
#ifdef __sun
 
1801
#if defined(__sun)
2107
1802
  // TODO(Ryan) I'm experiencing abnormally high load using Solaris's
2108
1803
  // EVBACKEND_PORT. Temporarally forcing select() until I debug.
2109
 
  ev_default_loop(EVBACKEND_SELECT);
 
1804
  ev_default_loop(EVBACKEND_POLL);
 
1805
#elif defined(__APPLE_CC__) && __APPLE_CC__ >= 5659
 
1806
  ev_default_loop(EVBACKEND_KQUEUE);
2110
1807
#else
2111
1808
  ev_default_loop(EVFLAG_AUTO);
2112
1809
#endif
2139
1836
 
2140
1837
    eio_init(node::EIOWantPoll, node::EIODonePoll);
2141
1838
    // Don't handle more than 10 reqs on each eio_poll(). This is to avoid
2142
 
    // race conditions. See test/mjsunit/test-eio-race.js
 
1839
    // race conditions. See test/simple/test-eio-race.js
2143
1840
    eio_set_max_poll_reqs(10);
2144
1841
  }
2145
1842
 
2167
1864
 
2168
1865
    // Start the debug thread and it's associated TCP server on port 5858.
2169
1866
    bool r = Debug::EnableAgent("node " NODE_VERSION, node::debug_port);
 
1867
    if (node::debug_wait_connect) {
 
1868
      // Set up an empty handler so v8 will not continue until a debugger
 
1869
      // attaches. This is the same behavior as Debug::EnableAgent(_,_,true)
 
1870
      // except we don't break at the beginning of the script.
 
1871
      // see Debugger::StartAgent in debug.cc of v8/src
 
1872
      Debug::SetMessageHandler2(node::DebugBreakMessageHandler);
 
1873
    }
2170
1874
 
2171
1875
    // Crappy check that everything went well. FIXME
2172
1876
    assert(r);
2175
1879
  }
2176
1880
 
2177
1881
  // Create the one and only Context.
2178
 
  Persistent<Context> context = Context::New();
2179
 
  Context::Scope context_scope(context);
 
1882
  Persistent<v8::Context> context = v8::Context::New();
 
1883
  v8::Context::Scope context_scope(context);
 
1884
 
 
1885
  atexit(node::AtExit);
2180
1886
 
2181
1887
  // Create all the objects, load modules, do everything.
2182
1888
  // so your next reading stop should be node::Load()!
2183
1889
  node::Load(argc, argv);
2184
1890
 
2185
 
  node::Stdio::Flush();
2186
 
 
2187
1891
#ifndef NDEBUG
2188
1892
  // Clean up.
2189
1893
  context.Dispose();
2191
1895
#endif  // NDEBUG
2192
1896
  return 0;
2193
1897
}
2194