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

Commit

Permalink
Browse files Browse the repository at this point in the history
fs: make fs.watchFile() work on windows
  • Loading branch information
bnoordhuis committed Jun 21, 2012
1 parent d98a857 commit f0ce984
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 63 deletions.
12 changes: 7 additions & 5 deletions lib/fs.js
Expand Up @@ -876,7 +876,13 @@ function StatWatcher() {
var self = this;
this._handle = new binding.StatWatcher();

this._handle.onchange = function(current, previous) {
// uv_fs_poll is a little more powerful than ev_stat but we curb it for
// the sake of backwards compatibility
var oldStatus = -1;

this._handle.onchange = function(current, previous, newStatus) {
if (oldStatus == -1 && newStatus == -1) return;
oldStatus = newStatus;
self.emit('change', current, previous);
};

Expand Down Expand Up @@ -905,10 +911,6 @@ function inStatWatchers(filename) {


fs.watchFile = function(filename) {
if (isWindows) {
throw new Error('use fs.watch api instead');
}

var stat;
var options;
var listener;
Expand Down
2 changes: 1 addition & 1 deletion node.gyp
Expand Up @@ -82,6 +82,7 @@
'src/node_main.cc',
'src/node_os.cc',
'src/node_script.cc',
'src/node_stat_watcher.cc',
'src/node_string.cc',
'src/node_zlib.cc',
'src/pipe_wrap.cc',
Expand Down Expand Up @@ -208,7 +209,6 @@
'defines': [ '__POSIX__' ],
'sources': [
'src/node_signal_watcher.cc',
'src/node_stat_watcher.cc',
'src/node_io_watcher.cc',
]
}],
Expand Down
1 change: 0 additions & 1 deletion src/node.cc
Expand Up @@ -69,7 +69,6 @@ typedef int mode_t;
#include "node_http_parser.h"
#ifdef __POSIX__
# include "node_signal_watcher.h"
# include "node_stat_watcher.h"
#endif
#include "node_constants.h"
#include "node_javascript.h"
Expand Down
6 changes: 1 addition & 5 deletions src/node_file.cc
Expand Up @@ -22,9 +22,7 @@
#include "node.h"
#include "node_file.h"
#include "node_buffer.h"
#ifdef __POSIX__
# include "node_stat_watcher.h"
#endif
#include "node_stat_watcher.h"
#include "req_wrap.h"

#include <fcntl.h>
Expand Down Expand Up @@ -984,9 +982,7 @@ void InitFs(Handle<Object> target) {

oncomplete_sym = NODE_PSYMBOL("oncomplete");

#ifdef __POSIX__
StatWatcher::Initialize(target);
#endif
}

} // end namespace node
Expand Down
68 changes: 36 additions & 32 deletions src/node_stat_watcher.cc
Expand Up @@ -25,6 +25,11 @@
#include <string.h>
#include <stdlib.h>

// Poll interval in milliseconds. 5007 is what libev used to use. It's a little
// on the slow side but let's stick with it for now, keep behavioral changes to
// a minimum.
#define DEFAULT_POLL_INTERVAL 5007

namespace node {

using namespace v8;
Expand All @@ -33,6 +38,7 @@ Persistent<FunctionTemplate> StatWatcher::constructor_template;
static Persistent<String> onchange_sym;
static Persistent<String> onstop_sym;


void StatWatcher::Initialize(Handle<Object> target) {
HandleScope scope;

Expand All @@ -48,18 +54,24 @@ void StatWatcher::Initialize(Handle<Object> target) {
}


void StatWatcher::Callback(EV_P_ ev_stat *watcher, int revents) {
assert(revents == EV_STAT);
StatWatcher *handler = static_cast<StatWatcher*>(watcher->data);
assert(watcher == &handler->watcher_);
void StatWatcher::Callback(uv_fs_poll_t* handle,
int status,
const uv_statbuf_t* prev,
const uv_statbuf_t* curr) {
StatWatcher* wrap = container_of(handle, StatWatcher, watcher_);
assert(handle == &wrap->watcher_);
HandleScope scope;
Local<Value> argv[2];
argv[0] = BuildStatsObject(&watcher->attr);
argv[1] = BuildStatsObject(&watcher->prev);
Local<Value> argv[3];
argv[0] = BuildStatsObject(curr);
argv[1] = BuildStatsObject(prev);
argv[2] = Integer::New(status);
if (status == -1) {
SetErrno(uv_last_error(wrap->watcher_.loop));
}
if (onchange_sym.IsEmpty()) {
onchange_sym = NODE_PSYMBOL("onchange");
}
MakeCallback(handler->handle_, onchange_sym, ARRAY_SIZE(argv), argv);
MakeCallback(wrap->handle_, onchange_sym, ARRAY_SIZE(argv), argv);
}


Expand All @@ -69,7 +81,7 @@ Handle<Value> StatWatcher::New(const Arguments& args) {
}

HandleScope scope;
StatWatcher *s = new StatWatcher();
StatWatcher* s = new StatWatcher();
s->Wrap(args.Holder());
return args.This();
}
Expand All @@ -82,52 +94,44 @@ Handle<Value> StatWatcher::Start(const Arguments& args) {
return ThrowException(Exception::TypeError(String::New("Bad arguments")));
}

StatWatcher *handler = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
StatWatcher* wrap = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
String::Utf8Value path(args[0]);

assert(handler->path_ == NULL);
handler->path_ = strdup(*path);

ev_tstamp interval = 0.;
if (args[2]->IsInt32()) {
interval = NODE_V8_UNIXTIME(args[2]);
uint32_t interval = DEFAULT_POLL_INTERVAL;

This comment has been minimized.

Copy link
@shigeki

shigeki Jun 21, 2012

The default option.interval is set to be 0 in https://github.com/joyent/node/blob/master/lib/fs.js#L931 so that this initial value is never applied.
Is the default interval still 0[msec] even in new uv_fs_poll() timer or is it to be changed to DEFAULT_POLL_INTERVAL?
Anyway, inofity is no longer used in StatWatcher so the doc should be changed to be in 9d32425 . I've already confirmed that interval of fs.watchFile works fine even in Linux. Thanks.

This comment has been minimized.

Copy link
@bnoordhuis

bnoordhuis Jun 21, 2012

Author Member

You're right, thanks for pointing that out. Fixed in ef1ffcb and 8708bb0.

if (args[2]->IsUint32()) {
interval = args[2]->Uint32Value();
}

ev_stat_set(&handler->watcher_, handler->path_, interval);
ev_stat_start(EV_DEFAULT_UC_ &handler->watcher_);
uv_fs_poll_start(&wrap->watcher_, Callback, *path, interval);

handler->persistent_ = args[1]->IsTrue();
wrap->persistent_ = args[1]->IsTrue();

if (!handler->persistent_) {
ev_unref(EV_DEFAULT_UC);
if (!wrap->persistent_) {
uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->watcher_));
}

handler->Ref();
wrap->Ref();

return Undefined();
}


Handle<Value> StatWatcher::Stop(const Arguments& args) {
HandleScope scope;
StatWatcher *handler = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
StatWatcher* wrap = ObjectWrap::Unwrap<StatWatcher>(args.Holder());
if (onstop_sym.IsEmpty()) {
onstop_sym = NODE_PSYMBOL("onstop");
}
MakeCallback(handler->handle_, onstop_sym, 0, NULL);
handler->Stop();
MakeCallback(wrap->handle_, onstop_sym, 0, NULL);
wrap->Stop();
return Undefined();
}


void StatWatcher::Stop () {
if (watcher_.active) {
if (!persistent_) ev_ref(EV_DEFAULT_UC);
ev_stat_stop(EV_DEFAULT_UC_ &watcher_);
free(path_);
path_ = NULL;
Unref();
}
if (!uv_is_active(reinterpret_cast<uv_handle_t*>(&watcher_))) return;
uv_fs_poll_stop(&watcher_);
Unref();
}


Expand Down
15 changes: 7 additions & 8 deletions src/node_stat_watcher.h
Expand Up @@ -23,7 +23,7 @@
#define NODE_STAT_WATCHER_H_

#include "node.h"
#include "uv-private/ev.h"
#include "uv.h"

namespace node {

Expand All @@ -36,28 +36,27 @@ class StatWatcher : ObjectWrap {

StatWatcher() : ObjectWrap() {
persistent_ = false;
path_ = NULL;
ev_init(&watcher_, StatWatcher::Callback);
watcher_.data = this;
uv_fs_poll_init(uv_default_loop(), &watcher_);
}

~StatWatcher() {
Stop();
assert(path_ == NULL);
}

static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> Start(const v8::Arguments& args);
static v8::Handle<v8::Value> Stop(const v8::Arguments& args);

private:
static void Callback(EV_P_ ev_stat *watcher, int revents);
static void Callback(uv_fs_poll_t* handle,
int status,
const uv_statbuf_t* prev,
const uv_statbuf_t* curr);

void Stop();

ev_stat watcher_;
uv_fs_poll_t watcher_;
bool persistent_;
char *path_;
};

} // namespace node
Expand Down
6 changes: 0 additions & 6 deletions test/pummel/test-fs-watch-file.js
Expand Up @@ -19,12 +19,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

// fs.watchFile is not available on Windows
if (process.platform === 'win32') {
process.exit(0);
}


var common = require('../common');
var assert = require('assert');
var path = require('path');
Expand Down
5 changes: 0 additions & 5 deletions test/pummel/test-watch-file.js
Expand Up @@ -19,11 +19,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

// fs.watchFile is not available on Windows
if (process.platform === 'win32') {
process.exit(0);
}

var common = require('../common');
var assert = require('assert');

Expand Down

0 comments on commit f0ce984

Please sign in to comment.