Guard against the possibility that the queue is emptied while we're iterating
over it. Simple test case:
#include "ngx-queue.h"
#include <assert.h>
int main(void) {
ngx_queue_t h;
ngx_queue_t v[2];
ngx_queue_t* q;
unsigned n = 0;
ngx_queue_init(&h);
ngx_queue_insert_tail(&h, v + 0);
ngx_queue_insert_tail(&h, v + 1);
ngx_queue_foreach(q, &h) {
ngx_queue_remove(v + 0);
ngx_queue_remove(v + 1);
n++;
}
assert(n == 1); // *not* 2
return 0;
}
Fixes#605.
uv_fs_poll_t has an embedded uv_timer_t handle that got closed at a time when
the memory of the encapsulating handle might already have been deallocated.
Solve that by moving the poller's state into a structure that is allocated on
the heap and can be freed independently.
Problem: registering two uv_fs_event_t watchers for the same path, then closing
them, caused a segmentation fault. While active, the watchers didn't work right
either, only one would receive events.
Cause: each watcher has a wd (watch descriptor) that's used as its key in a
binary tree. When you call inotify_watch_add() twice with the same path, the
second call doesn't return a new wd - it returns the existing one. That in turn
resulted in the first handle getting ousted from the binary tree, leaving
dangling pointers.
This commit addresses that by storing the watchers in a queue and storing the
queue in the binary tree instead of storing the watchers directly in the tree.
Fixesjoyent/node#3789.
produces better error message from test-dgram-multicast-multi-process
when run w/o network.
before:
=== release test-dgram-multicast-multi-process ===
Path: simple/test-dgram-multicast-multi-process
dgram.js:287
throw new errnoException(errno, 'addMembership');
^
Error: addMembership Unknown system errno 19
at new errnoException (dgram.js:356:11)
at Socket.addMembership (dgram.js:287:11)
at Object.<anonymous> (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
[PARENT] Worker 9223 died. 1 dead of 3
dgram.js:287
throw new errnoException(errno, 'addMembership');
^
Error: addMembership Unknown system errno 19
at new errnoException (dgram.js:356:11)
at Socket.addMembership (dgram.js:287:11)
at Object.<anonymous> (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
[PARENT] sent 'First message to send' to 224.0.0.114:12346
dgram.js:287
[PARENT] sent 'Second message to send' to 224.0.0.114:12346
throw new errnoException(errno, 'addMembership');
[PARENT] sent 'Third message to send' to 224.0.0.114:12346
^
[PARENT] sendSocket closed
[PARENT] Worker 9224 died. 2 dead of 3
Error: addMembership Unknown system errno 19
at new errnoException (dgram.js:356:11)
at Socket.addMembership (dgram.js:287:11)
at Object.<anonymous> (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
[PARENT] Worker 9225 died. 3 dead of 3
[PARENT] All workers have died.
[PARENT] Fail
Command: out/Release/node /home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js
after:
=== release test-dgram-multicast-multi-process ===
Path: simple/test-dgram-multicast-multi-process
dgram.js:287
throw new errnoException(errno, 'addMembership');
^
Error: addMembership ENODEV
at new errnoException (dgram.js:356:11)
at Socket.addMembership (dgram.js:287:11)
at Object.<anonymous> (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
[PARENT] Worker 13141 died. 1 dead of 3
dgram.js:287
throw new errnoException(errno, 'addMembership');
^
[PARENT] sent 'First message to send' to 224.0.0.114:12346
[PARENT] sent 'Second message to send' to 224.0.0.114:12346
[PARENT] sent 'Third message to send' to 224.0.0.114:12346
[PARENT] sent 'Fourth message to send' to 224.0.0.114:12346
[PARENT] sendSocket closed
dgram.js:287
throw new errnoException(errno, 'addMembership');
^
Error: addMembership ENODEV
at new errnoException (dgram.js:356:11)
at Socket.addMembership (dgram.js:287:11)
at Object.<anonymous> (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
[PARENT] Worker 13142 died. 2 dead of 3
Error: addMembership ENODEV
at new errnoException (dgram.js:356:11)
at Socket.addMembership (dgram.js:287:11)
at Object.<anonymous> (/home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js:224:16)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
[PARENT] Worker 13143 died. 3 dead of 3
[PARENT] All workers have died.
[PARENT] Fail
Command: out/Release/node /home/roman/wc/node/test/simple/test-dgram-multicast-multi-process.js
* the callback gets called only once on error, not repeatedly...
* ...unless the error reason changes from e.g. UV_ENOENT to UV_EACCES
* the callback receives pointers to uv_statbuf_t objects so it can inspect what
changed
* replace libev backed timers with a pure libuv implementation
* gut ev_run() and make it take a timeout instead of flags
Incidentally speeds up the loop_count_timed benchmark by about 100%.
Previously the only option was to create a pipe or an ipc channel. This
patch makes it possible to inherit a handle that is already open in the
parent process. There is also room for setting more than just stdin,
stdout and stderr, although this is not supported yet.
Makes the uv__io code a little more obscure but has the advantage that
sizeof(uv__io_t) == sizeof(ev_io), i.e. the sizes of embedding handles
don't change.
The new idle watcher was temporarily disabled in 073a48d due to some semantic
incompatibilities with the previous implementation. This commit resolves those
issues and reactivates the new implementation.
One outstanding bug is that idle watchers can run in a different order
(relative to other handle types) than the old implementation, e.g. (timer, idle)
instead of the expected (idle, timer). This will be fixed in an upcoming commit.
This commit changes how the event loop determines if it needs to stay alive.
Previously, an internal counter was increased whenever a handle got created
and decreased again when the handle was closed.
While conceptually simple, it turned out hard to work with: you often want
to keep the event loop alive only if the handle is actually doing something.
Stopped or inactive handles were a frequent source of hanging event loops.
That's why this commit changes the reference counting scheme to a model where
a handle only references the event loop when it's active. 'Active' means
different things for different handle types, e.g.:
* timers: ticking
* sockets: reading, writing or listening
* processes: always active (for now, subject to change)
* idle, check, prepare: only active when started
This commit also changes how the uv_ref() and uv_unref() functions work: they
now operate on the level of individual handles, not the whole event loop.
The Windows implementation was done by Bert Belder.
Instead of using one port per watch, use one port for all the watches.
This is a cherry-pick of commit 7326962 from v0.6 into master.
Conflicts:
include/uv-private/uv-unix.h
src/unix/core.c
src/unix/sunos.c