Uh oh!
There was an error while loading. Please reload this page.
handle_wrap: expose {un}refed check to JS - #5834
Conversation
There was a problem hiding this comment.
idk if it's better to have this be isUnrefed?
There was a problem hiding this comment.
It probably should be isUnrefed(), but isRefed() seems a lot simpler to think about.
There was a problem hiding this comment.
I think isRefed() sounds better ("is this holding the event loop open?").
There was a problem hiding this comment.
This is not the way it's done. This has to be declared in every child class: https://github.com/nodejs/node/blob/v5.9.0/src/tcp_wrap.cc#L87
Otherwise you're setting an object property on an already constructed object.
There was a problem hiding this comment.
oh that kinda sucks, alright.
Fishrock123
commented
Mar 21, 2016
(does this needs tests..?) |
There was a problem hiding this comment.
Also: is it ok to return nothing of the handle is not alive?
There was a problem hiding this comment.
returning nothing == returning undefined. but the JS signature returns bool. The question this is trying to answer is "Can this handle hold open the event loop?" So if !IsAlive() means should return false.
There was a problem hiding this comment.
So basically this can be boiled down to:
bool refed = IsAlive(wrap) && (wrap->flags_ & kUnref) == 0;
args.GetReturnValue().Set(Boolean::New(env->isolate(), refed);thlorenz
commented
Mar 21, 2016
Yes, I think this needs tests. Ideally you'd pass tests similar to the ones in the PRs you referenced. |
mscdex
commented
Mar 21, 2016
Yes, tests are needed. |
Fishrock123
commented
Mar 21, 2016
Does anyone have advice on how I can make a more generic test for this rather than testing everywhere that we expose a handle? |
thlorenz
commented
Mar 21, 2016
@Fishrock123 I guess you could test on C++ level (do we have C++ level tests?) and just create a handle and interact with it directly. |
jasnell
commented
Mar 21, 2016
Does it have to be a method? Is it possible to have it as a read-only property? A quick test case would be worthwhile also. |
Fishrock123
commented
Mar 21, 2016
@jasnell I guess this makes it explicit that you cannot just set it, but I could possibly change it otherwise. |
jasnell
commented
Mar 21, 2016
@Fishrock123 ... that makes sense. The additional |
trevnorris
commented
Mar 21, 2016
The implementation is incomplete. As noted in #5834 (comment) the method needs to be placed on the The test is simple enough: constassert=require('assert');constnet=require('net');constserver=net.createServer(()=>{}).listen(common.PORT);server.unref();assert.equal(false,server._handle.isRefed());Remember this won't cover timer cases. To make the API parallel may need to implement a JS version that can be called on the JS timer handle instances. |
AndreasMadsen
commented
Mar 22, 2016
@Fishrock123 thanks for doing this. It would also be useful for just checking what keeps a process alive at any given time. |
502fe6d to
a55ceffCompareFishrock123
commented
Mar 22, 2016
Updated with a test, some things: I realized that some I'm not sure if it is possible to test spawn a TTY's cannot be re-refed for some reason. The method does not exist in c++, and does not work if it is added. |
Fishrock123
commented
Mar 22, 2016
Fishrock123
commented
Mar 22, 2016
Hmm, getting this on Windows vs2015 and vcbt2015: Anyone know how to fix this test for that? constassert=makeAssert('isRefed() not working on tty_wrap');constReadStream=require('tty').ReadStream;consttty=newReadStream();assert(Object.getPrototypeOf(tty._handle).hasOwnProperty('isRefed'),true);assert(tty._handle.isRefed(),true);tty.unref();assert(tty._handle.isRefed(),false); |
cjihrig
commented
Mar 22, 2016
Do you need to pass a fd to the Once the CI is happy, LGTM. |
There was a problem hiding this comment.
This depends on some non-obvious implementation details. If the timer is unref'd then the JS object will be moved to a TimerWrap that also isn't ref'd, correct?
There was a problem hiding this comment.
See
Lines 460 to 485 in d3a7534
timer.unref() assigns a ._handle for that specific timer, and is unlikely to change in the short term.
There was a problem hiding this comment.
I realize that. What I failed to say is that a note of this should be placed in timer_wrap.cc where the method is added so future generations can immediately see why this non-obvious implementation detail actually works.
There was a problem hiding this comment.
Where exactly do you mean? Isn't the same thing for the un(ref) methods on timer_wrap?
There was a problem hiding this comment.
My point is it may be non-obvious why setTimeout(()=>{}, 100)._handle === undefined but setTimeout(()=>{}, 100).unref()._handle links to a Timer instance. So using isRefed() is conditional to the state of timer. So not having a uniform way to access that data from the public object instance could be confusing.
There was a problem hiding this comment.
Sure, but the regular timers implementation will also benefit from this. e.g.
Lines 210 to 214 in cf94929
So I'm not sure what I would say in handle_wrap
a55ceff to
40c81d2CompareFishrock123
commented
Mar 22, 2016
Ci with fd 0 for TTY: https://ci.nodejs.org/job/node-test-pull-request/2030/ |
Fishrock123
commented
Mar 22, 2016
@cjihrig still the same thing on those windows builds/platforms.. |
cjihrig
commented
Mar 22, 2016
Crap. The only real use of |
Fishrock123
commented
Mar 22, 2016
maybe cc @bnoordhuis |
40c81d2 to
abd0dafCompareFishrock123
commented
Apr 7, 2016
@nodejs/lts think we can get this in the next minor LTS release? |
jasnell
commented
Apr 7, 2016
Should be possible. It's just not yet clear when that next minor LTS release will be. |
Fishrock123
commented
Apr 7, 2016
OK in hindsight this behavior regarding This needs to be accurate enough for timers to use too, and currently it isn't with either the following patches: diff --git a/lib/timers.js b/lib/timers.js
index dc2506e..3a57d86 100644
--- a/lib/timers.js+++ b/lib/timers.js@@ -133,8 +133,6 @@ function insert(item, unrefed) {
list = new TimersList(msecs, unrefed);
L.init(list);
list._timer._list = list;
-- if (unrefed === true) list._timer.unref();
list._timer.start(msecs, 0);
lists[msecs] = list;
@@ -149,7 +147,7 @@ function TimersList(msecs, unrefed) {
this._idleNext = null; // Create the list with the linkedlist properties to
this._idlePrev = null; // prevent any unnecessary hidden class changes.
this._timer = new TimerWrap();
- this._unrefed = unrefed;+ if (unrefed === true) this._timer.unref();
this.msecs = msecs;
}
@@ -207,7 +205,7 @@ function listOnTimeout() {
debug('%d list empty', msecs);
assert(L.isEmpty(list));
this.close();
- if (list._unrefed === true) {+ if (list._timer.isRefed() === false) {
delete unrefedLists[msecs];
} else {
delete refedLists[msecs];
diff --git a/lib/timers.js b/lib/timers.js
index dc2506e..cdc0d1c 100644
--- a/lib/timers.js+++ b/lib/timers.js@@ -133,8 +133,6 @@ function insert(item, unrefed) {
list = new TimersList(msecs, unrefed);
L.init(list);
list._timer._list = list;
-- if (unrefed === true) list._timer.unref();
list._timer.start(msecs, 0);
lists[msecs] = list;
@@ -149,7 +147,7 @@ function TimersList(msecs, unrefed) {
this._idleNext = null; // Create the list with the linkedlist properties to
this._idlePrev = null; // prevent any unnecessary hidden class changes.
this._timer = new TimerWrap();
- this._unrefed = unrefed;+ if (unrefed === true) this._timer.unref();
this.msecs = msecs;
}
@@ -207,10 +205,10 @@ function listOnTimeout() {
debug('%d list empty', msecs);
assert(L.isEmpty(list));
this.close();
- if (list._unrefed === true) {- delete unrefedLists[msecs];- } else {+ if (list._timer.isRefed() === true) {
delete refedLists[msecs];
+ } else {+ delete unrefedLists[msecs];
}
} |
Fishrock123
commented
Apr 7, 2016
So... it does work if I close after the delete (duh), but the behavior is still pretty confusing.. Will probably remove the |
MylesBorins
commented
Apr 8, 2016
@Fishrock123 you may want to chime into the v6 thread before the rc is cut if you don't think this should land |
This fixes my perceived usability issues with 7d8882b. Which, at the time of writing, has not landed in any release except v6 RCs. This should not be considered a breaking change due to that. It is useful if you have a handle, even if it has been closed, to be able to inspect whether that handle was unrefed or not. As such, this renames the method accordingly. If people need to check a handle's aliveness, that is a separate API we should consider exposing. Refs: nodejs#5834 PR-URL: nodejs#6204 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
This reverts commit 9bb5a5e. Refs: nodejs#6382 Refs: nodejs#6204 Refs: nodejs#5834
This reverts commit f938ef7. Refs: nodejs#6382 Refs: nodejs#6204 Refs: nodejs#5834
This reverts commit 7d8882b. Refs: nodejs#6382 Refs: nodejs#6204 Refs: nodejs#5834
This allows third-party tools to check whether or not a handle that can be unreferenced is unreferenced at a particular time. Notably, this should be helpful for inspection via AsyncWrap. Also, this is useful even to node's internals, particularly timers. Refs: #5828 Refs: #5827 PR-URL: #5834 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
This fixes my perceived usability issues with 7d8882b. Which, at the time of writing, has not landed in any release except v6 RCs. This should not be considered a breaking change due to that. It is useful if you have a handle, even if it has been closed, to be able to inspect whether that handle was unrefed or not. As such, this renames the method accordingly. If people need to check a handle's aliveness, that is a separate API we should consider exposing. Refs: #5834 PR-URL: #6204 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Pull Request check-list
make -j8 test(UNIX) orvcbuild test nosign(Windows) pass withthis change (including linting)?
Affected core subsystem(s)
handle_wrap
Description of change
Give tools a consistent way to check if a handle is unrefed that works for all of our APIs that expose handles. E.g. would be very helpful to see which handles are umrefed in @AndreasMadsen's https://github.com/AndreasMadsen/dprof
(Some APIs, like timers, do not normally expose handles and are not addressed at that level here)
Refs: #5828
Refs: #5827
R= @trevnorris
cc @thlorenz