Project

General

Profile

Actions

Bug #17820

closed

`Errno::EINVAL` from `Process.kill` with available signal on Windows

Added by AlexWayfer (Alexander Popov) 16 days ago. Updated 12 days ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x64-mingw32]
[ruby-core:103556]

Description

Hello.

I've installed Ruby on Windows via Chocolatey.

I receive Errno::EINVAL from Process.kill with almost every signal. Only 0 seems working. TERM (15), INT (2) — don't. Although they're in Signal.list output:


Files

clipboard-202104222051-b64xq.png (63.9 KB) clipboard-202104222051-b64xq.png AlexWayfer (Alexander Popov), 04/22/2021 05:51 PM
clipboard-202104222318-tbufr.png (96.8 KB) clipboard-202104222318-tbufr.png AlexWayfer (Alexander Popov), 04/22/2021 08:18 PM

Updated by xtkoba (Tee KOBAYASHI) 16 days ago

This seems to be a well-known restriction. Only KILL (9) works for Windows.

https://blog.simplificator.com/2016/01/18/how-to-kill-processes-on-windows-using-ruby/

Updated by AlexWayfer (Alexander Popov) 16 days ago

xtkoba (Tee KOBAYASHI) wrote in #note-1:

This seems to be a well-known restriction. Only KILL (9) works for Windows.

https://blog.simplificator.com/2016/01/18/how-to-kill-processes-on-windows-using-ruby/

Yes, I found this article, and wanted to add the link to the issue description, but didn't find an ability to edit the description.

So, about this article and behavior:

  1. This behavior doesn't seem "well-known restriction", there is no explanation or details (why?) in the article or somewhere.
  2. Article highlights that even KILL signal works incorrect on Windows (but I guess it should be a separate issue).
  3. Article suggests system command instead of Ruby method.
  4. There is should be consistency and understandable behavior in Ruby, even in Windows (as I know, Ruby should works on Windows). So, either Signal.list should return only KILL and something else working, or Process.kill should works with TERM and other signals. Anyway, Signal.list output and Process.kill input should be synced.

Also I found this SO answer and there are only outputs too, without details and explanation, like "it should work, try and puzzle it out by yourself".

Updated by AlexWayfer (Alexander Popov) 16 days ago

Also I found a very strange behavior with Signal.trap, not sure is it related, but I'm still sure that all signals should be synchronized and consistent.

So… Signal.trap('KILL') raises Invalid argument - SIGKILL (Errno::EINVAL). And other signals, which are incorrect for Process.kill, don't raise errors:

Updated by xtkoba (Tee KOBAYASHI) 16 days ago

The signals (except for EXIT, that is a pseudo signal) listed in Signal.list are valid to be sent to Process.pid ($$).

I suppose it is not easy to make POSIX signals consistent with Windows.

Updated by AlexWayfer (Alexander Popov) 16 days ago

xtkoba (Tee KOBAYASHI) wrote in #note-4:

The signals (except for EXIT, that is a pseudo signal) listed in Signal.list are valid to be sent to Process.pid ($$).

Sorry, what? This method only returns process ID, what do you mean about "send signals to Process.pid"?

xtkoba (Tee KOBAYASHI) wrote in #note-4:

I suppose it is not easy to make POSIX signals consistent with Windows.

Either the list of signals should be shortened and consistent among methods (Process.kill, Signal.list, Signal.trap, etc.), or some of these methods should raise an exception, like Process.getpgid: getpgid() function is unimplemented on this machine (NotImplementedError).

Updated by xtkoba (Tee KOBAYASHI) 16 days ago

I mean for example the following script works even on Windows (MinGW32).

Process.kill :TERM, Process.pid

Updated by jeremyevans0 (Jeremy Evans) 12 days ago

  • Status changed from Open to Rejected

I tested every signal from Signal.list on Windows 10, and all signals work in some fashion, assuming you send the signal to the current process. For Process.kill:

  • INT raises a standard Interrupt exception
  • ILL/SEGV simulates a crash and generates a backtrace (does not run ensure blocks)
  • ABRT/FPE/KILL exits immediately (does not run ensure blocks)
  • TERM exits immediately (runs ensure blocks)
  • EXIT doesn't work

However, EXIT works for Signal.trap. This code prints 1 and then 2:

Signal.trap('EXIT'){p 2}
begin
  Process.kill('TERM', $$)
ensure
  p 1
end

So all signals listed in Signal.list are valid in some context. The documentation for Signal itself states:

The list of available signal names and their interpretation is
system dependent.

So Ruby makes no guarantee that signal handling behavior will be consistent across systems.

Considering all this, I don't think the current behavior is a bug. If you think the behavior or documentation could be improved, please submit a pull request.

Updated by AlexWayfer (Alexander Popov) 12 days ago

jeremyevans0 (Jeremy Evans) wrote in #note-7:

I tested every signal from Signal.list on Windows 10, and all signals work in some fashion, assuming you send the signal to the current process. For Process.kill:

  • INT raises a standard Interrupt exception
  • ILL/SEGV simulates a crash and generates a backtrace (does not run ensure blocks)
  • ABRT/FPE/KILL exits immediately (does not run ensure blocks)
  • TERM exits immediately (runs ensure blocks)
  • EXIT doesn't work

However, EXIT works for Signal.trap. This code prints 1 and then 2:

Signal.trap('EXIT'){p 2}
begin
  Process.kill('TERM', $$)
ensure
  p 1
end

So all signals listed in Signal.list are valid in some context. The documentation for Signal itself states:

The list of available signal names and their interpretation is
system dependent.

So Ruby makes no guarantee that signal handling behavior will be consistent across systems.

Considering all this, I don't think the current behavior is a bug. If you think the behavior or documentation could be improved, please submit a pull request.

I'm glad that these things work for current process, and with such circumstances the current behavior can be left, but it's weird for me that the same doesn't work for other Ruby processes. I'm testing filewatcher-cli with Windows, and the original author wants Filewatcher to be cross-independent, but there is restart-signal option and I just can't test it properly on Windows. I've already changed the default value from TERM to KILL, already added a warning for any different value, but spawned test Ruby script should trap specific signal and save a file with it. And even if I want to trap the default value (KILL) — I can't, I should trap EXIT, but such signal doesn't stop process, and so on… terrible behavior for me. I understand that Windows is not primary platform for Ruby, but I wish improvements and consistency in this direction. I'm not an expert with process signals so I can't send a PR for this.

Actions

Also available in: Atom PDF