Permalink
Browse files

implement MappedBuffer create interfaces;

  • Loading branch information...
1 parent 18a75bc commit e049fb7b364d5fea700997cb655323d79540a723 @kazupon committed Oct 26, 2012
Showing with 383 additions and 3 deletions.
  1. +11 −2 Makefile
  2. +20 −0 binding.gyp
  3. +5 −0 lib/mappedbuffer.js
  4. +1 −1 package.json
  5. +20 −0 src/debug.h
  6. +231 −0 src/mappedbuffer.cc
  7. +60 −0 src/mappedbuffer.h
  8. +35 −0 src/utils.h
View
@@ -10,13 +10,22 @@ endif
TARGET = build/${BUILDTYPE}/mappedbuffer.node
+all: $(TARGET)
+
+$(TARGET): src/mappedbuffer.cc
+ node-gyp rebuild ${GYP_BUILD_TYPE}
+
+clean:
+ node-gyp clean
+ rm -rf build
+
distclean: clean
rm -rf node_modules
node_modules: package.json
npm install
-test: node_modules
+test: node_modules $(TARGET)
./node_modules/.bin/mocha --reporter spec test/*.js
-.PHONY: test
+.PHONY: test node_modules distclean clean all
View
@@ -0,0 +1,20 @@
+{
+ 'target_defaults': {
+ 'configurations': {
+ 'Debug': {
+ 'defines': [ 'DEBUG', '_DEBUG' ]
+ },
+ 'Release': {
+ 'defines': [ 'NDEBUG' ]
+ }
+ }
+ },
+ 'targets': [
+ {
+ 'target_name': 'mappedbuffer',
+ 'sources': [
+ 'src/mappedbuffer.cc'
+ ]
+ }
+ ]
+}
View
@@ -0,0 +1,5 @@
+'use strict';
+
+var mappedbuffer = require('bindings')('mappedbuffer.node');
+
+module.exports = mappedbuffer;
View
@@ -21,6 +21,6 @@
"should": "*"
},
"engines": {
- "node": ">= 0.8.12"
+ "node": ">= 0.8.14"
}
}
View
@@ -0,0 +1,20 @@
+/*
+ * debug utilities.
+ * Copyright (C) 2012 kazuya kawaguchi. See Copyright Notice in mappedbuffer.h
+ */
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#if defined(NDEBUG) && NDEBUG
+#define TRACE(fmt, ...) ((void)0)
+#else
+#define TRACE(fmt, ...) \
+ do { \
+ fprintf(stderr, "%s: %d: (%p) %s: " fmt, __FILE__, __LINE__, pthread_self(), __func__, ##__VA_ARGS__); \
+ } while (0)
+#endif /* DEBUG */
+
+
+#endif /* __DEBUG_H__ */
+
View
@@ -0,0 +1,231 @@
+/*
+ * mappedbuffer main
+ * Copyright (C) 2012 kazuya kawaguchi. See Copyright Notice in mappedbuffer.h
+ */
+
+#define BUILDING_NODE_EXTENSION
+
+#include "mappedbuffer.h"
+#include "debug.h"
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+typedef struct mmap_req_t {
+ size_t size;
+ int32_t protection;
+ int32_t flags;
+ int32_t fd;
+ off_t offset;
+ char *map;
+ Persistent<Object> obj;
+ Persistent<Function> cb;
+};
+
+
+static Persistent<String> length_symbol;
+Persistent<Function> MappedBuffer::ctor;
+
+
+MappedBuffer::MappedBuffer(
+ Handle<Object> wrapper, size_t size, int32_t protection,
+ int32_t flags, int32_t fd, off_t offset, char *data)
+ : map_(NULL), length_(0), released_(false), ObjectWrap() {
+ TRACE(
+ "constructor: size=%ld, protectio=%d, flags=%d, fd=%d, offset=%lld, data=%p\n",
+ size, protection, flags, fd, offset, data
+ );
+ Wrap(wrapper);
+
+ if (data == NULL) {
+ map_ = (char *)mmap(NULL, size, protection, flags, fd, offset);
+ TRACE("mmap: map_=%p\n", map_);
+ } else {
+ map_ = data;
+ }
+ length_ = size;
+ if (map_ == MAP_FAILED) {
+ length_ = 0;
+ }
+ handle_->Set(length_symbol, Integer::NewFromUnsigned(length_));
+}
+
+MappedBuffer::~MappedBuffer() {
+ TRACE("destructor\n");
+ if (!released_ && map_ != NULL && length_ > 0) {
+ munmap(map_, length_);
+ TRACE("munmap\n");
+ released_ = true;
+ }
+}
+
+Handle<Value> MappedBuffer::New(const Arguments &args) {
+ HandleScope scope;
+ TRACE("New\n");
+
+ if (!args.IsConstructCall()) {
+ const int argc = args.Length();
+ Local<Value> *argv = new Local<Value>[argc];
+ for (int i = 0; i < argc; ++i) {
+ argv[i] = args[i];
+ }
+ Local<Object> instance = ctor->NewInstance(argc, argv);
+ delete[] argv;
+ return scope.Close(instance);
+ }
+
+
+ if (args.Length() <= 3) {
+ return ThrowException(Exception::Error(String::New("Bad argument")));
+ }
+
+ const size_t size = args[0]->ToInteger()->Value();
+ const int32_t protection = args[1]->ToInteger()->Value();
+ const int32_t flags = args[2]->ToInteger()->Value();
+ const int32_t fd = args[3]->ToInteger()->Value();
+ mmap_req_t *req = NULL;
+ off_t offset = 0;
+
+ if (args.Length() == 5) {
+ if (args[4]->IsFunction()) {
+ req = reinterpret_cast<mmap_req_t *>(malloc(sizeof(mmap_req_t)));
+ req->size = size;
+ req->protection = protection;
+ req->flags = flags;
+ req->fd = fd;
+ req->offset = offset;
+ req->map = NULL;
+ req->obj = Persistent<Object>::New(Handle<Object>::Cast(args.This()));
+ req->cb = Persistent<Function>::New(Handle<Function>::Cast(args[4]));
+ } else {
+ offset = args[4]->ToInteger()->Value();
+ }
+ } else if (args.Length() == 6) {
+ req = reinterpret_cast<mmap_req_t *>(malloc(sizeof(mmap_req_t)));
+ req->size = size;
+ req->protection = protection;
+ req->flags = flags;
+ req->fd = fd;
+ req->offset = args[4]->ToInteger()->Value();
+ req->map = NULL;
+ req->obj = Persistent<Object>::New(Handle<Object>::Cast(args.This()));
+ req->cb = Persistent<Function>::New(Handle<Function>::Cast(args[5]));
+ }
+
+ if (req == NULL) { // sync
+ MappedBuffer *obj = new MappedBuffer(
+ args.This(), size, protection, flags, fd, offset, NULL
+ );
+ return args.This();
+ } else { // async
+ uv_work_t *uv_req = reinterpret_cast<uv_work_t*>(malloc(sizeof(uv_work_t)));
+ assert(uv_req != NULL);
+ uv_req->data = req;
+
+ int32_t ret = uv_queue_work(uv_default_loop(), uv_req, OnWork, OnWorkDone);
+ TRACE("uv_queue_work: ret=%d\n", ret);
+ assert(ret == 0);
+ return scope.Close(args.This());
+ }
+}
+
+void MappedBuffer::OnWork(uv_work_t *work_req) {
+ TRACE("work_req=%p\n", work_req);
+
+ mmap_req_t *req = reinterpret_cast<mmap_req_t *>(work_req->data);
+ assert(req != NULL);
+
+ req->map = (char *)mmap(NULL, req->size, req->protection, req->flags, req->fd, req->offset);
+ TRACE("mmap: map =%p\n", req->map);
+}
+
+void MappedBuffer::OnWorkDone(uv_work_t *work_req) {
+ HandleScope scope;
+ TRACE("work_req=%p\n", work_req);
+
+ mmap_req_t *req = static_cast<mmap_req_t *>(work_req->data);
+ assert(req != NULL);
+
+ // init callback arguments.
+ int32_t argc = 0;
+ Local<Value> argv[2] = {
+ Local<Value>::New(Null()),
+ Local<Value>::New(Null()),
+ };
+
+ // set error to callback arguments.
+ if (req->map == MAP_FAILED) {
+ const char *name = "mmap error";
+ Local<String> message = String::NewSymbol(name);
+ Local<Value> err = Exception::Error(message);
+ argv[argc] = err;
+ }
+ argc++;
+
+ MappedBuffer *raw = new MappedBuffer(
+ req->obj, req->size, req->protection, req->flags, req->fd, req->offset, req->map
+ );
+ Local<Value> buf = Local<Value>::New(raw->handle_);
+ argv[argc++] = buf;
+
+ // execute callback
+ if (!req->cb.IsEmpty()) {
+ TryCatch try_catch;
+ MakeCallback(Context::GetCurrent()->Global(), req->cb, argc, argv);
+ if (try_catch.HasCaught()) {
+ FatalException(try_catch);
+ }
+ }
+
+ // releases
+ req->cb.Dispose();
+ req->obj.Dispose();
+ req->map = NULL;
+ free(req);
+ work_req->data = NULL;
+ free(work_req);
+}
+
+void MappedBuffer::Init(Handle<Object> target) {
+ TRACE("load MappedBuffer module: target=%p\n", &target);
+
+ length_symbol = NODE_PSYMBOL("length");
+
+ // prepare constructor template
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(String::NewSymbol("MappedBuffer"));
+
+ Local<ObjectTemplate> insttpl = tpl->InstanceTemplate();
+ insttpl->SetInternalFieldCount(1);
+
+ // prototype
+ Local<ObjectTemplate> prottpl = tpl->PrototypeTemplate();
+
+ ctor = Persistent<Function>::New(tpl->GetFunction());
+ target->Set(String::NewSymbol("MappedBuffer"), ctor);
+
+ // define constants
+ NODE_DEFINE_CONSTANT(ctor, PROT_READ);
+ NODE_DEFINE_CONSTANT(ctor, PROT_NONE);
+ NODE_DEFINE_CONSTANT(ctor, PROT_READ);
+ NODE_DEFINE_CONSTANT(ctor, PROT_WRITE);
+ NODE_DEFINE_CONSTANT(ctor, PROT_EXEC);
+ NODE_DEFINE_CONSTANT(ctor, MAP_SHARED);
+ NODE_DEFINE_CONSTANT(ctor, MAP_PRIVATE);
+ NODE_DEFINE_CONSTANT(ctor, MAP_NORESERVE);
+ NODE_DEFINE_CONSTANT(ctor, MAP_FIXED);
+ ctor->Set(
+ String::NewSymbol("PAGESIZE"), Integer::New(sysconf(_SC_PAGESIZE)),
+ static_cast<PropertyAttribute>(ReadOnly | DontDelete)
+ );
+}
+
+
+void init(Handle<Object> target) {
+ TRACE("load mappedbuffer module\n");
+
+ MappedBuffer::Init(target);
+}
+
+NODE_MODULE(mappedbuffer, init);
View
@@ -0,0 +1,60 @@
+/*
+ * node-mappedbuffer -- Buffer to store the memory that is mapped by the `mmap`
+ * Copyright (C) 2012 kazuya kawaguchi. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+ */
+
+#ifndef __MAPPED_BUFFER_H__
+#define __MAPPED_BUFFER_H__
+
+#include <node.h>
+
+using namespace node;
+using namespace v8;
+
+
+class MappedBuffer : public ObjectWrap {
+ public:
+ static Persistent<Function> ctor;
+ static void Init(Handle<Object> target);
+
+ private:
+ char *map_;
+ size_t length_;
+ bool released_;
+
+ MappedBuffer(
+ Handle<Object> wrapper, size_t size, int32_t protection,
+ int32_t flags, int32_t fd, off_t offset, char *data
+ );
+ ~MappedBuffer();
+
+ static Handle<Value> New(const Arguments &args);
+
+ static void OnWork(uv_work_t *work_req);
+ static void OnWorkDone(uv_work_t *work_req);
+};
+
+
+#endif /* __MAPPED_BUFFER_H__ */
+
Oops, something went wrong.

0 comments on commit e049fb7

Please sign in to comment.