Permalink
Browse files

node-mmap: mmap bindings for node.js, first check-in.

  • Loading branch information...
0 parents commit 8d825d3292a1c62d7e1a9734ed28a31273031f5d @bnoordhuis committed Aug 7, 2010
Showing with 141 additions and 0 deletions.
  1. +80 −0 mmap.cc
  2. +46 −0 test.js
  3. +15 −0 wscript
80 mmap.cc
@@ -0,0 +1,80 @@
+#include <v8.h>
+#include <node.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+using namespace v8;
+using namespace node;
+
+namespace {
+
+class Buffer: public ObjectWrap {
+public:
+ Buffer(size_t size, int protection, int flags, int fd, off_t offset);
+ ~Buffer();
+
+ static Handle<Value> New(const Arguments& args);
+
+private:
+ static Persistent<String> length_symbol;
+ const size_t size;
+ void* const data;
+};
+
+Persistent<String> Buffer::length_symbol = Persistent<String>::New(String::NewSymbol("length"));
+
+Buffer::Buffer(size_t size, int protection, int flags, int fd, off_t offset): size(size), data(mmap(0, size, protection, flags, fd, 0)) {
+ if (data == MAP_FAILED) {
+ ThrowException(ErrnoException(errno, "mmap"));
+ }
+}
+
+Buffer::~Buffer() {
+ if (data != MAP_FAILED) {
+ if (munmap(data, size) < 0) {
+ // does it make sense to raise an exception here? destructor is invoked by V8's GC
+ ThrowException(ErrnoException(errno, "mmap"));
+ }
+ }
+}
+
+Handle<Value> Buffer::New(const Arguments& args) {
+ HandleScope scope;
+
+ if (args.Length() <= 3) {
+ return ThrowException(Exception::Error(String::New("Constructor takes 4 arguments: size, protection, flags, fd and offset.")));
+ }
+
+ const size_t size = args[0]->ToInteger()->Value();
+ const int protection = args[1]->ToInteger()->Value();
+ const int flags = args[2]->ToInteger()->Value();
+ const int fd = args[3]->ToInteger()->Value();
+ const off_t offset = args[4]->ToInteger()->Value();
+
+ Buffer* instance = new Buffer(size, protection, flags, fd, offset);
+ instance->Wrap(args.Holder());
+
+ args.This()->SetIndexedPropertiesToExternalArrayData(instance->data, kExternalUnsignedByteArray, instance->size);
+ args.This()->Set(length_symbol, Integer::New(instance->size), (PropertyAttribute) (ReadOnly | DontDelete));
+ return args.This();
+}
+
+extern "C" void init(Handle<Object> target) {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+ target->Set(String::NewSymbol("Buffer"), t->GetFunction());
+
+ const PropertyAttribute attribs = (PropertyAttribute) (ReadOnly | DontDelete);
+ target->Set(String::New("PROT_READ"), Integer::New(PROT_READ), attribs);
+ target->Set(String::New("PROT_WRITE"), Integer::New(PROT_WRITE), attribs);
+ target->Set(String::New("PROT_EXEC"), Integer::New(PROT_EXEC), attribs);
+ target->Set(String::New("PROT_NONE"), Integer::New(PROT_NONE), attribs);
+ target->Set(String::New("MAP_SHARED"), Integer::New(MAP_SHARED), attribs);
+ target->Set(String::New("MAP_PRIVATE"), Integer::New(MAP_PRIVATE), attribs);
+ target->Set(String::New("PAGESIZE"), Integer::New(sysconf(_SC_PAGESIZE)), attribs);
+}
+
+}
46 test.js
@@ -0,0 +1,46 @@
+fs = require('fs');
+sys = require('sys');
+mmap = require('mmap');
+assert = require('assert');
+
+Buffer = mmap.Buffer;
+PAGESIZE = mmap.PAGESIZE;
+PROT_READ = mmap.PROT_READ;
+MAP_SHARED = mmap.MAP_SHARED;
+
+_ = function(what) { sys.puts(sys.inspect(what)); };
+
+// open self (this script)
+fd = fs.openSync(process.argv[1], 'r');
+size = fs.fstatSync(fd).size;
+
+// full 5-arg constructor
+buffer = new Buffer(size, PROT_READ, MAP_SHARED, fd, 0);
+assert.equal(buffer.length, size);
+
+// short-hand 4-arg constructor
+buffer = new Buffer(size, PROT_READ, MAP_SHARED, fd);
+assert.equal(buffer.length, size);
+
+// page size is almost certainly >= 4K and this script isn't that large...
+fd = fs.openSync(process.argv[1], 'r');
+buffer = new Buffer(size, PROT_READ, MAP_SHARED, fd, PAGESIZE);
+assert.equal(buffer.length, size); // ...but this is according to spec
+
+// zero size should throw exception
+fd = fs.openSync(process.argv[1], 'r');
+try {
+ buffer = new Buffer(0, PROT_READ, MAP_SHARED, fd, 0);
+} catch (e) {
+ assert.equal(e.errno, process.EINVAL);
+}
+
+// non-page size offset should throw exception
+if (PAGESIZE != 1) {
+ fd = fs.openSync(process.argv[1], 'r');
+ try {
+ buffer = new Buffer(size, PROT_READ, MAP_SHARED, fd, 1);
+ } catch (e) {
+ assert.equal(e.errno, process.EINVAL);
+ }
+}
15 wscript
@@ -0,0 +1,15 @@
+srcdir = '.'
+blddir = 'build'
+VERSION = '1.0.0'
+
+def set_options(ctx):
+ ctx.tool_options('compiler_cxx')
+
+def configure(ctx):
+ ctx.check_tool('compiler_cxx')
+ ctx.check_tool('node_addon')
+
+def build(ctx):
+ t = ctx.new_task_gen('cxx', 'shlib', 'node_addon')
+ t.target = 'mmap'
+ t.source = 'mmap.cc'

0 comments on commit 8d825d3

Please sign in to comment.