diff --git a/build.xml b/build.xml
index ccdc3b5..d3629cb 100644
--- a/build.xml
+++ b/build.xml
@@ -285,6 +285,7 @@
+
@@ -361,6 +362,7 @@
+
diff --git a/patches/test/simple/test-domain.js.patch b/patches/test/simple/test-domain.js.patch
new file mode 100644
index 0000000..bef12e9
--- /dev/null
+++ b/patches/test/simple/test-domain.js.patch
@@ -0,0 +1,29 @@
+--- ../node/test/simple/test-domain.js 2013-08-22 13:48:54.000000000 +0200
++++ test/simple/test-domain.js 2013-12-04 14:07:46.000000000 +0100
+@@ -70,7 +70,7 @@
+ assert.equal(er.domainThrown, true);
+ break;
+
+- case "ENOENT, open 'this file does not exist'":
++ case "ENOENT, no such file or directory 'this file does not exist'":
+ assert.equal(er.domain, d);
+ assert.equal(er.domainThrown, false);
+ assert.equal(typeof er.domainBound, 'function');
+@@ -80,7 +80,7 @@
+ assert.equal(typeof er.errno, 'number');
+ break;
+
+- case "ENOENT, open 'stream for nonexistent file'":
++ case "ENOENT, no such file or directory 'stream for nonexistent file'":
+ assert.equal(typeof er.errno, 'number');
+ assert.equal(er.code, 'ENOENT');
+ assert.equal(er_path, 'stream for nonexistent file');
+@@ -104,7 +104,7 @@
+ assert.ok(!er.domainBound);
+ break;
+
+- case 'Cannot call method \'isDirectory\' of undefined':
++ case 'Cannot read property "isDirectory" from undefined':
+ assert.equal(er.domain, d);
+ assert.ok(!er.domainEmitter);
+ assert.ok(!er.domainBound);
diff --git a/project.properties b/project.properties
index 53bf9be..de05644 100644
--- a/project.properties
+++ b/project.properties
@@ -142,6 +142,17 @@ source.test.simple.list = \
test-dgram-send-bad-arguments.js \
test-dgram-udp4.js \
test-dgram-unref.js \
+ test-domain-crypto.js \
+ test-domain-exit-dispose.js \
+ test-domain-from-timer.js \
+ test-domain-http-server.js \
+ test-domain-implicit-fs.js \
+ test-domain-multi.js \
+ test-domain-nested-throw.js \
+ test-domain-nested.js \
+ test-domain-stack.js \
+ test-domain-timers.js \
+ test-domain.js \
test-error-reporting.js \
test-event-emitter-add-listeners.js \
test-event-emitter-check-listener-leaks.js \
diff --git a/src/main/java/net/java/avatar/js/eventloop/Event.java b/src/main/java/net/java/avatar/js/eventloop/Event.java
index ce18f58..8595601 100644
--- a/src/main/java/net/java/avatar/js/eventloop/Event.java
+++ b/src/main/java/net/java/avatar/js/eventloop/Event.java
@@ -27,8 +27,8 @@ package net.java.avatar.js.eventloop;
import java.security.AccessControlContext;
import java.security.AccessController;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
-import net.java.avatar.js.eventloop.Callback;
import net.java.avatar.js.Server;
public final class Event {
@@ -37,12 +37,15 @@ public final class Event {
private final Callback callback;
private final Object[] args;
private final AccessControlContext ctx;
- public Event(final String name, final Callback callback) {
- this(name, callback, (Object[]) null);
+ private final ScriptObjectMirror domain;
+
+ public Event(final String name, final ScriptObjectMirror domain, final Callback callback) {
+ this(name, domain, callback, (Object[]) null);
}
- public Event(final String name, final Callback callback, final Object arg) {
+ public Event(final String name, final ScriptObjectMirror domain, final Callback callback, final Object arg) {
this.name = name;
+ this.domain = domain;
this.callback = callback;
this.args = new Object[1];
this.args[0] = arg;
@@ -55,6 +58,7 @@ public final class Event {
public Event(final String name, final Callback callback, final Object... args) {
this.name = name;
+ this.domain = null;
this.callback = callback;
this.args = args == null ? null : args.clone();
if(System.getSecurityManager() != null) {
@@ -107,4 +111,7 @@ public final class Event {
return sb.toString();
}
+ public ScriptObjectMirror getDomain() {
+ return domain;
+ }
}
diff --git a/src/main/java/net/java/avatar/js/eventloop/EventLoop.java b/src/main/java/net/java/avatar/js/eventloop/EventLoop.java
index e7f0135..8bb1f58 100644
--- a/src/main/java/net/java/avatar/js/eventloop/EventLoop.java
+++ b/src/main/java/net/java/avatar/js/eventloop/EventLoop.java
@@ -41,12 +41,16 @@ import javax.script.ScriptException;
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
import net.java.avatar.js.dns.DNS;
import net.java.avatar.js.log.Logger;
import net.java.avatar.js.log.Logging;
import net.java.libuv.LibUV;
import net.java.libuv.cb.AsyncCallback;
import net.java.libuv.cb.CallbackExceptionHandler;
+import net.java.libuv.cb.CallbackDomainProvider;
+import net.java.libuv.cb.CallbackHandler;
+import net.java.libuv.cb.CallbackHandlerFactory;
import net.java.libuv.handles.AsyncHandle;
import net.java.libuv.handles.LoopHandle;
@@ -69,6 +73,8 @@ public final class EventLoop {
private Callback uncaughtExceptionHandler = null;
private Exception pendingException = null;
+ private ScriptObjectMirror domain;
+
public static final class Handle implements AutoCloseable {
private final AtomicInteger hooks;
@@ -106,9 +112,14 @@ public final class EventLoop {
uncaughtExceptionHandler = handler;
}
- public void nextTick(final Event event) {
+ public void nextTick(final Callback cb) {
assert Thread.currentThread() == mainThread : "called from non-event thread " + Thread.currentThread().getName();
- eventQueue.add(event);
+ eventQueue.add(new Event("nextTick", cb));
+ }
+
+ public void nextTickWithDomain(final Callback cb, ScriptObjectMirror evtDomain) {
+ assert Thread.currentThread() == mainThread : "called from non-event thread " + Thread.currentThread().getName();
+ eventQueue.add(new Event("nextTickWithDomain", evtDomain, cb));
}
public void post(final Callback cb, Object... args) {
@@ -141,7 +152,17 @@ public final class EventLoop {
for (Event event = eventQueue.poll();
event != null;
event = eventQueue.poll()) {
- processEvent(event);
+ ScriptObjectMirror evtDomain = event.getDomain();
+ if (evtDomain != null) {
+ if (isDisposed(evtDomain)) {
+ continue;
+ }
+ enterDomain(evtDomain);
+ processEvent(event);
+ exitDomain(evtDomain);
+ } else {
+ processEvent(event);
+ }
}
}
}
@@ -198,19 +219,25 @@ public final class EventLoop {
private static final String UNCAUGHT_EXCEPTION_NAME = "uncaughtException";
public boolean handleCallbackException(final Exception ex) {
-
+ boolean handled = true;
// callback to check if an uncaught exception handler has been registered by the user
final Object[] registeredArgs = {null};
if (isHandlerRegistered != null) {
try {
isHandlerRegistered.call(UNCAUGHT_EXCEPTION_NAME, registeredArgs);
} catch (final Exception e) {
- return false;
+ handled = false;
}
}
if (registeredArgs[0] == null || uncaughtExceptionHandler == null) {
// no handler registered - rethrow uncaught exceptions
+ handled = false;
+ }
+
+ if (!handled && domain == null) {
+ // No domain and no uncaughtException Handler registered
+ // rethrowing
return false;
}
@@ -333,6 +360,8 @@ public final class EventLoop {
this.uvVersion = uvVersion;
this.logging = logging;
this.dns = new DNS(this);
+
+ final LoopCallbackHandler defaultHandler = new LoopCallbackHandler(this);
this.uvLoop = new LoopHandle(new CallbackExceptionHandler() {
@Override
public void handle(final Exception ex) {
@@ -345,8 +374,23 @@ public final class EventLoop {
stop();
}
}
- }, new LoopCallbackHandler(this));
-
+ },
+ new CallbackHandlerFactory() {
+ @Override
+ public CallbackHandler newCallbackHandlerWithDomain(Object domain) {
+ return new LoopCallbackHandler(EventLoop.this, domain);
+ }
+ @Override
+ public CallbackHandler newCallbackHandler() {
+ return defaultHandler;
+ }
+ },
+ new CallbackDomainProvider() {
+ @Override
+ public Object getDomain() {
+ return EventLoop.this.getDomain();
+ }
+ });
this.instanceNumber = instanceNumber;
this.executor = executor;
@@ -399,4 +443,47 @@ public final class EventLoop {
return uvLoop;
}
+ public void setDomain(ScriptObjectMirror obj) {
+ assert Thread.currentThread() == mainThread : "called from non-event thread " + Thread.currentThread().getName();
+ domain = obj;
+ }
+
+ public ScriptObjectMirror getDomain() {
+ assert Thread.currentThread() == mainThread : "called from non-event thread " + Thread.currentThread().getName();
+ return domain;
+ }
+
+ public boolean isDisposed(ScriptObjectMirror domain) {
+ assert Thread.currentThread() == mainThread : "called from non-event thread " + Thread.currentThread().getName();
+ return Boolean.TRUE.equals(domain.getMember("_disposed"));
+ }
+
+ public void enterDomain(ScriptObjectMirror domain) {
+ assert Thread.currentThread() == mainThread : "called from non-event thread " + Thread.currentThread().getName();
+ domain.callMember("enter");
+ }
+
+ public void exitDomain(ScriptObjectMirror domain) {
+ assert Thread.currentThread() == mainThread : "called from non-event thread " + Thread.currentThread().getName();
+ domain.callMember("exit");
+ }
+
+ public boolean isDisposed(Object domain) {
+ if (domain instanceof ScriptObjectMirror) {
+ isDisposed((ScriptObjectMirror) domain);
+ }
+ return false;
+ }
+
+ public void enterDomain(Object domain) {
+ if (domain instanceof ScriptObjectMirror) {
+ enterDomain((ScriptObjectMirror) domain);
+ }
+ }
+
+ public void exitDomain(Object domain) {
+ if (domain instanceof ScriptObjectMirror) {
+ exitDomain((ScriptObjectMirror) domain);
+ }
+ }
}
diff --git a/src/main/java/net/java/avatar/js/eventloop/LoopCallbackHandler.java b/src/main/java/net/java/avatar/js/eventloop/LoopCallbackHandler.java
index 73fad47..035aa7c 100644
--- a/src/main/java/net/java/avatar/js/eventloop/LoopCallbackHandler.java
+++ b/src/main/java/net/java/avatar/js/eventloop/LoopCallbackHandler.java
@@ -63,16 +63,42 @@ import net.java.libuv.cb.UDPSendCallback;
final class LoopCallbackHandler implements CallbackHandler {
private final EventLoop eventLoop;
-
+ private final Object domain;
public LoopCallbackHandler(EventLoop eventLoop) {
+ this(eventLoop, null);
+ }
+
+ public LoopCallbackHandler(EventLoop eventLoop, Object domain) {
this.eventLoop = eventLoop;
+ this.domain = domain;
}
+ private boolean shouldCall() {
+ if (domain != null) {
+ if (eventLoop.isDisposed(domain)) {
+ return false;
+ }
+
+ eventLoop.enterDomain(domain);
+ }
+
+ return true;
+ }
+
+ private void post() throws Exception {
+ if (domain != null) {
+ eventLoop.exitDomain(domain);
+ }
+ eventLoop.processQueuedEvents();
+ }
+
@Override
public void handleAsyncCallback(final AsyncCallback cb, final int status) {
try {
- cb.onSend(status);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onSend(status);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -81,8 +107,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleCheckCallback(final CheckCallback cb, final int status) {
try {
- cb.onCheck(status);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onCheck(status);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -91,8 +119,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleSignalCallback(final SignalCallback cb, final int signum) {
try {
- cb.onSignal(signum);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onSignal(signum);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -101,8 +131,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleStreamReadCallback(final StreamReadCallback cb, final ByteBuffer data) {
try {
- cb.onRead(data);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onRead(data);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -111,8 +143,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleStreamRead2Callback(final StreamRead2Callback cb, final ByteBuffer data, final long handle, final int type) {
try {
- cb.onRead2(data, handle, type);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onRead2(data, handle, type);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -121,8 +155,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleStreamWriteCallback(final StreamWriteCallback cb, final int status, final Exception error) {
try {
- cb.onWrite(status, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onWrite(status, error);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -131,8 +167,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleStreamConnectCallback(final StreamConnectCallback cb, final int status, final Exception error) {
try {
- cb.onConnect(status, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onConnect(status, error);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -141,8 +179,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleStreamConnectionCallback(final StreamConnectionCallback cb, final int status, final Exception error) {
try {
- cb.onConnection(status, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onConnection(status, error);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -151,8 +191,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleStreamCloseCallback(final StreamCloseCallback cb) {
try {
- cb.onClose();
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onClose();
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -161,8 +203,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleStreamShutdownCallback(final StreamShutdownCallback cb, final int status, final Exception error) {
try {
- cb.onShutdown(status, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onShutdown(status, error);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -171,8 +215,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileCallback(final FileCallback cb, final Object context, final Exception error) {
try {
- cb.onDone(context, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onDone(context, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -182,8 +228,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileCloseCallback(final FileCloseCallback cb, final Object context, final int fd, final Exception error) {
try {
- cb.onClose(context, fd, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onClose(context, fd, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -192,8 +240,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileOpenCallback(final FileOpenCallback cb, final Object context, final int fd, final Exception error) {
try {
- cb.onOpen(context, fd, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onOpen(context, fd, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -202,8 +252,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileReadCallback(final FileReadCallback cb, final Object context, final int bytesRead, final ByteBuffer data, final Exception error) {
try {
- cb.onRead(context, bytesRead, data, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onRead(context, bytesRead, data, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -212,8 +264,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileReadDirCallback(final FileReadDirCallback cb, final Object context, final String[] names, final Exception error) {
try {
- cb.onReadDir(context, names, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onReadDir(context, names, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -222,8 +276,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileReadLinkCallback(final FileReadLinkCallback cb, final Object context, final String name, final Exception error) {
try {
- cb.onReadLink(context, name, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onReadLink(context, name, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -232,8 +288,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileStatsCallback(final FileStatsCallback cb, final Object context, final Stats stats, final Exception error) {
try {
- cb.onStats(context, stats, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onStats(context, stats, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -242,8 +300,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileUTimeCallback(final FileUTimeCallback cb, final Object context, final long time, final Exception error) {
try {
- cb.onUTime(context, time, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onUTime(context, time, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -252,8 +312,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileWriteCallback(final FileWriteCallback cb, final Object context, final int bytesWritten, final Exception error) {
try {
- cb.onWrite(context, bytesWritten, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onWrite(context, bytesWritten, error);
+ post();
+ }
} catch (final Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -262,8 +324,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFileEventCallback(FileEventCallback cb, int status, String event, String filename) {
try {
- cb.onEvent(status, event, filename);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onEvent(status, event, filename);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -273,7 +337,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFilePollCallback(FilePollCallback cb, int status, Stats previous, Stats current) {
try {
- cb.onPoll(status, previous, current);
+ if (shouldCall()) {
+ cb.onPoll(status, previous, current);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -282,7 +349,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleFilePollStopCallback(FilePollStopCallback cb) {
try {
- cb.onStop();
+ if (shouldCall()) {
+ cb.onStop();
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -291,7 +361,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleProcessCloseCallback(ProcessCloseCallback cb) {
try {
- cb.onClose();
+ if (shouldCall()) {
+ cb.onClose();
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -300,7 +373,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleProcessExitCallback(ProcessExitCallback cb, int status, int signal, Exception error) {
try {
- cb.onExit(status, signal, error);
+ if (shouldCall()) {
+ cb.onExit(status, signal, error);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -309,8 +385,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleTimerCallback(final TimerCallback cb, final int status) {
try {
- cb.onTimer(status);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onTimer(status);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -319,8 +397,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleUDPRecvCallback(final UDPRecvCallback cb, final int nread, final ByteBuffer data, final Address address) {
try {
- cb.onRecv(nread, data, address);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onRecv(nread, data, address);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -329,8 +409,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleUDPSendCallback(final UDPSendCallback cb, final int status, final Exception error) {
try {
- cb.onSend(status, error);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onSend(status, error);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -339,8 +421,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleUDPCloseCallback(final UDPCloseCallback cb) {
try {
- cb.onClose();
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onClose();
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
@@ -349,8 +433,10 @@ final class LoopCallbackHandler implements CallbackHandler {
@Override
public void handleIdleCallback(IdleCallback cb, int status) {
try {
- cb.onIdle(status);
- eventLoop.processQueuedEvents();
+ if (shouldCall()) {
+ cb.onIdle(status);
+ post();
+ }
} catch (Exception ex) {
eventLoop.loop().getExceptionHandler().handle(ex);
}
diff --git a/src/main/js/lib/process.js b/src/main/js/lib/process.js
index fcb95ec..0f3c3c8 100644
--- a/src/main/js/lib/process.js
+++ b/src/main/js/lib/process.js
@@ -61,7 +61,6 @@ var eventloop = __avatar.eventloop;
var LibUV = Packages.net.java.libuv.LibUV;
var Process = Packages.net.java.avatar.js.os.Process;
var Server = Packages.net.java.avatar.js.Server;
-var Event = Packages.net.java.avatar.js.eventloop.Event
var Constants = Packages.net.java.avatar.js.constants.Constants;
var Signals = Packages.net.java.libuv.handles.SignalHandle;
@@ -430,16 +429,14 @@ Object.defineProperty(exports, 'hrtime', {
Object.defineProperty(exports, 'nextTick', {
enumerable: true,
+ configurable: true,
value: function(callback) {
if (this._exiting) {
return;
}
- eventloop.nextTick(
- new Event('nextTick', function(name, args) {
- callback();
- }
- )
- );
+ eventloop.nextTick(function(name, args) {
+ callback();
+ });
}
});
@@ -588,8 +585,36 @@ exports.openStdin = function() {
}
exports._usingDomains = function() {
+ // redefine nextTick at this time to speedup
+ // domain event posting
+ Object.defineProperty(exports, 'nextTick', {
+ enumerable: true,
+ value: function(callback) {
+ if (this._exiting) {
+ return;
+ }
+ eventloop.nextTickWithDomain(function(name, args) {
+ callback();
+ }, process.domain)
+ }
+ });
}
+var ScriptUtils = Packages.jdk.nashorn.api.scripting.ScriptUtils
+Object.defineProperty(exports, 'domain', {
+ enumerable : true,
+ set : function(domain) {
+ if (domain) {
+ eventloop.domain = domain;
+ } else {
+ eventloop.domain = null;
+ }
+ },
+ get : function() {
+ return ScriptUtils.unwrap(eventloop.domain);
+ }
+});
+
var Check = Packages.net.java.libuv.handles.CheckHandle;
var Idle = Packages.net.java.libuv.handles.IdleHandle;
var checkHandle = new Check(eventloop.loop());
diff --git a/src/main/js/net/java/avatar/js/init.js b/src/main/js/net/java/avatar/js/init.js
index 8e312a6..9a1e875 100644
--- a/src/main/js/net/java/avatar/js/init.js
+++ b/src/main/js/net/java/avatar/js/init.js
@@ -200,6 +200,67 @@ var gc = global.gc;
console.log(this.stack);
};
+ var fatalProcessing = function(er) {
+ var caught = false;
+ if (process.domain) { // From nodejs
+ var domain = process.domain;
+ var domainModule = NativeModule.require('domain');
+ var domainStack = domainModule._stack;
+
+ // ignore errors on disposed domains.
+ //
+ // XXX This is a bit stupid. We should probably get rid of
+ // domain.dispose() altogether. It's almost always a terrible
+ // idea. --isaacs
+ if (domain._disposed)
+ return true;
+
+ er.domain = domain;
+ er.domainThrown = true;
+ // wrap this in a try/catch so we don't get infinite throwing
+ try {
+ // One of three things will happen here.
+ //
+ // 1. There is a handler, caught = true
+ // 2. There is no handler, caught = false
+ // 3. It throws, caught = false
+ //
+ // If caught is false after this, then there's no need to exit()
+ // the domain, because we're going to crash the process anyway.
+ caught = domain.emit('error', er);
+ // Exit all domains on the stack. Uncaught exceptions end the
+ // current tick and no domains should be left on the stack
+ // between ticks.
+ var domainModule = NativeModule.require('domain');
+ domainStack.length = 0;
+ domainModule.active = process.domain = null;
+ } catch (er2) {
+ // The domain error handler threw! oh no!
+ // See if another domain can catch THIS error,
+ // or else crash on the original one.
+ // If the user already exited it, then don't double-exit.
+ if (domain === domainModule.active)
+ domainStack.pop();
+ if (domainStack.length) {
+ var parentDomain = domainStack[domainStack.length - 1];
+ process.domain = domainModule.active = parentDomain;
+ caught = fatalProcessing(er2);
+ } else
+ caught = false;
+ }
+ } else {
+ caught = process.emit('uncaughtException', er);
+ }
+
+ // Avatar-js specific handling,
+ // exit is handled in the class that is catching the rethrown er
+ if (!caught) {
+ throw er;
+ }
+
+ return caught;
+ };
+
__avatar.eventloop.setUncaughtExceptionHandler(
function(name, args) {
var listeners = process.listeners('uncaughtException');
@@ -208,13 +269,12 @@ var gc = global.gc;
}
},
function(name, args) {
- var ctx = Packages.net.java.avatar.js.eventloop.EventLoop;
var e = new Error();
var ex = args[0];
for (var k in ex) {
e[k] = ex[k];
}
- process.emit(name, e);
+ fatalProcessing(e);
}
);
diff --git a/src/main/js/net/java/avatar/js/timer_wrap.js b/src/main/js/net/java/avatar/js/timer_wrap.js
index afc085b..5e809ab 100644
--- a/src/main/js/net/java/avatar/js/timer_wrap.js
+++ b/src/main/js/net/java/avatar/js/timer_wrap.js
@@ -32,7 +32,14 @@
var that = this;
this._timer.setTimerFiredCallback(function(status) {
if (that.ontimeout) {
+ // When a timer is unref, the domain is set on the wrap.
+ if (that.domain) {
+ that.domain.enter();
+ }
that.ontimeout();
+ if (that.domain) {
+ that.domain.exit();
+ }
}
});
}