Browse Source

Add more functionality to the os module

v0.7.4-release
Brian White 14 years ago
committed by Ryan Dahl
parent
commit
d75c338dd6
  1. 97
      doc/api/os.markdown
  2. 9
      lib/os.js
  3. 12
      src/node.cc
  4. 101
      src/node_os.cc
  5. 9
      src/platform.h
  6. 128
      src/platform_cygwin.cc
  7. 131
      src/platform_darwin.cc
  8. 2
      src/platform_darwin_proctitle.cc
  9. 139
      src/platform_freebsd.cc
  10. 128
      src/platform_linux.cc
  11. 201
      src/platform_openbsd.cc
  12. 5
      test/simple/test-os-hostname.js
  13. 12
      test/simple/test-os.js
  14. 2
      wscript

97
doc/api/os.markdown

@ -2,6 +2,101 @@
Use `require('os')` to access this module.
### os.getHostname()
### os.hostname()
Returns the hostname of the operating system.
### os.type()
Returns the operating system name.
### os.release()
Returns the operating system release.
### os.uptime()
Returns the system uptime in seconds.
### os.loadavg()
Returns an array containing the 1, 5, and 15 minute load averages.
### os.totalmem()
Returns the total amount of system memory in bytes.
### os.freemem()
Returns the amount of free system memory in bytes.
### os.cpus()
Returns an array of objects containing information about each CPU/core installed: model, speed (in MHz), and times (an object containing the number of CPU ticks spent in: user, nice, sys, idle, and irq).
Example inspection of os.cpus:
[ { model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 252020,
nice: 0,
sys: 30340,
idle: 1070356870,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 306960,
nice: 0,
sys: 26980,
idle: 1071569080,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 248450,
nice: 0,
sys: 21750,
idle: 1070919370,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 256880,
nice: 0,
sys: 19430,
idle: 1070905480,
irq: 20 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 511580,
nice: 20,
sys: 40900,
idle: 1070842510,
irq: 0 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 291660,
nice: 0,
sys: 34360,
idle: 1070888000,
irq: 10 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 308260,
nice: 0,
sys: 55410,
idle: 1071129970,
irq: 880 } },
{ model: 'Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz',
speed: 2926,
times:
{ user: 266450,
nice: 1480,
sys: 34920,
idle: 1072572010,
irq: 30 } } ]

9
lib/os.js

@ -1,3 +1,10 @@
var binding = process.binding('os');
exports.getHostname = binding.getHostname;
exports.hostname = binding.getHostname;
exports.loadavg = binding.getLoadAvg;
exports.uptime = binding.getUptime;
exports.freemem = binding.getFreeMem;
exports.totalmem = binding.getTotalMem;
exports.cpus = binding.getCPUs;
exports.type = binding.getOSType;
exports.release = binding.getOSRelease;

12
src/node.cc

@ -1186,7 +1186,7 @@ static void CheckStatus(EV_P_ ev_timer *watcher, int revents) {
// check memory
size_t rss, vsize;
if (!ev_is_active(&gc_idle) && OS::GetMemory(&rss, &vsize) == 0) {
if (!ev_is_active(&gc_idle) && Platform::GetMemory(&rss, &vsize) == 0) {
if (rss > 1024*1024*128) {
// larger than 128 megs, just start the idle watcher
ev_idle_start(EV_A_ &gc_idle);
@ -1211,7 +1211,7 @@ v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
size_t rss, vsize;
int r = OS::GetMemory(&rss, &vsize);
int r = Platform::GetMemory(&rss, &vsize);
if (r != 0) {
return ThrowException(Exception::Error(String::New(strerror(errno))));
@ -1519,7 +1519,7 @@ static Handle<Value> ProcessTitleGetter(Local<String> property,
const AccessorInfo& info) {
HandleScope scope;
int len;
const char *s = OS::GetProcessTitle(&len);
const char *s = Platform::GetProcessTitle(&len);
return scope.Close(s ? String::New(s, len) : String::Empty());
}
@ -1529,7 +1529,7 @@ static void ProcessTitleSetter(Local<String> property,
const AccessorInfo& info) {
HandleScope scope;
String::Utf8Value title(value->ToString());
OS::SetProcessTitle(*title);
Platform::SetProcessTitle(*title);
}
@ -1685,7 +1685,7 @@ static void Load(int argc, char *argv[]) {
size_t size = 2*PATH_MAX;
char execPath[size];
if (OS::GetExecutablePath(execPath, &size) != 0) {
if (Platform::GetExecutablePath(execPath, &size) != 0) {
// as a last ditch effort, fallback on argv[0] ?
process->Set(String::NewSymbol("execPath"), String::New(argv[0]));
} else {
@ -1874,7 +1874,7 @@ static int RegisterSignalHandler(int signal, void (*handler)(int)) {
int Start(int argc, char *argv[]) {
// Hack aroung with the argv pointer. Used for process.title = "blah".
argv = node::OS::SetupArgs(argc, argv);
argv = node::Platform::SetupArgs(argc, argv);
// Parse a few arguments which are specific to Node.
node::ParseArgs(&argc, argv);

101
src/node_os.cc

@ -3,8 +3,12 @@
#include <node.h>
#include <v8.h>
#include "platform.h"
#include <errno.h>
#include <unistd.h> // gethostname
#include <unistd.h> // gethostname, sysconf
#include <sys/param.h> // sysctl
#include <sys/sysctl.h> // sysctl
namespace node {
@ -13,19 +17,108 @@ using namespace v8;
static Handle<Value> GetHostname(const Arguments& args) {
HandleScope scope;
char s[255];
int r = gethostname(s, 255);
if (r < 0) {
return ThrowException(ErrnoException(errno, "gethostname"));
if (gethostname(s, 255) < 0) {
return Undefined();
}
return scope.Close(String::New(s));
}
static Handle<Value> GetOSType(const Arguments& args) {
HandleScope scope;
char type[256];
static int which[] = {CTL_KERN, KERN_OSTYPE};
size_t size = sizeof(type);
if (sysctl(which, 2, &type, &size, NULL, 0) < 0) {
return Undefined();
}
return scope.Close(String::New(type));
}
static Handle<Value> GetOSRelease(const Arguments& args) {
HandleScope scope;
char release[256];
static int which[] = {CTL_KERN, KERN_OSRELEASE};
size_t size = sizeof(release);
if (sysctl(which, 2, &release, &size, NULL, 0) < 0) {
return Undefined();
}
return scope.Close(String::New(release));
}
static Handle<Value> GetCPUInfo(const Arguments& args) {
HandleScope scope;
Local<Array> cpus;
int r = Platform::GetCPUInfo(&cpus);
if (r < 0) {
return Undefined();
}
return scope.Close(cpus);
}
static Handle<Value> GetFreeMemory(const Arguments& args) {
HandleScope scope;
double amount = Platform::GetFreeMemory();
if (amount < 0) {
return Undefined();
}
return scope.Close(Number::New(amount));
}
static Handle<Value> GetTotalMemory(const Arguments& args) {
HandleScope scope;
double amount = Platform::GetTotalMemory();
if (amount < 0) {
return Undefined();
}
return scope.Close(Number::New(amount));
}
static Handle<Value> GetUptime(const Arguments& args) {
HandleScope scope;
double uptime = Platform::GetUptime();
if (uptime < 0) {
return Undefined();
}
return scope.Close(Number::New(uptime));
}
static Handle<Value> GetLoadAvg(const Arguments& args) {
HandleScope scope;
Local<Array> loads = Array::New(3);
int r = Platform::GetLoadAvg(&loads);
if (r < 0) {
return Undefined();
}
return scope.Close(loads);
}
void OS::Initialize(v8::Handle<v8::Object> target) {
HandleScope scope;
NODE_SET_METHOD(target, "getHostname", GetHostname);
NODE_SET_METHOD(target, "getLoadAvg", GetLoadAvg);
NODE_SET_METHOD(target, "getUptime", GetUptime);
NODE_SET_METHOD(target, "getTotalMem", GetTotalMemory);
NODE_SET_METHOD(target, "getFreeMem", GetFreeMemory);
NODE_SET_METHOD(target, "getCPUs", GetCPUInfo);
NODE_SET_METHOD(target, "getOSType", GetOSType);
NODE_SET_METHOD(target, "getOSRelease", GetOSRelease);
}

9
src/platform.h

@ -1,9 +1,11 @@
#ifndef NODE_PLATFORM_H_
#define NODE_PLATFORM_H_
#include <v8.h>
namespace node {
class OS {
class Platform {
public:
static char** SetupArgs(int argc, char *argv[]);
static void SetProcessTitle(char *title);
@ -11,6 +13,11 @@ class OS {
static int GetMemory(size_t *rss, size_t *vsize);
static int GetExecutablePath(char* buffer, size_t* size);
static int GetCPUInfo(v8::Local<v8::Array> *cpus);
static double GetFreeMemory();
static double GetTotalMemory();
static double GetUptime();
static int GetLoadAvg(v8::Local<v8::Array> *loads);
};

128
src/platform_cygwin.cc

@ -1,13 +1,22 @@
#include "node.h"
#include "platform.h"
#include <v8.h>
#include <sys/param.h> // for MAXPATHLEN
#include <unistd.h> // getpagesize
#include <sys/sysctl.h>
#include <sys/sysinfo.h>
#include <unistd.h> // getpagesize, sysconf
#include <stdio.h> // sscanf, snprintf
#include <string.h>
#include <windows.h>
namespace node {
using namespace v8;
static char buf[MAXPATHLEN + 1];
static char *process_title = NULL;
@ -30,12 +39,12 @@ static void _winapi_perror(const char* prefix = NULL) {
}
char** OS::SetupArgs(int argc, char *argv[]) {
char** Platform::SetupArgs(int argc, char *argv[]) {
return argv;
}
void OS::SetProcessTitle(char *title) {
void Platform::SetProcessTitle(char *title) {
// We need to convert _title_ to UTF-16 first, because that's what windows uses internally.
// It would be more efficient to use the UTF-16 value that we can obtain from v8,
// but it's not accessible from here.
@ -139,7 +148,7 @@ static inline char* _getProcessTitle() {
}
const char* OS::GetProcessTitle(int *len) {
const char* Platform::GetProcessTitle(int *len) {
// If the process_title was never read before nor explicitly set,
// we must query it with getConsoleTitleW
if (!process_title) {
@ -156,7 +165,7 @@ const char* OS::GetProcessTitle(int *len) {
}
int OS::GetMemory(size_t *rss, size_t *vsize) {
int Platform::GetMemory(size_t *rss, size_t *vsize) {
FILE *f = fopen("/proc/self/stat", "r");
if (!f) return -1;
@ -236,11 +245,118 @@ error:
}
int OS::GetExecutablePath(char* buffer, size_t* size) {
int Platform::GetExecutablePath(char* buffer, size_t* size) {
*size = readlink("/proc/self/exe", buffer, *size - 1);
if (*size <= 0) return -1;
buffer[*size] = '\0';
return 0;
}
int Platform::GetCPUInfo(Local<Array> *cpus) {
Local<Object> cpuinfo;
Local<Object> cputimes;
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
int numcpus = 0, i = 0;
unsigned long long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr;
char line[512], speedPath[256], model[512];
FILE *fpStat = fopen("/proc/stat", "r");
FILE *fpModel = fopen("/proc/cpuinfo", "r");
FILE *fpSpeed;
if (fpModel) {
while (fgets(line, 511, fpModel) != NULL) {
if (strncmp(line, "model name", 10) == 0) {
numcpus++;
if (numcpus == 1) {
char *p = strchr(line, ':') + 2;
strcpy(model, p);
model[strlen(model)-1] = 0;
}
} else if (strncmp(line, "cpu MHz", 7) == 0) {
if (numcpus == 1) {
sscanf(line, "%*s %*s : %u", &cpuspeed);
}
}
}
fclose(fpModel);
}
*cpus = Array::New(numcpus);
if (fpStat) {
while (fgets(line, 511, fpStat) != NULL) {
if (strncmp(line, "cpu ", 4) == 0)
continue;
else if (strncmp(line, "intr ", 5) == 0)
break;
sscanf(line, "%*s %llu %llu %llu %llu %*llu %llu",
&ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr);
snprintf(speedPath, sizeof(speedPath),
"/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i);
fpSpeed = fopen(speedPath, "r");
if (fpSpeed) {
if (fgets(line, 511, fpSpeed) != NULL) {
sscanf(line, "%u", &cpuspeed);
cpuspeed /= 1000;
}
fclose(fpSpeed);
}
cpuinfo = Object::New();
cputimes = Object::New();
cputimes->Set(String::New("user"), Number::New(ticks_user * multiplier));
cputimes->Set(String::New("nice"), Number::New(ticks_nice * multiplier));
cputimes->Set(String::New("sys"), Number::New(ticks_sys * multiplier));
cputimes->Set(String::New("idle"), Number::New(ticks_idle * multiplier));
cputimes->Set(String::New("irq"), Number::New(ticks_intr * multiplier));
cpuinfo->Set(String::New("model"), String::New(model));
cpuinfo->Set(String::New("speed"), Number::New(cpuspeed));
cpuinfo->Set(String::New("times"), cputimes);
(*cpus)->Set(i++, cpuinfo);
}
fclose(fpStat);
}
return 0;
}
double Platform::GetFreeMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
double pages = static_cast<double>(sysconf(_SC_AVPHYS_PAGES));
return static_cast<double>(pages * pagesize);
}
double Platform::GetTotalMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
double pages = static_cast<double>(sysconf(_SC_PHYS_PAGES));
return pages * pagesize;
}
double Platform::GetUptime() {
struct sysinfo info;
if (sysinfo(&info) < 0) {
return -1;
}
return static_cast<double>(info.uptime);
}
int Platform::GetLoadAvg(Local<Array> *loads) {
struct sysinfo info;
if (sysinfo(&info) < 0) {
return -1;
}
(*loads)->Set(0, Number::New(static_cast<double>(info.loads[0]) / 65536.0));
(*loads)->Set(1, Number::New(static_cast<double>(info.loads[1]) / 65536.0));
(*loads)->Set(2, Number::New(static_cast<double>(info.loads[2]) / 65536.0));
return 0;
}
} // namespace node

131
src/platform_darwin.cc

@ -1,27 +1,38 @@
#include "node.h"
#include "platform.h"
#include <v8.h>
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/mach.h>
#include <mach/mach_host.h>
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
#include <limits.h> /* PATH_MAX */
#include <unistd.h> // sysconf
#include <sys/param.h>
#include <sys/sysctl.h>
#include <time.h>
namespace node {
using namespace v8;
static char *process_title;
char** OS::SetupArgs(int argc, char *argv[]) {
char** Platform::SetupArgs(int argc, char *argv[]) {
process_title = argc ? strdup(argv[0]) : NULL;
return argv;
}
// OS::SetProcessTitle implemented in platform_darwin_proctitle.cc
// Platform::SetProcessTitle implemented in platform_darwin_proctitle.cc
} // namespace node
#include "platform_darwin_proctitle.cc"
namespace node {
const char* OS::GetProcessTitle(int *len) {
const char* Platform::GetProcessTitle(int *len) {
if (process_title) {
*len = strlen(process_title);
return process_title;
@ -32,7 +43,7 @@ const char* OS::GetProcessTitle(int *len) {
// Researched by Tim Becker and Michael Knight
// http://blog.kuriositaet.de/?p=257
int OS::GetMemory(size_t *rss, size_t *vsize) {
int Platform::GetMemory(size_t *rss, size_t *vsize) {
struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
@ -50,7 +61,7 @@ int OS::GetMemory(size_t *rss, size_t *vsize) {
}
int OS::GetExecutablePath(char* buffer, size_t* size) {
int Platform::GetExecutablePath(char* buffer, size_t* size) {
uint32_t usize = *size;
int result = _NSGetExecutablePath(buffer, &usize);
if (result) return result;
@ -68,4 +79,112 @@ int OS::GetExecutablePath(char* buffer, size_t* size) {
return 0;
}
int Platform::GetCPUInfo(Local<Array> *cpus) {
Local<Object> cpuinfo;
Local<Object> cputimes;
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks);
char model[512];
uint64_t cpuspeed;
size_t size;
size = sizeof(model);
if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
return -1;
}
size = sizeof(cpuspeed);
if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0) < 0) {
return -1;
}
natural_t numcpus;
mach_msg_type_number_t count;
processor_cpu_load_info_data_t *info;
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
reinterpret_cast<processor_info_array_t*>(&info),
&count) != KERN_SUCCESS) {
return -1;
}
*cpus = Array::New(numcpus);
for (int i = 0; i < numcpus; i++) {
cpuinfo = Object::New();
cputimes = Object::New();
cputimes->Set(String::New("user"),
Number::New((uint64_t)(info[i].cpu_ticks[0]) * multiplier));
cputimes->Set(String::New("nice"),
Number::New((uint64_t)(info[i].cpu_ticks[3]) * multiplier));
cputimes->Set(String::New("sys"),
Number::New((uint64_t)(info[i].cpu_ticks[1]) * multiplier));
cputimes->Set(String::New("idle"),
Number::New((uint64_t)(info[i].cpu_ticks[2]) * multiplier));
cputimes->Set(String::New("irq"), Number::New(0));
cpuinfo->Set(String::New("model"), String::New(model));
cpuinfo->Set(String::New("speed"), Number::New(cpuspeed/1000000));
cpuinfo->Set(String::New("times"), cputimes);
(*cpus)->Set(i, cpuinfo);
}
vm_deallocate(mach_task_self(), (vm_address_t)info, count);
return 0;
}
double Platform::GetFreeMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
vm_statistics_data_t info;
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
if (host_statistics(mach_host_self(), HOST_VM_INFO,
(host_info_t)&info, &count) != KERN_SUCCESS) {
return -1;
}
return (static_cast<double>(info.free_count)) * pagesize;
}
double Platform::GetTotalMemory() {
uint64_t info;
static int which[] = {CTL_HW, HW_MEMSIZE};
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
return static_cast<double>(info);
}
double Platform::GetUptime() {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
now = time(NULL);
return static_cast<double>(now - info.tv_sec);
}
int Platform::GetLoadAvg(Local<Array> *loads) {
struct loadavg info;
size_t size = sizeof(info);
static int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
(*loads)->Set(0, Number::New(static_cast<double>(info.ldavg[0])
/ static_cast<double>(info.fscale)));
(*loads)->Set(1, Number::New(static_cast<double>(info.ldavg[1])
/ static_cast<double>(info.fscale)));
(*loads)->Set(2, Number::New(static_cast<double>(info.ldavg[2])
/ static_cast<double>(info.fscale)));
return 0;
}
} // namespace node

2
src/platform_darwin_proctitle.cc

@ -38,7 +38,7 @@
namespace node {
void OS::SetProcessTitle(char *title) {
void Platform::SetProcessTitle(char *title) {
static int symbol_lookup_status = 0; // 1=ok, 2=unavailable
if (symbol_lookup_status == 2) {
// feature is unavailable

139
src/platform_freebsd.cc

@ -1,33 +1,41 @@
#include "node.h"
#include "platform.h"
#include <v8.h>
#include <stdlib.h>
#include <kvm.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/dkstat.h>
#include <vm/vm_param.h>
#include <string.h>
#include <paths.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
namespace node {
using namespace v8;
static char *process_title;
char** OS::SetupArgs(int argc, char *argv[]) {
char** Platform::SetupArgs(int argc, char *argv[]) {
process_title = argc ? strdup(argv[0]) : NULL;
return argv;
}
void OS::SetProcessTitle(char *title) {
void Platform::SetProcessTitle(char *title) {
if (process_title) free(process_title);
process_title = strdup(title);
setproctitle(title);
}
const char* OS::GetProcessTitle(int *len) {
const char* Platform::GetProcessTitle(int *len) {
if (process_title) {
*len = strlen(process_title);
return process_title;
@ -36,7 +44,7 @@ const char* OS::GetProcessTitle(int *len) {
return NULL;
}
int OS::GetMemory(size_t *rss, size_t *vsize) {
int Platform::GetMemory(size_t *rss, size_t *vsize) {
kvm_t *kd = NULL;
struct kinfo_proc *kinfo = NULL;
pid_t pid;
@ -64,7 +72,7 @@ error:
}
int OS::GetExecutablePath(char* buffer, size_t* size) {
int Platform::GetExecutablePath(char* buffer, size_t* size) {
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
@ -78,4 +86,125 @@ int OS::GetExecutablePath(char* buffer, size_t* size) {
return 0;
}
int Platform::GetCPUInfo(Local<Array> *cpus) {
Local<Object> cpuinfo;
Local<Object> cputimes;
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
cur = 0;
char model[512];
int numcpus;
size_t size;
size = sizeof(model);
if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
return -1;
}
size = sizeof(numcpus);
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0) < 0) {
return -1;
}
*cpus = Array::New(numcpus);
size = sizeof(cpuspeed);
if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0) < 0) {
return -1;
}
// kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of ncpu
size = sizeof(maxcpus);
if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
return -1;
}
size = maxcpus * CPUSTATES * sizeof(long);
long cp_times[size];
if (sysctlbyname("kern.cp_times", &cp_times, &size, NULL, 0) < 0) {
return -1;
}
for (int i = 0; i < numcpus; i++) {
cpuinfo = Object::New();
cputimes = Object::New();
cputimes->Set(String::New("user"),
Number::New((uint64_t)(cp_times[CP_USER+cur]) * multiplier));
cputimes->Set(String::New("nice"),
Number::New((uint64_t)(cp_times[CP_NICE+cur]) * multiplier));
cputimes->Set(String::New("sys"),
Number::New((uint64_t)(cp_times[CP_SYS+cur]) * multiplier));
cputimes->Set(String::New("idle"),
Number::New((uint64_t)(cp_times[CP_IDLE+cur]) * multiplier));
cputimes->Set(String::New("irq"),
Number::New((uint64_t)(cp_times[CP_INTR+cur]) * multiplier));
cpuinfo->Set(String::New("model"), String::New(model));
cpuinfo->Set(String::New("speed"), Number::New(cpuspeed));
cpuinfo->Set(String::New("times"), cputimes);
(*cpus)->Set(i, cpuinfo);
cur+=CPUSTATES;
}
return 0;
}
double Platform::GetFreeMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
unsigned long info;
size_t size = sizeof(info);
if (sysctlbyname("vm.stats.vm.v_free_count", &info, &size, NULL, 0) < 0) {
return -1;
}
return (static_cast<double>(info)) * pagesize;
}
double Platform::GetTotalMemory() {
#if defined(HW_PHYSMEM64)
uint64_t info;
static int which[] = {CTL_HW, HW_PHYSMEM64};
#else
unsigned int info;
static int which[] = {CTL_HW, HW_PHYSMEM};
#endif
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
return static_cast<double>(info);
}
double Platform::GetUptime() {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
now = time(NULL);
return static_cast<double>(now - info.tv_sec);
}
int Platform::GetLoadAvg(Local<Array> *loads) {
struct loadavg info;
size_t size = sizeof(info);
static int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
(*loads)->Set(0, Number::New(static_cast<double>(info.ldavg[0])
/ static_cast<double>(info.fscale)));
(*loads)->Set(1, Number::New(static_cast<double>(info.ldavg[1])
/ static_cast<double>(info.fscale)));
(*loads)->Set(2, Number::New(static_cast<double>(info.ldavg[2])
/ static_cast<double>(info.fscale)));
return 0;
}
} // namespace node

128
src/platform_linux.cc

@ -1,8 +1,13 @@
#include "node.h"
#include "platform.h"
#include <v8.h>
#include <sys/param.h> // for MAXPATHLEN
#include <unistd.h> // getpagesize
#include <sys/sysctl.h>
#include <sys/sysinfo.h>
#include <unistd.h> // getpagesize, sysconf
#include <stdio.h> // sscanf, snprintf
/* SetProcessTitle */
#include <sys/prctl.h>
@ -10,27 +15,28 @@
#include <stdlib.h> // free
#include <string.h> // strdup
namespace node {
using namespace v8;
static char buf[MAXPATHLEN + 1];
static char *process_title;
char** OS::SetupArgs(int argc, char *argv[]) {
char** Platform::SetupArgs(int argc, char *argv[]) {
process_title = strdup(argv[0]);
return argv;
}
void OS::SetProcessTitle(char *title) {
void Platform::SetProcessTitle(char *title) {
if (process_title) free(process_title);
process_title = strdup(title);
prctl(PR_SET_NAME, process_title);
}
const char* OS::GetProcessTitle(int *len) {
const char* Platform::GetProcessTitle(int *len) {
if (process_title) {
*len = strlen(process_title);
return process_title;
@ -40,7 +46,7 @@ const char* OS::GetProcessTitle(int *len) {
}
int OS::GetMemory(size_t *rss, size_t *vsize) {
int Platform::GetMemory(size_t *rss, size_t *vsize) {
FILE *f = fopen("/proc/self/stat", "r");
if (!f) return -1;
@ -135,11 +141,119 @@ error:
}
int OS::GetExecutablePath(char* buffer, size_t* size) {
int Platform::GetExecutablePath(char* buffer, size_t* size) {
*size = readlink("/proc/self/exe", buffer, *size - 1);
if (*size <= 0) return -1;
buffer[*size] = '\0';
return 0;
}
int Platform::GetCPUInfo(Local<Array> *cpus) {
HandleScope scope;
Local<Object> cpuinfo;
Local<Object> cputimes;
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
int numcpus = 0, i = 0;
unsigned long long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr;
char line[512], speedPath[256], model[512];
FILE *fpStat = fopen("/proc/stat", "r");
FILE *fpModel = fopen("/proc/cpuinfo", "r");
FILE *fpSpeed;
if (fpModel) {
while (fgets(line, 511, fpModel) != NULL) {
if (strncmp(line, "model name", 10) == 0) {
numcpus++;
if (numcpus == 1) {
char *p = strchr(line, ':') + 2;
strcpy(model, p);
model[strlen(model)-1] = 0;
}
} else if (strncmp(line, "cpu MHz", 7) == 0) {
if (numcpus == 1) {
sscanf(line, "%*s %*s : %u", &cpuspeed);
}
}
}
fclose(fpModel);
}
*cpus = Array::New(numcpus);
if (fpStat) {
while (fgets(line, 511, fpStat) != NULL) {
if (strncmp(line, "cpu ", 4) == 0)
continue;
else if (strncmp(line, "intr ", 5) == 0)
break;
sscanf(line, "%*s %llu %llu %llu %llu %*llu %llu",
&ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr);
snprintf(speedPath, sizeof(speedPath),
"/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i);
fpSpeed = fopen(speedPath, "r");
if (fpSpeed) {
if (fgets(line, 511, fpSpeed) != NULL) {
sscanf(line, "%u", &cpuspeed);
cpuspeed /= 1000;
}
fclose(fpSpeed);
}
cpuinfo = Object::New();
cputimes = Object::New();
cputimes->Set(String::New("user"), Number::New(ticks_user * multiplier));
cputimes->Set(String::New("nice"), Number::New(ticks_nice * multiplier));
cputimes->Set(String::New("sys"), Number::New(ticks_sys * multiplier));
cputimes->Set(String::New("idle"), Number::New(ticks_idle * multiplier));
cputimes->Set(String::New("irq"), Number::New(ticks_intr * multiplier));
cpuinfo->Set(String::New("model"), String::New(model));
cpuinfo->Set(String::New("speed"), Number::New(cpuspeed));
cpuinfo->Set(String::New("times"), cputimes);
(*cpus)->Set(i++, cpuinfo);
}
fclose(fpStat);
}
return 0;
}
double Platform::GetFreeMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
double pages = static_cast<double>(sysconf(_SC_AVPHYS_PAGES));
return static_cast<double>(pages * pagesize);
}
double Platform::GetTotalMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
double pages = static_cast<double>(sysconf(_SC_PHYS_PAGES));
return pages * pagesize;
}
double Platform::GetUptime() {
struct sysinfo info;
if (sysinfo(&info) < 0) {
return -1;
}
return static_cast<double>(info.uptime);
}
int Platform::GetLoadAvg(Local<Array> *loads) {
struct sysinfo info;
if (sysinfo(&info) < 0) {
return -1;
}
(*loads)->Set(0, Number::New(static_cast<double>(info.loads[0]) / 65536.0));
(*loads)->Set(1, Number::New(static_cast<double>(info.loads[1]) / 65536.0));
(*loads)->Set(2, Number::New(static_cast<double>(info.loads[2]) / 65536.0));
return 0;
}
} // namespace node

201
src/platform_openbsd.cc

@ -0,0 +1,201 @@
#include "node.h"
#include "platform.h"
#include <v8.h>
#include <stdlib.h>
#include <kvm.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/dkstat.h>
#include <uvm/uvm_param.h>
#include <string.h>
#include <paths.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
namespace node {
using namespace v8;
static char *process_title;
char** Platform::SetupArgs(int argc, char *argv[]) {
process_title = argc ? strdup(argv[0]) : NULL;
return argv;
}
void Platform::SetProcessTitle(char *title) {
if (process_title) free(process_title);
process_title = strdup(title);
setproctitle(title);
}
const char* Platform::GetProcessTitle(int *len) {
if (process_title) {
*len = strlen(process_title);
return process_title;
}
*len = 0;
return NULL;
}
int Platform::GetMemory(size_t *rss, size_t *vsize) {
kvm_t *kd = NULL;
struct kinfo_proc2 *kinfo = NULL;
pid_t pid;
int nprocs, max_size = sizeof(struct kinfo_proc2);
size_t page_size = getpagesize();
pid = getpid();
kd = kvm_open(NULL, _PATH_MEM, NULL, O_RDONLY, "kvm_open");
if (kd == NULL) goto error;
kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
if (kinfo == NULL) goto error;
*rss = kinfo->p_vm_rssize * page_size;
*vsize = kinfo->p_uru_ixrss;
kvm_close(kd);
return 0;
error:
if (kd) kvm_close(kd);
return -1;
}
int Platform::GetExecutablePath(char* buffer, size_t* size) {
*size = 0;
return -1;
}
int Platform::GetCPUInfo(Local<Array> *cpus) {
Local<Object> cpuinfo;
Local<Object> cputimes;
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
uint64_t info[CPUSTATES];
char model[512];
int numcpus = 1;
static int which[] = {CTL_HW, HW_MODEL, NULL};
size_t size;
size = sizeof(model);
if (sysctl(which, 2, &model, &size, NULL, 0) < 0) {
return -1;
}
which[1] = HW_NCPU;
size = sizeof(numcpus);
if (sysctl(which, 2, &numcpus, &size, NULL, 0) < 0) {
return -1;
}
*cpus = Array::New(numcpus);
which[1] = HW_CPUSPEED;
size = sizeof(cpuspeed);
if (sysctl(which, 2, &cpuspeed, &size, NULL, 0) < 0) {
return -1;
}
size = sizeof(info);
which[0] = CTL_KERN;
which[1] = KERN_CPTIME2;
for (int i = 0; i < numcpus; i++) {
which[2] = i;
size = sizeof(info);
if (sysctl(which, 3, &info, &size, NULL, 0) < 0) {
return -1;
}
cpuinfo = Object::New();
cputimes = Object::New();
cputimes->Set(String::New("user"),
Number::New((uint64_t)(info[CP_USER]) * multiplier));
cputimes->Set(String::New("nice"),
Number::New((uint64_t)(info[CP_NICE]) * multiplier));
cputimes->Set(String::New("sys"),
Number::New((uint64_t)(info[CP_SYS]) * multiplier));
cputimes->Set(String::New("idle"),
Number::New((uint64_t)(info[CP_IDLE]) * multiplier));
cputimes->Set(String::New("irq"),
Number::New((uint64_t)(info[CP_INTR]) * multiplier));
cpuinfo->Set(String::New("model"), String::New(model));
cpuinfo->Set(String::New("speed"), Number::New(cpuspeed));
cpuinfo->Set(String::New("times"), cputimes);
(*cpus)->Set(i, cpuinfo);
}
return 0;
}
double Platform::GetFreeMemory() {
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
struct uvmexp info;
size_t size = sizeof(info);
static int which[] = {CTL_VM, VM_UVMEXP};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
return static_cast<double>(info.free) * pagesize;
}
double Platform::GetTotalMemory() {
#if defined(HW_PHYSMEM64)
uint64_t info;
static int which[] = {CTL_HW, HW_PHYSMEM64};
#else
unsigned int info;
static int which[] = {CTL_HW, HW_PHYSMEM};
#endif
size_t size = sizeof(info);
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
return static_cast<double>(info);
}
double Platform::GetUptime() {
time_t now;
struct timeval info;
size_t size = sizeof(info);
static int which[] = {CTL_KERN, KERN_BOOTTIME};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
now = time(NULL);
return static_cast<double>(now - info.tv_sec);
}
int Platform::GetLoadAvg(Local<Array> *loads) {
struct loadavg info;
size_t size = sizeof(info);
static int which[] = {CTL_VM, VM_LOADAVG};
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
return -1;
}
(*loads)->Set(0, Number::New(static_cast<double>(info.ldavg[0])
/ static_cast<double>(info.fscale)));
(*loads)->Set(1, Number::New(static_cast<double>(info.ldavg[1])
/ static_cast<double>(info.fscale)));
(*loads)->Set(2, Number::New(static_cast<double>(info.ldavg[2])
/ static_cast<double>(info.fscale)));
return 0;
}
} // namespace node

5
test/simple/test-os-hostname.js

@ -1,5 +0,0 @@
var common = require('../common');
var assert = require('assert');
var os = require('os');
assert.ok(os.getHostname().length > 0);

12
test/simple/test-os.js

@ -0,0 +1,12 @@
var common = require('../common');
var assert = require('assert');
var os = require('os');
assert.ok(os.hostname().length > 0);
assert.ok(os.loadavg().length > 0);
assert.ok(os.uptime() > 0);
assert.ok(os.freemem() > 0);
assert.ok(os.totalmem() > 0);
assert.ok(os.cpus().length > 0);
assert.ok(os.type().length > 0);
assert.ok(os.release().length > 0);

2
wscript

@ -197,7 +197,7 @@ def configure(conf):
conf.env.append_value("CCFLAGS", "-rdynamic")
conf.env.append_value("LINKFLAGS_DL", "-rdynamic")
if sys.platform.startswith("freebsd"):
if sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"):
conf.check(lib='kvm', uselib_store='KVM')
#if Options.options.debug:

Loading…
Cancel
Save