timer: move setImmediate from timer to uv_check
uv_check is the robust place to invoke setImmediate callbacks after process.nextTick and before timers(setTimeout/setInterval)
This commit is contained in:
parent
7bdd05bd66
commit
cd372510bb
@ -292,29 +292,21 @@ Timeout.prototype.close = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var immediateTimer = null;
|
var immediateQueue = {};
|
||||||
var immediateQueue = { started: false };
|
|
||||||
L.init(immediateQueue);
|
L.init(immediateQueue);
|
||||||
|
|
||||||
|
|
||||||
function lazyImmediateInit() { // what's in a name?
|
|
||||||
if (immediateTimer) return;
|
|
||||||
immediateTimer = new Timer;
|
|
||||||
immediateTimer.ontimeout = processImmediate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function processImmediate() {
|
function processImmediate() {
|
||||||
var immediate;
|
var immediate = L.shift(immediateQueue);
|
||||||
if (L.isEmpty(immediateQueue)) {
|
|
||||||
immediateTimer.stop();
|
|
||||||
immediateQueue.started = false;
|
|
||||||
} else {
|
|
||||||
immediate = L.shift(immediateQueue);
|
|
||||||
|
|
||||||
|
if (L.isEmpty(immediateQueue)) {
|
||||||
|
process._needImmediateCallback = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (immediate._onImmediate) {
|
||||||
if (immediate.domain) immediate.domain.enter();
|
if (immediate.domain) immediate.domain.enter();
|
||||||
|
|
||||||
immediate._onTimeout();
|
immediate._onImmediate();
|
||||||
|
|
||||||
if (immediate.domain) immediate.domain.exit();
|
if (immediate.domain) immediate.domain.exit();
|
||||||
}
|
}
|
||||||
@ -326,19 +318,19 @@ exports.setImmediate = function(callback) {
|
|||||||
|
|
||||||
L.init(immediate);
|
L.init(immediate);
|
||||||
|
|
||||||
immediate._onTimeout = callback;
|
immediate._onImmediate = callback;
|
||||||
|
|
||||||
if (arguments.length > 1) {
|
if (arguments.length > 1) {
|
||||||
args = Array.prototype.slice.call(arguments, 1);
|
args = Array.prototype.slice.call(arguments, 1);
|
||||||
immediate._onTimeout = function() {
|
|
||||||
|
immediate._onImmediate = function() {
|
||||||
callback.apply(null, args);
|
callback.apply(null, args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!immediateQueue.started) {
|
if (!process._needImmediateCallback) {
|
||||||
lazyImmediateInit();
|
process._needImmediateCallback = true;
|
||||||
immediateTimer.start(0, 1);
|
process._immediateCallback = processImmediate;
|
||||||
immediateQueue.started = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.domain) immediate.domain = process.domain;
|
if (process.domain) immediate.domain = process.domain;
|
||||||
@ -352,12 +344,11 @@ exports.setImmediate = function(callback) {
|
|||||||
exports.clearImmediate = function(immediate) {
|
exports.clearImmediate = function(immediate) {
|
||||||
if (!immediate) return;
|
if (!immediate) return;
|
||||||
|
|
||||||
immediate._onTimeout = undefined;
|
immediate._onImmediate = undefined;
|
||||||
|
|
||||||
L.remove(immediate);
|
L.remove(immediate);
|
||||||
|
|
||||||
if (L.isEmpty(immediateQueue)) {
|
if (L.isEmpty(immediateQueue)) {
|
||||||
immediateTimer.stop();
|
process._needImmediateCallback = false;
|
||||||
immediateQueue.started = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
62
src/node.cc
62
src/node.cc
@ -134,6 +134,11 @@ static uv_idle_t tick_spinner;
|
|||||||
static bool need_tick_cb;
|
static bool need_tick_cb;
|
||||||
static Persistent<String> tick_callback_sym;
|
static Persistent<String> tick_callback_sym;
|
||||||
|
|
||||||
|
static uv_check_t check_immediate_watcher;
|
||||||
|
static uv_idle_t idle_immediate_dummy;
|
||||||
|
static bool need_immediate_cb;
|
||||||
|
static Persistent<String> immediate_callback_sym;
|
||||||
|
|
||||||
|
|
||||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
static bool use_npn = true;
|
static bool use_npn = true;
|
||||||
@ -211,6 +216,27 @@ static Handle<Value> NeedTickCallback(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void CheckImmediate(uv_check_t* handle, int status) {
|
||||||
|
assert(handle == &check_immediate_watcher);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
if (immediate_callback_sym.IsEmpty()) {
|
||||||
|
immediate_callback_sym = NODE_PSYMBOL("_immediateCallback");
|
||||||
|
}
|
||||||
|
|
||||||
|
MakeCallback(process, immediate_callback_sym, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void IdleImmediateDummy(uv_idle_t* handle, int status) {
|
||||||
|
// Do nothing. Only for maintaining event loop
|
||||||
|
assert(handle == &idle_immediate_dummy);
|
||||||
|
assert(status == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline const char *errno_string(int errorno) {
|
static inline const char *errno_string(int errorno) {
|
||||||
#define ERRNO_CASE(e) case e: return #e;
|
#define ERRNO_CASE(e) case e: return #e;
|
||||||
switch (errorno) {
|
switch (errorno) {
|
||||||
@ -2176,6 +2202,35 @@ static Handle<Value> DebugProcess(const Arguments& args);
|
|||||||
static Handle<Value> DebugPause(const Arguments& args);
|
static Handle<Value> DebugPause(const Arguments& args);
|
||||||
static Handle<Value> DebugEnd(const Arguments& args);
|
static Handle<Value> DebugEnd(const Arguments& args);
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Value> NeedImmediateCallbackGetter(Local<String> property,
|
||||||
|
const AccessorInfo& info) {
|
||||||
|
return Boolean::New(need_immediate_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void NeedImmediateCallbackSetter(Local<String> property,
|
||||||
|
Local<Value> value,
|
||||||
|
const AccessorInfo& info) {
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
bool bool_value = value->BooleanValue();
|
||||||
|
|
||||||
|
if (need_immediate_cb == bool_value) return;
|
||||||
|
|
||||||
|
need_immediate_cb = bool_value;
|
||||||
|
|
||||||
|
if (need_immediate_cb) {
|
||||||
|
uv_check_start(&check_immediate_watcher, node::CheckImmediate);
|
||||||
|
// idle handle is needed only to maintain event loop
|
||||||
|
uv_idle_start(&idle_immediate_dummy, node::IdleImmediateDummy);
|
||||||
|
} else {
|
||||||
|
uv_check_stop(&check_immediate_watcher);
|
||||||
|
uv_idle_stop(&idle_immediate_dummy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Handle<Object> SetupProcessObject(int argc, char *argv[]) {
|
Handle<Object> SetupProcessObject(int argc, char *argv[]) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
@ -2269,6 +2324,9 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
|
|||||||
|
|
||||||
process->Set(String::NewSymbol("pid"), Integer::New(getpid(), node_isolate));
|
process->Set(String::NewSymbol("pid"), Integer::New(getpid(), node_isolate));
|
||||||
process->Set(String::NewSymbol("features"), GetFeatures());
|
process->Set(String::NewSymbol("features"), GetFeatures());
|
||||||
|
process->SetAccessor(String::New("_needImmediateCallback"),
|
||||||
|
NeedImmediateCallbackGetter,
|
||||||
|
NeedImmediateCallbackSetter);
|
||||||
|
|
||||||
// -e, --eval
|
// -e, --eval
|
||||||
if (eval_string) {
|
if (eval_string) {
|
||||||
@ -2851,6 +2909,10 @@ char** Init(int argc, char *argv[]) {
|
|||||||
|
|
||||||
uv_idle_init(uv_default_loop(), &tick_spinner);
|
uv_idle_init(uv_default_loop(), &tick_spinner);
|
||||||
|
|
||||||
|
uv_check_init(uv_default_loop(), &check_immediate_watcher);
|
||||||
|
uv_unref((uv_handle_t*) &check_immediate_watcher);
|
||||||
|
uv_idle_init(uv_default_loop(), &idle_immediate_dummy);
|
||||||
|
|
||||||
V8::SetFatalErrorHandler(node::OnFatalError);
|
V8::SetFatalErrorHandler(node::OnFatalError);
|
||||||
|
|
||||||
// Fetch a reference to the main isolate, so we have a reference to it
|
// Fetch a reference to the main isolate, so we have a reference to it
|
||||||
|
Loading…
x
Reference in New Issue
Block a user