Browse files

Add a native addon to provide loop/unloop functionality for sync oper…

…ations. Expose on index module for others as well
  • Loading branch information...
1 parent bdc97a0 commit 4362b84751a15e7ec02c71cdd25e970c5acd6bd1 Charles Jolley committed Mar 12, 2010
Showing with 248 additions and 37 deletions.
  1. +3 −0 .gitignore
  2. +3 −2 lib/co.js
  3. +5 −0 lib/index.js
  4. +12 −0 lib/private/loop.js
  5. +6 −2 lib/sandbox.js
  6. +80 −33 scripts/setup.js
  7. +45 −0 src/loop.cc
  8. +65 −0 tests/loop.js
  9. +29 −0 wscript
View
3 .gitignore
@@ -1 +1,4 @@
tmp
+build
+loop.node
+.lock-wscript
View
5 lib/co.js
@@ -284,6 +284,7 @@ Co.once = function(action, context) {
be thrown.
*/
Co.wait = function(cont, context) {
+ var LOOP = require('./private/loop');
var looped = false,
unlooped = false,
ret ;
@@ -299,12 +300,12 @@ Co.wait = function(cont, context) {
}
unlooped = true;
- if (looped) process.unloop();
+ if (looped) LOOP.unloop();
};
cont.apply(context, args);
looped = true;
- if (!unlooped) process.loop(); // wait until finished
+ if (!unlooped) LOOP.loop(); // wait until finished
return ret;
};
View
5 lib/index.js
@@ -46,3 +46,8 @@ Co.wait(function(done) {
});
});
+// export the native LOOP api so that other packages can use it
+var LOOP = require('./private/loop');
+seed.loop = LOOP.loop;
+seed.unloop = LOOP.unloop;
+
View
12 lib/private/loop.js
@@ -0,0 +1,12 @@
+// ==========================================================================
+// Project: Seed - CommonJS Runtime
+// Copyright: ©2009-2010 Apple Inc. All rights reserved.
+// License: Licened under MIT license (see __preamble__.js)
+// ==========================================================================
+
+// Need to use nodeRequire() explicitly until Seed loader can handle native
+// extensions
+
+var nodeRequire = require.nodeRequire || require;
+module.exports = nodeRequire('../../build/default/loop');
+
View
8 lib/sandbox.js
@@ -7,6 +7,8 @@
var Co = require('./co');
var Sandbox ;
+var LOOP; // imported on demand by sync require
+
/**
@file
@@ -223,6 +225,8 @@ Sandbox = function Sandbox(id, seed) {
// add sync version
requireSync = function(m, p, moduleId, pkg) {
+ if (!LOOP) LOOP = require('./private/loop');
+
var looped = false,
unlooped = false,
error = null,
@@ -232,11 +236,11 @@ Sandbox = function Sandbox(id, seed) {
exports = exp;
error = err;
unlooped = true;
- if (looped) process.unloop();
+ if (looped) LOOP.unloop();
});
looped = true;
- if (!unlooped) process.loop();
+ if (!unlooped) LOOP.loop();
if (error) throw error;
return exports;
View
113 scripts/setup.js
@@ -1,44 +1,91 @@
#!/usr/bin/env node
+// ==========================================================================
+// Project: Seed - Flexible Package Manager
+// Copyright: ©2009-2010 Apple Inc. All rights reserved.
+// License: Licened under MIT license
+// ==========================================================================
+/*globals __dirname process */
+
+// Runs once to install seed.
var Co = require('../lib/co');
-var SEED_DIR = Co.path.normalize(Co.path.join(__dirname, '..'));
-var NODE_LIBRARIES = Co.path.join(process.env.HOME, '.node_libraries');
-var SEED_REPO_BIN = Co.path.join(process.env.HOME, '.seeds', 'bin');
+var SEED_DIR = Co.path.normalize(Co.path.join(__dirname, '..')),
+ NODE_LIBRARIES = Co.path.join(process.env.HOME, '.node_libraries'),
+ SEED_REPO_BIN = Co.path.join(process.env.HOME, '.seeds', 'bin');
-Co.fs.mkdir_p(NODE_LIBRARIES, 0777, function(err) {
- if (err) throw err;
-
- var path = Co.path.join(NODE_LIBRARIES,'seed');
- var cmd = 'ln -s ' + SEED_DIR + ' ' + path;
- Co.path.exists(path, function(err, exists) {
- if (exists) Co.sys.puts('~/.node_libraries/seed already exists');
- else {
- Co.sys.exec(cmd, function(err) {
- if (err) Co.sys.puts(cmd + ' FAILED!');
- else Co.sys.puts(cmd + ' SUCCESS');
- });
- }
+var O_RWX = 511; //0777
+
+// Step 1: Configure and build native extensions
+Co.chain(function(done) {
+ var cmd = 'cd '+SEED_DIR+'; node-waf configure build';
+ Co.sys.puts(cmd);
+ Co.sys.exec(cmd, function(err, str) {
+ if (err) return done(err);
+ Co.sys.puts(str);
+ return done();
});
-
-});
-Co.fs.mkdir_p(SEED_REPO_BIN, 0777, function(err) {
- if (err) throw err;
- var src = Co.path.join(SEED_DIR, 'bin','seed');
- var dst = Co.path.join(SEED_REPO_BIN, 'seed');
-
- var cmd = 'ln -s ' +src + ' ' +dst;
- Co.path.exists(dst, function(err, exists) {
- if (exists) Co.sys.puts('~/.seeds/bin/seed already exists');
- else {
- Co.sys.puts(cmd);
- Co.sys.exec(cmd, function(err) {
- if (err) Co.sys.puts(cmd + ' FAILED!');
- else Co.sys.puts(cmd + ' SUCCESS');
- });
+// Step 2: Copy or symlink seed into node_libraries. If env.MODE = 'dev'
+// link only
+}, function(done) {
+
+ Co.fs.mkdir_p(NODE_LIBRARIES, O_RWX, function(err) {
+ if (err) throw err;
+
+ var path = Co.path.join(NODE_LIBRARIES,'seed'), cmd;
+
+ var mode = (process.env.MODE || 'dev').toLowerCase();
+ if (mode === 'dev') {
+ cmd = 'ln -s ' + SEED_DIR + ' ' + path;
+ } else {
+ cmd = 'cp -r ' + SEED_DIR + ' ' + path;
}
+
+ Co.path.exists(path, function(err, exists) {
+ if (exists && !process.env.FORCE) {
+ Co.sys.puts('WARNING: ~/.node_libraries/seed already exists');
+ return done();
+
+ } else {
+ Co.sys.exec(cmd, Co.err(done));
+ }
+ });
+
});
-});
+// Step 3: Copy seed/bin/* to .seeds/bin dir
+}, function(done) {
+ Co.fs.mkdir_p(SEED_REPO_BIN, O_RWX, function(err) {
+ if (err) throw err;
+
+ var SRC_DIR = Co.path.join(SEED_DIR, 'bin');
+ Co.fs.readdir_p(SRC_DIR, function(err, bins) {
+ if (err) return done(err);
+ if (!bins) bins = [];
+
+ Co.each(bins, function(filename, done) {
+ var src = Co.path.join(SRC_DIR, filename);
+ var dst = Co.path.join(SEED_REPO_BIN, filename);
+ var cmd = 'ln -s '+src+' '+dst;
+
+ Co.path.exists(dst, function(err, exists) {
+ if (exists && !process.env.FORCE) {
+ Co.sys.puts('~/.seed/bin/'+filename+' already exists');
+ return done(); // skip
+ } else {
+ Co.sys.puts(cmd);
+ Co.sys.exec(cmd, Co.err(done));
+ }
+ });
+
+ })(done);
+ });
+ });
+
+
+})(function(err) {
+ if (err) Co.sys.puts("Failed: " + err);
+ else Co.sys.puts("Done");
+});
View
45 src/loop.cc
@@ -0,0 +1,45 @@
+// ==========================================================================
+// Project: Seed - Flexible Package Manager
+// Copyright: ©2009-2010 Apple Inc. All rights reserved.
+// License: Licened under MIT license
+// ==========================================================================
+
+// Expose loop/unloop actions from libev
+
+#include <node.h>
+#include <string.h>
+
+using namespace v8;
+
+static Handle<Value> Loop(const Arguments& args) {
+ HandleScope scope;
+ ev_loop(EV_DEFAULT_UC_ 0);
+ return Undefined();
+}
+
+static Handle<Value> Unloop(const Arguments& args) {
+ HandleScope scope;
+ int how = EVUNLOOP_ONE;
+ if (args[0]->IsString()) {
+ String::Utf8Value how_s(args[0]->ToString());
+ if (0 == strcmp(*how_s, "all")) {
+ how = EVUNLOOP_ALL;
+ }
+ }
+ ev_unloop(EV_DEFAULT_ how);
+ return Undefined();
+}
+
+extern "C" void
+init (Handle<Object> target)
+{
+ HandleScope scope;
+ target->Set(
+ String::NewSymbol("loop"),
+ FunctionTemplate::New(Loop)->GetFunction());
+
+ target->Set(
+ String::NewSymbol("unloop"),
+ FunctionTemplate::New(Unloop)->GetFunction());
+}
+
View
65 tests/loop.js
@@ -0,0 +1,65 @@
+// ==========================================================================
+// Project: Seed - Flexible Package Manager
+// Copyright: ©2009-2010 Apple Inc. All rights reserved.
+// License: Licened under MIT license (see __preamble__.js)
+// ==========================================================================
+/*global process path sys assert libDir __filename */
+
+process.mixin(require('./common'));
+
+var loop = require('private/loop');
+
+var Co = require('co');
+
+Co.fs.stat(__filename, function(err, stat) {
+ Co.sys.puts("stat1");
+
+ var looped = false;
+ var unlooped = false;
+ var timer ;
+
+ function fire() {
+ unlooped = true;
+ if (looped) {
+ looped = false;
+ loop.unloop();
+ }
+
+ if (timer) {
+ clearTimeout(timer);
+ timer = null;
+ }
+ }
+
+ Co.fs.stat(__filename, function(err, stat2) {
+ Co.sys.puts("stat2");
+ fire();
+ });
+
+ timer = setTimeout(function() {
+ Co.sys.puts('unloop');
+ fire();
+ });
+
+ if (!unlooped) {
+ looped = true;
+ loop.loop(); // wait
+ }
+
+});
+
+// var i = 0;
+//
+// function sched(again) {
+// var iter = i++;
+// setTimeout(function() {
+// if (again) sched(false);
+// sys.puts("unloop "+iter);
+// loop.unloop();
+// }, 1000);
+//
+// sys.puts("loop "+iter);
+// loop.loop();
+// }
+//
+// sched(true);
View
29 wscript
@@ -0,0 +1,29 @@
+import Options
+from os import unlink, symlink, popen
+from os.path import exists
+
+srcdir = '.'
+blddir = 'build'
+VERSION = '0.1.0'
+
+def set_options(opt):
+ opt.tool_options('compiler_cxx')
+
+def configure(conf):
+ conf.check_tool('compiler_cxx')
+ conf.check_tool('node_addon')
+
+def build(bld):
+ obj = bld.new_task_gen('cxx', 'shlib', 'node_addon')
+ obj.target = 'loop'
+ obj.source = "src/loop.cc"
+
+
+def shutdown():
+ # HACK to get binding.node out of build directory.
+ # better way to do this?
+ if Options.commands['clean']:
+ if exists('loop.node'): unlink('loop.node')
+ else:
+ if exists('build/default/loop.node') and not exists('loop.node'):
+ symlink('build/default/loop.node', 'loop.node')

0 comments on commit 4362b84

Please sign in to comment.