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

move setImmediate from timer to uv_check #3872

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions doc/api/timers.markdown
Expand Up @@ -49,9 +49,10 @@ request the timer hold the program open. If the timer is already `ref`d calling

## setImmediate(callback, [arg], [...])

To schedule the "immediate" execution of `callback`. Returns an `immediateId`
for possible use with `clearImmediate()`. Optionally you can also pass
arguments to the callback.
To schedule the "immediate" execution of `callback` after I/O events
callbacks and before `setTimeout` and `setInterval` . Returns an
`immediateId` for possible use with `clearImmediate()`. Optionally you
can also pass arguments to the callback.

Immediates are queued in the order created, and are popped off the queue once
per loop iteration. This is different from `process.nextTick` which will
Expand Down
39 changes: 15 additions & 24 deletions lib/timers.js
Expand Up @@ -292,29 +292,21 @@ Timeout.prototype.close = function() {
};


var immediateTimer = null;
var immediateQueue = { started: false };
var immediateQueue = {};
L.init(immediateQueue);


function lazyImmediateInit() { // what's in a name?
if (immediateTimer) return;
immediateTimer = new Timer;
immediateTimer.ontimeout = processImmediate;
}


function processImmediate() {
var immediate;
var immediate = L.shift(immediateQueue);

if (L.isEmpty(immediateQueue)) {
immediateTimer.stop();
immediateQueue.started = false;
} else {
immediate = L.shift(immediateQueue);
process._needImmediateCallback = false;
}

if (immediate._onImmediate) {
if (immediate.domain) immediate.domain.enter();

immediate._onTimeout();
immediate._onImmediate();

if (immediate.domain) immediate.domain.exit();
}
Expand All @@ -326,19 +318,19 @@ exports.setImmediate = function(callback) {

L.init(immediate);

immediate._onTimeout = callback;
immediate._onImmediate = callback;

if (arguments.length > 1) {
args = Array.prototype.slice.call(arguments, 1);
immediate._onTimeout = function() {

immediate._onImmediate = function() {
callback.apply(null, args);
};
}

if (!immediateQueue.started) {
lazyImmediateInit();
immediateTimer.start(0, 1);
immediateQueue.started = true;
if (!process._needImmediateCallback) {
process._needImmediateCallback = true;
process._immediateCallback = processImmediate;
}

if (process.domain) immediate.domain = process.domain;
Expand All @@ -352,12 +344,11 @@ exports.setImmediate = function(callback) {
exports.clearImmediate = function(immediate) {
if (!immediate) return;

immediate._onTimeout = undefined;
immediate._onImmediate = undefined;

L.remove(immediate);

if (L.isEmpty(immediateQueue)) {
immediateTimer.stop();
immediateQueue.started = false;
process._needImmediateCallback = false;
}
};
62 changes: 62 additions & 0 deletions src/node.cc
Expand Up @@ -134,6 +134,11 @@ static uv_idle_t tick_spinner;
static bool need_tick_cb;
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
static bool use_npn = true;
Expand Down Expand Up @@ -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) {
#define ERRNO_CASE(e) case e: return #e;
switch (errorno) {
Expand Down Expand Up @@ -2184,6 +2210,35 @@ static Handle<Value> DebugProcess(const Arguments& args);
static Handle<Value> DebugPause(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);
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a getter/setter instead of process._needImmediateCallback()? (Like process._needTickCallback())

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because setImmediate() needs to be canceled by clearImmediate().
I prefer process._needImmediateCallback = false rather than process._needImmediateCallback(false) so I used getter/setter.


Handle<Object> SetupProcessObject(int argc, char *argv[]) {
HandleScope scope;

Expand Down Expand Up @@ -2277,6 +2332,9 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {

process->Set(String::NewSymbol("pid"), Integer::New(getpid(), node_isolate));
process->Set(String::NewSymbol("features"), GetFeatures());
process->SetAccessor(String::New("_needImmediateCallback"),
NeedImmediateCallbackGetter,
NeedImmediateCallbackSetter);

// -e, --eval
if (eval_string) {
Expand Down Expand Up @@ -2859,6 +2917,10 @@ char** Init(int argc, char *argv[]) {

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);

// Fetch a reference to the main isolate, so we have a reference to it
Expand Down