Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
add a second domain test
Browse files Browse the repository at this point in the history
  • Loading branch information
ry committed Sep 18, 2011
1 parent 8cfc680 commit 66d2fd2
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 22 deletions.
63 changes: 57 additions & 6 deletions lib/domain.js
Expand Up @@ -23,9 +23,8 @@ var assert = require('assert');
var EventEmitter = require('events').EventEmitter;
var util = require('util');

var currentDomain = null;
var defaultDomain = new Domain();
var createQueue = [];
var domainIds = 0;


var debug;
if (process.env.NODE_DEBUG && /domain/.test(process.env.NODE_DEBUG)) {
Expand All @@ -36,14 +35,34 @@ if (process.env.NODE_DEBUG && /domain/.test(process.env.NODE_DEBUG)) {


function Domain() {
this.id = ++domainIds;
this.handles = [];
this.callerDomain = null;
}
util.inherits(Domain, EventEmitter);


var defaultDomain = new Domain();
exports.defaultDomain = defaultDomain;
var currentDomain = defaultDomain;
var createQueue = [];

exports.getCurrent = function getCurrent() {
return currentDomain;
};


Domain.prototype.inspect = function() {
return "#<Domain id=" + this.id +
" handles.length=" + this.handles.length +
">";
};


Domain.prototype.enter = function() {
assert.ok(!currentDomain);
assert.ok(this != currentDomain || currentDomain == defaultDomain,
"Node should not recursively enter the same domain");
this.callerDomain = currentDomain;
currentDomain = this;
};

Expand All @@ -55,6 +74,8 @@ Domain.prototype.kill = function() {
this.handles[i].close();
} else {
this.handles[i].oncomplete = null;
this.handles[i].ontimeout = null;
this.handles[i]._onTimeout = null;
}
}
this.handles = [];
Expand All @@ -63,7 +84,8 @@ Domain.prototype.kill = function() {

Domain.prototype.exit = function() {
assert.ok(currentDomain == this);
currentDomain = null;
assert.ok(this.callerDomain == defaultDomain || this.callerDomain == null);
currentDomain = this.callerDomain;

if (this.handles.length == 0) {
this.emit('exit');
Expand All @@ -72,9 +94,15 @@ Domain.prototype.exit = function() {


exports.pollNewDomains = function() {
if (currentDomain != defaultDomain) {
return;
}

var d;
while ((d = createQueue.shift())) {
d.enter();
assert.ok(currentDomain);
assert.equal(d, currentDomain);

try {
d.cb(d.arg);
Expand All @@ -95,15 +123,38 @@ exports.add = function(handle) {
if (process.features.domains) {
debug("add handle", handle, "to domain", currentDomain);
currentDomain.handles.push(handle);
assert.ok(!handle.domain);
handle.domain = currentDomain;
}
};


exports.addDefaultDomain = function(handle) {
if (process.features.domains) {
debug("add handle", handle, "to defaultDomain");
defaultDomain.handles.push(handle);
assert.ok(!handle.domain);
handle.domain = defaultDomain;
}
};


exports.remove = function(handle) {
if (process.features.domains) {
// TODO do this in O(1)
assert.equal(currentDomain, handle.domain);

if (handle.domain) {
if (currentDomain != handle.domain) {
console.error("(node) Attempting to access a handle outside of the " +
"current domain. Thiis is not allowed. handle =", handle);
throw new Error("bad handle access");
// We should not reach here.
process.exit(-10);
}
} else {
assert.equal(currentDomain, defaultDomain);
}

var i = currentDomain.handles.indexOf(handle);
currentDomain.handles.splice(i, 1);
}
Expand Down
46 changes: 36 additions & 10 deletions lib/timers_uv.js
Expand Up @@ -65,7 +65,11 @@ function insert(item, msecs) {
list = lists[msecs];
} else {
list = new Timer();
require('domain').add(list);
// This is a special timer which is owned by Node. It must only be in
// the defaultDomain. When it makes callbacks it iterates through a link list
// of pseudo handles and invokes a callback on each. Each item in that
// list can be associated with a domain.
require('domain').addDefaultDomain(list);

list.start(msecs, 0);

Expand All @@ -74,6 +78,14 @@ function insert(item, msecs) {
lists[msecs] = list;

list.ontimeout = function() {
if (process.features.domains) {
assert(this == list);
assert(list.domain);
assert(list.domain == require('domain').defaultDomain);
assert(require('domain').getCurrent() ==
require('domain').defaultDomain);
}

debug('timeout callback ' + msecs);

var now = new Date();
Expand All @@ -91,19 +103,34 @@ function insert(item, msecs) {
assert(first !== L.peek(list));

if (first._onTimeout) {
// Enter the domain during the callback. 'first' is a pseudo
// handle here - actually a pure javascript object but we treat
// it as its own handle.
console.error("first", first)
first.domain.enter();
first._onTimeout();
first.domain.exit();
if (process.features.domains) {
// Enter the domain during the callback. 'first' is a pseudo
// handle here - actually a pure javascript object but we treat
// it as its own handle.
process.dispatch(first, "_onTimeout");
assert(this == list);
assert(list.domain);
assert(list.domain == require('domain').defaultDomain);
assert(require('domain').getCurrent() ==
require('domain').defaultDomain);
} else {
first._onTimeout();
}
}
}
}

debug(msecs + ' list empty');
assert(L.isEmpty(list));

if (process.features.domains) {
assert(list.domain);
assert(list.domain == require('domain').defaultDomain);
assert(require('domain').getCurrent() ==
require('domain').defaultDomain,
"not in defaultDomain when we expected to be");
}

closeTimer(list);
delete lists[msecs];
};
Expand All @@ -116,7 +143,7 @@ function insert(item, msecs) {

var unenroll = exports.unenroll = function(item) {
L.remove(item);
require('domains').remove(item);
require('domain').remove(item);

var list = lists[item._idleTimeout];
// if empty then stop the watcher
Expand Down Expand Up @@ -184,7 +211,6 @@ exports.setTimeout = function(callback, after) {
timer._idleNext = timer;

require('domain').add(timer);
assert(timer.domain);

if (arguments.length <= 2) {
timer._onTimeout = callback;
Expand Down
21 changes: 15 additions & 6 deletions src/node.js
Expand Up @@ -197,6 +197,11 @@
var l = nextTickQueue.length;
if (l === 0) return;

if (process.features.domains) {
var domain = NativeModule.require('domain');
assert(domain.getCurrent() == domain.defaultDomain);
}

try {
for (var i = 0; i < l; i++) {
dispatch(nextTickQueue, i);
Expand Down Expand Up @@ -536,21 +541,25 @@
function dispatch(obj, method, arg0, arg1, arg2, arg3) {
assert(arguments.length < 7);

var domain = obj.domain;
if (domain) {
domain.enter();
var domain;
if (obj.domain) {
domain = obj.domain
} else {
domain = NativeModule.require('domain').defaultDomain;
}

domain.enter();

try {
obj[method](arg0, arg1, arg2, arg3);
} catch (e) {
throw e;
domain.emit('error', e);
domain.kill();
}

if (domain) {
domain.exit();
}
debugger;
domain.exit();

NativeModule.require('domain').pollNewDomains();
}
Expand Down
80 changes: 80 additions & 0 deletions test/simple/test-domains2.js
@@ -0,0 +1,80 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.

var common = require('../common');
var assert = require('assert');
var domain = require('domain');

var timerCallbacks = 0;

setTimeout(function() {
console.error("timer 1");
timerCallbacks++;

var d1 = domain.create(null, function() {
console.error("d1 created");

setTimeout(function() {
console.error("timer 2");
timerCallbacks++;

setTimeout(function() {
console.error("timer 3");
timerCallbacks++;
}, 1);
}, 3);

setTimeout(function() {
timerCallbacks++;
}, 1);
});

}, 1);

setTimeout(function() {
timerCallbacks++;
console.error("timer 4");

var d2 = domain.create(null, function() {
console.error("d2 created");

var t1 = setTimeout(function() {
assert.ok(false, "should not get here");
}, 4);
assert.ok(t1.domain);
assert.equal(t1.domain, d2);
assert.equal(t1.domain.id, require('domain').getCurrent().id);

var t2 = setTimeout(function() {
assert.ok(false, "should not get here");
}, 3);
assert.equal(t2.domain, d2);

debugger;

this.kill();
});
}, 2);


process.on('exit', function() {
assert.equal(5, timerCallbacks);
});

0 comments on commit 66d2fd2

Please sign in to comment.