Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,29 @@ added: v0.5.8
Stop watching for changes on the given `fs.FSWatcher`. Once stopped, the
`fs.FSWatcher` object is no longer usable.

### `watcher.ref()`
<!-- YAML
added: REPLACEME
-->

When called, requests that the Node.js event loop *not* exit so long as the
`FSWatcher` is active. Calling `watcher.ref()` multiple times will have
no effect.

By default, all `FSWatcher` objects are "ref'ed", making it normally
unnecessary to call `watcher.ref()` unless `watcher.unref()` had been
called previously.

### `watcher.unref()`
<!-- YAML
added: REPLACEME
-->
When called, the active `FSWatcher` object will not require the Node.js
Comment thread
rickyes marked this conversation as resolved.
event loop to remain active. If there is no other activity keeping the
event loop running, the process may exit before the `FSWatcher` object's
callback is invoked. Calling `watcher.unref()` multiple times will have
no effect.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These methods should probably also be documented for the return value of .watchFile().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK, there are other methods like .stop(), I'm not sure if it should be documented in this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed


## Class: `fs.ReadStream`
<!-- YAML
added: v0.1.93
Expand Down
3 changes: 3 additions & 0 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,9 @@ function watchFile(filename, options, listener) {
stat[watchers.kFSStatWatcherStart](filename,
options.persistent, options.interval);
statWatchers.set(filename, stat);
} else {
stat[watchers.KFSStatWatcherRefCount]++;
stat[watchers.KFSStatWatcherMaxRefCount]++;
Comment thread
rickyes marked this conversation as resolved.
Outdated
}

stat.addListener('change', listener);
Expand Down
33 changes: 31 additions & 2 deletions lib/internal/fs/watchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const kUseBigint = Symbol('kUseBigint');

const kFSWatchStart = Symbol('kFSWatchStart');
const kFSStatWatcherStart = Symbol('kFSStatWatcherStart');
const KFSStatWatcherRefCount = Symbol('KFSStatWatcherRefCount');
const KFSStatWatcherMaxRefCount = Symbol('KFSStatWatcherMaxRefCount');

function emitStop(self) {
self.emit('stop');
Expand All @@ -42,6 +44,8 @@ function StatWatcher(bigint) {
this._handle = null;
this[kOldStatus] = -1;
this[kUseBigint] = bigint;
this[KFSStatWatcherRefCount] = 1;
this[KFSStatWatcherMaxRefCount] = 1;
}
ObjectSetPrototypeOf(StatWatcher.prototype, EventEmitter.prototype);
ObjectSetPrototypeOf(StatWatcher, EventEmitter);
Expand Down Expand Up @@ -75,7 +79,7 @@ StatWatcher.prototype[kFSStatWatcherStart] = function(filename,
this._handle[owner_symbol] = this;
this._handle.onchange = onchange;
if (!persistent)
this._handle.unref();
this.unref();

// uv_fs_poll is a little more powerful than ev_stat but we curb it for
// the sake of backwards compatibility.
Expand Down Expand Up @@ -117,6 +121,21 @@ StatWatcher.prototype.stop = function() {
this._handle = null;
};

StatWatcher.prototype.ref = function() {
// Avoid refCount calling ref multiple times causing unref to have no effect.
if (this[KFSStatWatcherRefCount] === this[KFSStatWatcherMaxRefCount])
return;
if (this._handle && this[KFSStatWatcherRefCount]++ === 0)
this._handle.ref();
};

StatWatcher.prototype.unref = function() {
// Avoid refCount calling unref multiple times causing ref to have no effect.
if (this[KFSStatWatcherRefCount] === 0) return;
if (this._handle && --this[KFSStatWatcherRefCount] === 0)
this._handle.unref();
};
Comment thread
rickyes marked this conversation as resolved.


function FSWatcher() {
EventEmitter.call(this);
Expand Down Expand Up @@ -208,6 +227,14 @@ FSWatcher.prototype.close = function() {
process.nextTick(emitCloseNT, this);
};

FSWatcher.prototype.ref = function() {
if (this._handle) this._handle.ref();
};

FSWatcher.prototype.unref = function() {
if (this._handle) this._handle.unref();
};
Comment thread
rickyes marked this conversation as resolved.

function emitCloseNT(self) {
self.emit('close');
}
Expand All @@ -223,5 +250,7 @@ module.exports = {
FSWatcher,
StatWatcher,
kFSWatchStart,
kFSStatWatcherStart
kFSStatWatcherStart,
KFSStatWatcherRefCount,
KFSStatWatcherMaxRefCount,
};
3 changes: 1 addition & 2 deletions src/fs_event_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,8 @@ void FSEventWrap::Initialize(Local<Object> target,
FSEventWrap::kInternalFieldCount);
t->SetClassName(fsevent_string);

t->Inherit(AsyncWrap::GetConstructorTemplate(env));
t->Inherit(HandleWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "start", Start);
env->SetProtoMethod(t, "close", Close);

Local<FunctionTemplate> get_initialized_templ =
FunctionTemplate::New(env->isolate(),
Expand Down
35 changes: 35 additions & 0 deletions test/parallel/test-fs-watch-ref-unref.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

const common = require('../common');

if (common.isIBMi)
common.skip('IBMi does not support `fs.watch()`');

const fs = require('fs');
const assert = require('assert');

let refCount = 0;

const watcher = fs.watch(__filename, common.mustNotCall());

function unref() {
watcher.unref();
refCount--;
assert.strictEqual(refCount, -1);
}

function ref() {
watcher.ref();
refCount++;
assert.strictEqual(refCount, 0);
}

unref();

setTimeout(
common.mustCall(() => {
ref();
unref();
}),
common.platformTimeout(100)
);
36 changes: 36 additions & 0 deletions test/parallel/test-fs-watchfile-ref-unref.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

const common = require('../common');

const fs = require('fs');
const assert = require('assert');

let refCount = 0;

const watcher = fs.watchFile(__filename, common.mustNotCall());

function unref() {
watcher.unref();
refCount--;
Comment thread
rickyes marked this conversation as resolved.
Outdated
assert.strictEqual(refCount, -1);
}

function ref() {
watcher.ref();
refCount++;
assert.strictEqual(refCount, 0);
}

unref();

setTimeout(
common.mustCall(() => {
ref();
unref();
watcher.unref();
watcher.ref();
watcher.ref();
watcher.unref();
}),
common.platformTimeout(100)
);