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

Can't do process.on('SIGINT' with 0.5.4 on windows #1553

Closed
Pita opened this issue Aug 18, 2011 · 52 comments
Closed

Can't do process.on('SIGINT' with 0.5.4 on windows #1553

Pita opened this issue Aug 18, 2011 · 52 comments
Assignees

Comments

@Pita
Copy link

Pita commented Aug 18, 2011

original issue is here https://github.com/Pita/etherpad-lite/issues/94

We get following error message:

E:\etherpad-lite-win\node>..\bin\node server.js
←[32m[2011-08-18 04:36:32.850] [INFO] console - ←[39mServer is listening at 0.0.
0.0:9001

node.js:205
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: No such module
at EventEmitter. (node.js:318:27)
at E:\etherpad-lite-win\node\server.js:384:13
at E:\etherpad-lite-win\node_modules\async\lib\async.js:484:34
at Array. (E:\etherpad-lite-win\node_modules\async\lib\async.js:4
08:34)
at EventEmitter._tickCallback (node.js:197:26)

E:\etherpad-lite-win\node>

is on SIGINT a unix specific thing? is there something similar for windows? or is this a bug

@Pita
Copy link
Author

Pita commented Aug 18, 2011

this happend on windows xp btw

@piscisaureus
Copy link

SIGINT is not supported in windows indeed. It is possible to capture ctrl+c / ctrl+break on windows, but there is no support for this yet in node.

Adding event emitters should probably not crash node, but for the time being it might actually be good if it does.
@ry @bnoordhuis what do you guys think?

@bnoordhuis
Copy link
Member

Catching Windows events and emitting them as SIGINT / SIGTERM signals through the process object seems like the best option from a backwards compatibility / cross compatibility point of view.

@DrPizza
Copy link

DrPizza commented Aug 18, 2011

I had almost forgotten about it, but this issue is the one that made me start making code contributions to Node.

@wyattanderson
Copy link

Seems like a sensible way to accomplish this would be to have a win32-specific SignalWatcher object (since SignalWatcher isn't even included in the win32 build, as far as I can tell) that emulates signals in some appropriate fashion, right?

MSDN lists the "signals" a process can receive from the console, and maybe in combination with what can be received in normal conditions (process shutdown, etc.) emulate the POSIX equivalents.

The problems I see with this are twofold:

  1. Coming up with a sensible translation between Windows process events and POSIX signals
  2. It's probably more ideal to have some platform-independent abstraction for application/process state, perhaps in combination with what process.on already provides on Linux systems beyond stuff like SIGINT and SIGKILL.

Thoughts? Obviously not a member of the team or anything, but I've been contemplating a patch and wanted feedback.

@piscisaureus
Copy link

I agree that we'll need a way for node apps to capture console control signals. A patch should go into libuv - we haven't discussed this yet, but it seems obvious that we'll have to put a somewhat cross-platform equivalent of ev_signal in libuv.

@DrPizza
Copy link

DrPizza commented Sep 3, 2011

Windows has literally no equivalent to UNIX signals. The function you link to is a complete fake: sending a signal to the function directly executes the associated signal handler in the calling thread.

Ctrl-c is trappable and maps relatively well to SIGINT, and I think we should plumb in a handler to allow process.on('SIGINT') to map to ctrl-c. Beyond that, I can't think off-hand of anything else in Windows that's even remotely signal-like.

-----Original Message-----
From: wyattanderson [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 03 September 2011 23:21
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

Seems like a sensible way to accomplish this would be to have a win32-
specific SignalWatcher object (since SignalWatcher isn't even included in
the win32 build, as far as I can tell) that emulates signals in some
appropriate fashion, right?

[MSDN lists the "signals"](http://msdn.microsoft.com/en-
us/library/ms683242%28v=vs.85%29.aspx) a process can receive from the console,
and maybe in combination with what can be received in normal conditions
(process shutdown, etc.) emulate the POSIX equivalents.

The problems I see with this are twofold:

  1. Coming up with a sensible translation between Windows process events and
    POSIX signals 2. It's probably more ideal to have some platform-independent
    abstraction for application/process state, perhaps in combination with what
    process.on already provides on Linux systems beyond stuff like SIGINT and
    SIGKILL.

Thoughts? Obviously not a member of the team or anything, but I've been
contemplating a patch and wanted feedback.

Reply to this email directly or view it on GitHub:
#1553 (comment)

@piscisaureus
Copy link

@DrPizza
CTRL_CLOSE_EVENT != SIGTERM ?

@DrPizza
Copy link

DrPizza commented Sep 4, 2011

I'm not sure if they're exactly the same, but probably close enough.

More problematic are things like SIGALRM, SIGUSR, SIGHUP.

-----Original Message-----
From: piscisaureus [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 03 September 2011 23:37
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

@DrPizza
CTRL_CLOSE_EVENT != SIGTERM ?

Reply to this email directly or view it on GitHub:
#1553 (comment)

@wyattanderson
Copy link

Python's signal seems to "do the right thing" for Windows:

On Windows, signal() can only be called with SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, or SIGTERM. A ValueError will be raised in any other case.

Is the functionality in node_signal_handler.cpp being moved to libuv? That's what emits events on process, right?

@piscisaureus
Copy link

@wyattanderson
Did you verify it does the right thing? Is there any way you can use it in a meaningful way?

@DrPizza
Copy link

DrPizza commented Sep 4, 2011

SIGSEGV, SIGFPE, SIGILL are all SEH exceptions on Windows. We could feasibly install an SEH handler with e.g. AddVectoredExceptionHandler() that trapped these, but I'm not sure that we should.

SIGSEGV means there's a serious, possibly security-compromising, bug; crashing immediately is the only safe response.
SIGILL means that the compiler or V8 has a serious bug; crashing immediately is the only safe response.
SIGFPE means that V8 has a bug (since V8 should ensure FP is safe and handle any FP issues itself); crashing immediately is the only safe response.

SIGABRT would require abort() to co-operate and emit the signal. MSVC++ abort() doesn't co-operate and doesn't emit the signal; I have no idea what Python is doing to emulate it. I don't believe node gives any direct access to abort() anyway, so the value appears to be negligible to me.

SIGTERM should map to CTRL_CLOSE_EVENT, as @piscisaureus pointed out.


I think we can probably do something like this:
CTRL_C_EVENT -> SIGINT
CTRL_BREAK_EVENT -> SIGINT
CTRL_CLOSE_EVENT -> SIGTERM

CTRL_SHUTDOWN_EVENT and CTRL_LOGOFF_EVENT might be useful for services, but have no good signal that I know of. CTRL_SHUTDOWN_EVENT maps tolerably well to SIGTERM I suppose, but I'm not sure what to do with CTRL_LOGOFF_EVENT. Oh, apparently the documentation is wrong; CTRL_LOGOFF_EVENT is sent to any process on logoff. In that case, it too should become SIGTERM.

There might be some value in making CTRL_BREAK_EVENT do SIGHUP or something--that way, applications can use SIGHUP as a signal to reinitialize their configuration etc., which I believe some UNIX programs do.

@wyattanderson
Copy link

Sounds good, @DrPizza. I like the idea of mapping CTRL_BREAK_EVENT to SIGHUP, too.

@DrPizza
Copy link

DrPizza commented Sep 4, 2011

As for the implementation... node_signal_watcher.cc currently uses libev directly. My assumption is that libev should be hidden behind libuv, just as libeio is being hidden.

There's the other side to the equation--kill() will have to be implemented to generate events for the ctrl-c handler. At the moment, node.cc calls kill() directly, inside a #ifdef __POSIX__. So I imagine this needs to be moved to libuv too.

@ry
Copy link

ry commented Sep 21, 2011

It seems java used SIGQUIT on unix to print debug information and CTRL_BREAK_EVENT on Windows. http://www.ibm.com/developerworks/java/library/i-signalhandling/

Other signals used by the JVM are for internal control purposes and do not cause it to terminate. The only control signal of interest is SIGQUIT (on Unix type platforms) and SIGBREAK (on Windows), which cause a Java core dump to be generated.

@ry
Copy link

ry commented Oct 5, 2011

We should get this in v0.6

@OrangeDog
Copy link

CTRL_C_EVENT -> SIGINT
CTRL_BREAK_EVENT -> SIGKILL
CTRL_CLOSE_EVENT -> SIGTERM
CTRL_LOGOFF_EVENT -> SIGHUP

is what seems most natural to me. Many tools I encounter on Windows use Ctrl+C to request a graceful shutdown, while Ctrl+Break is reserved for hard kills. CTRL_BREAK_EVENT -> SIGHUP seems a little unexpected.

@DrPizza
Copy link

DrPizza commented Oct 31, 2011

Consider the behaviour of, for example, Windows' own ping.exe when run in non-stop mode (ping -t). ctrl-c terminates; ctrl-break just prints statistics and continues. Consider Java's behaviour, which when used to profile or debug the application uses ctrl-break to print statistics to the console without interrupting execution.

I think ctrl-break -> SIGHUP is entirely appropriate.

-----Original Message-----
From: OrangeDog [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 31 October 2011 15:27
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

CTRL_C_EVENT -> SIGINT
CTRL_BREAK_EVENT -> SIGKILL
CTRL_CLOSE_EVENT -> SIGTERM
CTRL_LOGOFF_EVENT -> SIGHUP

is what seems most natural to me. Many tools I encounter on Windows use
Ctrl+C to request a graceful shutdown, while Ctrl+Break is reserved for hard
kills. CTRL_BREAK_EVENT -> SIGHUP seems a little unexpected.

Reply to this email directly or view it on GitHub:
#1553 (comment)

@OrangeDog
Copy link

But SIGHUP doesn't mean "please print some statistics and carry on" it means "console/tty has been closed".

People generally expect 'Break' to break execution.

@DrPizza
Copy link

DrPizza commented Oct 31, 2011

I know what SIGHUP means, but I do not actually care. SIGHUP to rehash is a common pattern for non-interactive (daemon) programs on UNIX. If you don't like it, complain to the authors of the many, many programs that already work this way. The convention exists regardless of SIGHUP's proper meaning.

People don't generally expect "break" to do anything, and widely-used Windows programs, including some which ship with Windows, use ctrl-break to do something other than halt execution. If it's good enough for ping.exe, it's good enough for node.exe.

In any case, the intent is not to provide a perfect mapping. It's to provide a useful one. Windows distinguishes between ctrl-c and ctrl-break, ping.exe demonstrates that there are useful reasons to distinguish between ctrl-c and ctrl-break. Making both ctrl-c and ctrl-break produce SIGINT would deny the ability to distinguish.

Making ctrl-break produce SIGHUP is not perfect, but given the way SIGHUP is actually used by server programs, it is a reasonable fit.

-----Original Message-----
From: OrangeDog [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 31 October 2011 15:41
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

But SIGHUP doesn't mean "please print some statistics and carry on" it means
"console/tty has been closed".

People generally expect 'Break' to break execution.

Reply to this email directly or view it on GitHub:
#1553 (comment)

@OrangeDog
Copy link

I agree with making them distinguishable - hence my suggestions. Applications can assign handlers to do whatever they want (which is the original point of this issue), so all we have to worry about is having a logical mapping from Win32 to POSIX, without having to worry about what people might use them for.

Both the programs you cite only use this functionality in specific situations, not as a general rule.

@DrPizza
Copy link

DrPizza commented Oct 31, 2011

As a "general rule", ctrl-break doesn't do anything at all.

-----Original Message-----
From: OrangeDog [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 31 October 2011 16:18
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

I agree with making them distinguishable - hence my suggestions. Applications
can assign handlers to do whatever they want (which is the original point of
this issue), so all we have to worry about is having a logical mapping from
Win32 to POSIX, without having to worry about what people might use them for.

Both the programs you cite only use this functionality in specific
situations, not as a general rule.

Reply to this email directly or view it on GitHub:
#1553 (comment)

@OrangeDog
Copy link

Then map it to SIGUSR1.

@DrPizza
Copy link

DrPizza commented Oct 31, 2011

Why, when a standard UNIX daemon would put the corresponding action on SIGHUP?

-----Original Message-----
From: OrangeDog [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 31 October 2011 16:21
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

Then map it to SIGUSR1.

Reply to this email directly or view it on GitHub:
#1553 (comment)

@OrangeDog
Copy link

Because a standard UNIX non-daemon wouldn't (and POSIX gives a different default action for SIGHUP). Further looking around the internet and the consensus seems to be that Ctrl+Break is equivalent to SIGQUIT (mostly based on the behaviour of Java, as you noted above).

Another question is whether to discourage users from trying to handle CTRL_CLOSE_EVENT (by mapping it to SIGKILL) or not (using SIGTERM or similar).

@DrPizza
Copy link

DrPizza commented Oct 31, 2011

I think node.js's goal, "scalable network programs", makes the daemon the more relevant comparison. Yes, it can be used interactively, yes, it has a REPL. I know this. I still maintain that daemon behaviour is the more appropriate, over all.

I don't really see how it can be "mapped" to SIGKILL. SIGKILL can't be caught. Unless you mean simply that it should call abort() or similar, to provide an effect roughly similar to SIGKILL. I don't like the sound of that. Windows' SIGKILL is TerminateProcess(). CTRL_CLOSE_EVENT is sent to the application to give it a few seconds to shut down; if it doesn't end in time, TerminateProcess() is then used. We shouldn't abort early.

-----Original Message-----
From: OrangeDog [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 31 October 2011 16:38
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

Because a standard UNIX non-daemon wouldn't (and POSIX gives a different
default action for SIGHUP). Further looking around the internet and the
consensus seems to be that Ctrl+Break is equivalent to SIGQUIT (mostly based
on the behaviour of Java, as you noted above).

Another question is whether to discourage users from trying to handle
CTRL_CLOSE_EVENT (by mapping it to SIGKILL) or not (using SIGTERM or
similar).

Reply to this email directly or view it on GitHub:
#1553 (comment)

@ghost
Copy link

ghost commented Oct 31, 2011

@DrPizza "I know what SIGHUP means, but I do not actually care" But you should, or you end up giving wrong suggestions that may bring more bad than good. SIGHUP is unix equivalent of logout (hangup - hanging up the terminal line, legacy from the times where terminal was dialed and may get hang-up event, thus ending terminal session; hence, the nohup unix command to let the process survive SIGHUP). So it only natural that logout is mapped to SIGHUP and Ctrl+C is mapped to SIGUSR1.

(and don't ask me why they overloaded it with another meaning in case of daemons)

@OrangeDog: +1 to your list with SIGUSR1 amendment.

@OrangeDog
Copy link

Good point about SIGKILL, was getting confused with kill. I still think you're concentrating too much on 'UI event' -> 'Action user code should take' rather than 'UI event' -> 'Event we should emit'.

How about:
CTRL_C_EVENT -> SIGINT
CTRL_BREAK_EVENT -> SIGQUIT
CTRL_CLOSE_EVENT -> SIGTERM
CTRL_LOGOFF_EVENT -> SIGHUP

@DrPizza
Copy link

DrPizza commented Oct 31, 2011

Convention is far more important than specification. Node's forte is daemon-like programs; it should follow daemon conventions.

And mapping ctrl-c to SIGUSR1 is indefensible.

-----Original Message-----
From: Herbert Vojčík [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 31 October 2011 16:57
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

@DrPizza "I know what SIGHUP means, but I do not actually care" But you
should, or you end up giving wrong suggestions that may bring more bad than
good. SIGHUP is unix equivalent of logout (hangup - hanging up the terminal
line, legacy from the times where terminal was dialed and may get hang-up
event, thus ending terminal session; hence, the nohup unix command to let the
process survive SIGHUP). So it only natural that logout is mapped to SIGHUP
and Ctrl+C is mapped to SIGUSR1.

(and don't ask me why they overloaded it with another meaning in case of
daemons)

@OrangeDog: +1 to your list with SIGUSR1 amendment.

Reply to this email directly or view it on GitHub:
#1553 (comment)

@DrPizza
Copy link

DrPizza commented Oct 31, 2011

The Windows logoff event simply isn't comparable in terms of when it's sent or how it's sent. CTRL_LOGOFF_EVENT is (per the documentation, though not necessarily the implementation) sent only to services (i.e. programs connected to the SCM). While there's some evidence that it's also, erroneously, sent to interactive programs, they also get terminated afterwards anyway.

node.js has no facility for creating Windows services, so the entire CTRL_LOGOFF_EVENT machinery is irrelevant to it.

Consider also: there's no (easy) way to send the logoff event to a process, so no (easy) way to get SIGHUP-style configuration rehashing. ctrl-c and ctrl-break are the only signals that are easy to send, because they're the only ones that can be typed at the keyboard.

-----Original Message-----
From: OrangeDog [mailto:reply+i-1431458-
6065c7da3c61c53fc30e308d647ef00abb9439bc@reply.github.com]
Sent: 31 October 2011 17:00
To: DrPizza
Subject: Re: [node] Can't do process.on('SIGINT' with 0.5.4 on windows
(#1553)

Good point about SIGKILL, was getting confused with kill. I still think
you're concentrating too much on 'UI event' -> 'Action user code should take'
rather than 'UI event' -> 'Event we should emit'.

How about:
CTRL_C_EVENT -> SIGINT
CTRL_BREAK_EVENT -> SIGQUIT
CTRL_CLOSE_EVENT -> SIGTERM
CTRL_LOGOFF_EVENT -> SIGHUP

Reply to this email directly or view it on GitHub:
#1553 (comment)

@piscisaureus
Copy link

Just to keep everyone posted, the behavior that ctrl+break starts the debugger has been removed. To start the debugger, use node debug -p <<pid>> from another console.

@andyburke
Copy link

Although there's been lively argument above, this still seems an issue. I'm currently hitting it on windows in node 0.6.6. Personally, I don't care about what maps to SIGHUP. The thing stopping me right now is not being able to bind SIGINT.

Could this issue be broken into non-contentious and contentious parts and dealt with piecemeal?

@OrangeDog
Copy link

Priority order should be:

  1. Warn, don't crash when adding listeners
  2. Allow catching Ctrl+C as SIGINT
  3. The rest

@FLYBYME
Copy link

FLYBYME commented Jan 27, 2012

Is this still a problem? Im running win 0.6.6

@luffs
Copy link

luffs commented Feb 2, 2012

Still a problem in v0.6.9 (Win7x64)

@olecom
Copy link

olecom commented Mar 25, 2012

I suggest managing processes by simple http server example, node has on its web site. This is not OS specific, doesn’t require node versioning. No need of PID files.

Any flexibility of SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGUSR* can be programmed inside that “process controlling channel”. Just some localhost privilege separation and auth will be needed.

Especially this is true when we see, that automation scripting in e.g. WSH has only Terminate() method to manage execution of a process by its PID (kill –KILL as I can see).

I.e. if SIG* stuff will be implemented under MS Windows, it will be a thing inside node itself anyway. And this will be NIH (from e.g. Cygwin)…

If other application must be managed, signals aren’t right thing to do also. I.e. mongodb has
{ "shutdown" : 1 } or db.shutdownServer().

@OrangeDog
Copy link

@olecom Not every Node program is am HTTP server. Also, a public webserver that terminates when you make a particular request is not a good idea.

Perl supports "signals" on Windows using exactly the same syntax as on *NIX (i.e. it's actually a portable platform), so I don't see why Node shouldn't too.

@FLYBYME
Copy link

FLYBYME commented Mar 25, 2012

So this is not a node "0.5.4" version but more with windows and node. The title is a bit miss leading.

@rlidwka
Copy link

rlidwka commented Mar 25, 2012

If other application must be managed, signals aren’t right thing to do

It is the right thing to do because it is independent of other app API

Mongo has {"shutdown":1}. Does mysql or nginx have it? But SIGINT will shutdown them both.

@olecom
Copy link

olecom commented Mar 25, 2012

Does mysql or nginx have it? But SIGINT will shutdown them both.

Right.
But that SIGINT must not be in node under MS Windows...
I say cygwin, others say perl, that's OK. Process management (start/stop, watchdogs, bin updates) must be done using external and solid tools. Under linux-gnu this are shell and perl. So....

@springmeyer
Copy link

just hit this with node 0.6.15

@kylealanhale
Copy link

As thrilling as these semantic discussions have been, we really need to finalize a way to monitor processes in all OSes using a consistent API. Cleaning up after worker processes when using cluster in Windows is impossible in some circumstances (such as stopping a run or debug session in WebStorm).

@Ivanca
Copy link

Ivanca commented May 30, 2012

I little work around I found is to capture the STDIN and use process.exit() when Ctrl+C is pressed; and then just listen to process.on("exit")

if(process.platform === "win32"){
    var rint = require('readline').createInterface( process.stdin, {} ); 
    rint.input.on('keypress',function( char, key) {
        if(char === "\u0003"){
            process.exit();
        }               
    }); 
    require('tty').setRawMode(true);
}

@penartur
Copy link

@altIvan That won't work when stdin has been redirected (e.g. node app.js < input.txt). I'm not sure whether it won't crash trying to attach to such a stream at all.

@Ivanca
Copy link

Ivanca commented May 30, 2012

@penartur Yeah, I am sure it doesn't work in many situations, is just if you are doing something really simple and just want Ctrl+C to fire an event

@lancehunt
Copy link

I tossed-in an ugly try/catch around this issue for now, but it would be nice if node didnt blow chunks on this.

@seanmonstar
Copy link

Agreed, less chunk-blowing would be preferable.

@springmeyer
Copy link

It appears that ea1cba6, which landed in v0.8.9, avoids the throw of 'no such module'

@bnoordhuis
Copy link
Member

Yes, this should be solved now. Closing.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests