@ -20,34 +20,13 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var util = require ( 'util' ) ;
var util = require ( 'util' ) ;
var events = require ( 'events' ) ;
var EventEmitter = require ( 'events' ) ;
var EventEmitter = events . EventEmitter ;
var inherits = util . inherits ;
var inherits = util . inherits ;
// communicate with events module, but don't require that
// communicate with events module, but don't require that
// module to have to load this one, since this module has
// module to have to load this one, since this module has
// a few side effects.
// a few side effects.
events . usingDomains = true ;
EventEmitter . usingDomains = true ;
// overwrite process.domain with a getter/setter that will allow for more
// effective optimizations
var _ domain = [ null ] ;
Object . defineProperty ( process , 'domain' , {
enumerable : true ,
get : function ( ) {
return _ domain [ 0 ] ;
} ,
set : function ( arg ) {
return _ domain [ 0 ] = arg ;
}
} ) ;
// objects with external array data are excellent ways to communicate state
// between js and c++ w/o much overhead
var _ domain_flag = { } ;
// let the process know we're using domains
process . _ setupDomainUse ( _ domain , _ domain_flag ) ;
exports . Domain = Domain ;
exports . Domain = Domain ;
@ -63,65 +42,75 @@ exports._stack = stack;
exports . active = null ;
exports . active = null ;
function noop ( ) { }
var listenerObj = {
error : function errorHandler ( domain , er ) {
var caught = false ;
// 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 ) ;
if ( stack . length === 0 )
process . removeAsyncListener ( domain . _ listener ) ;
// Exit all domains on the stack. Uncaught exceptions end the
// current tick and no domains should be left on the stack
// between ticks.
stack . length = 0 ;
exports . 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 === exports . active ) {
stack . pop ( ) ;
}
if ( stack . length ) {
exports . active = process . domain = stack [ stack . length - 1 ] ;
caught = process . _ fatalException ( er2 ) ;
} else {
caught = false ;
}
return caught ;
}
return caught ;
}
} ;
inherits ( Domain , EventEmitter ) ;
inherits ( Domain , EventEmitter ) ;
function Domain ( ) {
function Domain ( ) {
EventEmitter . call ( this ) ;
EventEmitter . call ( this ) ;
this . members = [ ] ;
this . members = [ ] ;
this . _ listener = process . createAsyncListener ( noop , listenerObj , this ) ;
}
}
Domain . prototype . members = undefined ;
Domain . prototype . members = undefined ;
Domain . prototype . _ disposed = undefined ;
Domain . prototype . _ disposed = undefined ;
Domain . prototype . _ listener = undefined ;
// Called by process._fatalException in case an error was thrown.
Domain . prototype . _ errorHandler = function errorHandler ( er ) {
var caught = false ;
// 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 ( this . _ disposed )
return true ;
er . domain = this ;
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 = this . 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.
stack . length = 0 ;
exports . 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 ( this === exports . active ) {
stack . pop ( ) ;
}
if ( stack . length ) {
exports . active = process . domain = stack [ stack . length - 1 ] ;
caught = process . _ fatalException ( er2 ) ;
} else {
caught = false ;
}
return caught ;
}
return caught ;
} ;
Domain . prototype . enter = function ( ) {
Domain . prototype . enter = function ( ) {
if ( this . _ disposed ) return ;
if ( this . _ disposed ) return ;
@ -130,35 +119,37 @@ Domain.prototype.enter = function() {
// to push it onto the stack so that we can pop it later.
// to push it onto the stack so that we can pop it later.
exports . active = process . domain = this ;
exports . active = process . domain = this ;
stack . push ( this ) ;
stack . push ( this ) ;
_ domain_flag [ 0 ] = stack . length ;
process . addAsyncListener ( this . _ listener ) ;
} ;
} ;
Domain . prototype . exit = function ( ) {
Domain . prototype . exit = function ( ) {
if ( this . _ disposed ) return ;
if ( this . _ disposed ) return ;
process . removeAsyncListener ( this . _ listener ) ;
// exit all domains until this one.
// exit all domains until this one.
var d ;
var in dex = stack . lastIndexOf ( this ) ;
do {
if ( index !== - 1 )
d = stack . pop ( ) ;
stack . splice ( index + 1 ) ;
} while ( d && d !== this ) ;
else
_ domain_flag [ 0 ] = stack . length ;
stack . length = 0 ;
exports . active = stack [ stack . length - 1 ] ;
exports . active = stack [ stack . length - 1 ] ;
process . domain = exports . active ;
process . domain = exports . active ;
} ;
} ;
// note: this works for timers as well.
// note: this works for timers as well.
Domain . prototype . add = function ( ee ) {
Domain . prototype . add = function ( ee ) {
// disposed domains can't be used for new things.
// If the domain is disposed or already added, then nothing left to do.
if ( this . _ disposed ) return ;
if ( this . _ disposed || ee . domain === this )
return ;
// already added to this domain.
if ( ee . domain === this ) return ;
// has a domain already - remove it first.
// has a domain already - remove it first.
if ( ee . domain ) {
if ( ee . domain )
ee . domain . remove ( ee ) ;
ee . domain . remove ( ee ) ;
}
// check for circular Domain->Domain links.
// check for circular Domain->Domain links.
// This causes bad insanity!
// This causes bad insanity!
@ -177,85 +168,128 @@ Domain.prototype.add = function(ee) {
ee . domain = this ;
ee . domain = this ;
this . members . push ( ee ) ;
this . members . push ( ee ) ;
// Adding the domain._listener to the Wrap associated with the event
// emitter instance will be done automatically either on class
// instantiation or manually, like in cases of net listen().
// The reason it cannot be done here is because in specific cases the
// _handle is not created on EE instantiation, so there's no place to
// add the listener.
} ;
} ;
Domain . prototype . remove = function ( ee ) {
Domain . prototype . remove = function ( ee ) {
ee . domain = null ;
ee . domain = null ;
var index = this . members . indexOf ( ee ) ;
var index = this . members . indexOf ( ee ) ;
if ( index !== - 1 ) {
if ( index !== - 1 )
this . members . splice ( index , 1 ) ;
this . members . splice ( index , 1 ) ;
// First check if the ee is a handle itself.
if ( ee . removeAsyncListener )
ee . removeAsyncListener ( this . _ listener ) ;
// Manually remove the asyncListener from the handle, if possible.
if ( ee . _ handle && ee . _ handle . removeAsyncListener )
ee . _ handle . removeAsyncListener ( this . _ listener ) ;
// TODO(trevnorris): Are there cases where the handle doesn't live on
// the ee or the _handle.
// TODO(trevnorris): For debugging that we've missed adding AsyncWrap's
// methods to a handle somewhere on the native side.
if ( ee . _ handle && ! ee . _ handle . removeAsyncListener ) {
process . _ rawDebug ( 'Wrap handle is missing AsyncWrap methods' ) ;
process . abort ( ) ;
}
}
} ;
} ;
Domain . prototype . run = function ( fn ) {
Domain . prototype . run = function ( fn ) {
return this . bind ( fn ) ( ) ;
if ( this . _ disposed )
return ;
this . enter ( ) ;
var ret = fn . call ( this ) ;
this . exit ( ) ;
return ret ;
} ;
} ;
function intercepted ( _ this , self , cb , fnargs ) {
if ( self . _ disposed )
return ;
if ( fnargs [ 0 ] && fnargs [ 0 ] instanceof Error ) {
var er = fnargs [ 0 ] ;
util . _ extend ( er , {
domainBound : cb ,
domainThrown : false ,
domain : self
} ) ;
self . emit ( 'error' , er ) ;
return ;
}
var len = fnargs . length ;
var args = [ ] ;
var i , ret ;
self . enter ( ) ;
if ( fnargs . length > 1 ) {
for ( i = 1 ; i < fnargs . length ; i ++ )
args . push ( fnargs [ i ] ) ;
ret = cb . apply ( _ this , args ) ;
} else {
ret = cb . call ( _ this ) ;
}
self . exit ( ) ;
return ret ;
}
Domain . prototype . intercept = function ( cb ) {
Domain . prototype . intercept = function ( cb ) {
return this . bind ( cb , true ) ;
var self = this ;
function runIntercepted ( ) {
return intercepted ( this , self , cb , arguments ) ;
}
return runIntercepted ;
} ;
} ;
Domain . prototype . bind = function ( cb , interceptError ) {
// if cb throws, catch it here.
var self = this ;
var b = function ( ) {
// disposing turns functions into no-ops
if ( self . _ disposed ) return ;
if ( this instanceof Domain ) {
function bound ( _ this , self , cb , fnargs ) {
return cb . apply ( this , arguments ) ;
if ( self . _ disposed )
}
return ;
// only intercept first-arg errors if explicitly requested.
var len = fnargs . length ;
if ( interceptError && arguments [ 0 ] &&
var args = [ ] ;
( arguments [ 0 ] instanceof Error ) ) {
var i , ret ;
var er = arguments [ 0 ] ;
util . _ extend ( er , {
domainBound : cb ,
domainThrown : false ,
domain : self
} ) ;
self . emit ( 'error' , er ) ;
return ;
}
// remove first-arg if intercept as assumed to be the error-arg
self . enter ( ) ;
if ( interceptError ) {
if ( fnargs . length > 0 )
var len = arguments . length ;
ret = cb . apply ( _ this , fnargs ) ;
var args ;
else
switch ( len ) {
ret = cb . call ( _ this ) ;
case 0 :
self . exit ( ) ;
case 1 :
// no args that we care about.
args = [ ] ;
break ;
case 2 :
// optimization for most common case: cb(er, data)
args = [ arguments [ 1 ] ] ;
break ;
default :
// slower for less common case: cb(er, foo, bar, baz, ...)
args = new Array ( len - 1 ) ;
for ( var i = 1 ; i < len ; i ++ ) {
args [ i - 1 ] = arguments [ i ] ;
}
break ;
}
self . enter ( ) ;
var ret = cb . apply ( this , args ) ;
self . exit ( ) ;
return ret ;
}
self . enter ( ) ;
return ret ;
var ret = cb . apply ( this , arguments ) ;
}
self . exit ( ) ;
return ret ;
} ;
Domain . prototype . bind = function ( cb ) {
b . domain = this ;
var self = this ;
return b ;
function runBound ( ) {
return bound ( this , self , cb , arguments ) ;
}
runBound . domain = this ;
return runBound ;
} ;
} ;
Domain . prototype . dispose = util . deprecate ( function ( ) {
Domain . prototype . dispose = util . deprecate ( function ( ) {
if ( this . _ disposed ) return ;
if ( this . _ disposed ) return ;