Windows initiated ruby ​​process dies when shell terminates

I am trying to start a Ruby process on Windows using something like this:

p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"], :new_pgroup => true) 

Then I also disconnect from the process via:

 p1.detach 

This should, as I understand it, create a new process that is independent of the parent. I even use the new_pgroup parameter to make sure that the new process gets its own process group.

When I execute my script, the subprocess starts and continues to work. The execution of the subprocess spawning script also ends. However, when I close the shell, the subprocess dies. I expect it to continue working (it works on OS X and Linux). I can't figure out if this is a bug in Ruby runtime on Windows or is this a limitation of Windows and how it processes processes.

For completeness, the full Ruby code of what I'm trying to do:


spawner.rb : can be done through ruby spawner.rb and just spawns a new subprocess. The process creates loop.rb, which is just an endless loop. Depending on the OS, it sets another parameter for creating a group of processes.

 require "tempfile" require 'rbconfig' class SpawnTest def self.spawn_process if os == :windows p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"], :new_pgroup => true) else p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"], :pgroup => true) end # Detach from the processes so they will keep running puts p1 Process.detach(p1) end def self.os @os ||= ( host_os = RbConfig::CONFIG['host_os'] case host_os when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ :windows when /darwin|mac os/ :macosx when /linux/ :linux when /solaris|bsd/ :unix else raise Error::WebDriverError, "unknown os: #{host_os.inspect}" end ) end end if __FILE__ == $0 SpawnTest.spawn_process end 

loop.rb

 $stdout.sync = true $stderr.sync = true i = 0 while i < 10000 $stdout.puts "Iteration #{i}" sleep 1 i = i + 1 end $stdout.puts "Bye from #{Process.pid}" 

I found a win32-process gem during my research. It seems to use win32 API calls for appearance processes. Does anyone know if this library will fix this problem?

Any help was appreciated.

+6
source share
1 answer

I could not find any process groups in Windows, except sending CTRL events to several processes, since it is listed in the Process creation flags MSDN documents :

Process groups are used by the GenerateConsoleCtrlEvent function to enable the sending of a CTRL + BREAK signal to a console process group.

What actually happens when the CREATE_NEW_PROCESS_GROUP flag is CREATE_NEW_PROCESS_GROUP is ...

... an implicit call to SetConsoleCtrlHandler (NULL, TRUE) is performed on behalf of the new process; this means that CTRL + C is disabled in the new process. This allows shells to handle CTRL + C on their own and selectively pass this signal to subprocesses. CTRL + BREAK is not disabled and can be used to interrupt a process / process group.

From the CreateProcess MSDN docs .

Note that this is not the same as closing the console window using the x button. In the latter case, the process receives CTRL_CLOSE_EVENT ,

The signal that the system sends all processes connected to the console when the user closes the console (either by clicking the "Close" button in the window window of the console window, or by clicking the "Task of the final task" button in the task manager).

From HandlerRoutine MSDN Document Callback .

The handling of this event is independent of SetConsoleCtrlHandler(NULL,TRUE) set by the CREATE_NEW_PROCESS_GROUP flag when creating the process.

All of the above means that the CREATE_NEW_PROCESS_GROUP flag has nothing to do with the behavior you observe.

By default, the child process inherits the parent console window and IO descriptors. Therefore, when you close the shell by pressing the x button, it receives CTRL_CLOSE_EVENT and has no way to stop.

To avoid this, the child process should not be attached to the parent console. This is done by delivering the DETACHED_PROCESS flag to the CreateProcess Windows API.

By default, the console process inherits the parent console ... Console processes are not connected to the console if they are created using CreateProcess with DETACHED_PROCESS.

From creating console MSDN documents .

Here is what I believe Ruby spawn and win32-process gem do differently. I am not trying to debug both to see the specific difference in the flags that they set on CreateProcess , although that would be interesting to do.

There are other ways to create a child process without inheriting consoles or parent I / O descriptors. Examples are the flags CREATE_NO_WINDOW or CREATE_NEW_CONSOLE , Work Objects , etc.

+2
source

All Articles