-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows support for signal handling and dealing with IO #26
Changes from all commits
50a5bdf
1a98304
5bf96ee
a87ab06
78a8744
52f45e6
9030144
f84595f
45d0007
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,12 +19,21 @@ module ServerEngine | |
|
||
class MultiSpawnServer < MultiWorkerServer | ||
def initialize(worker_module, load_config_proc={}, &block) | ||
@pm = ProcessManager.new( | ||
auto_tick: false, | ||
graceful_kill_signal: Daemon::Signals::GRACEFUL_STOP, | ||
immediate_kill_signal: Daemon::Signals::IMMEDIATE_STOP, | ||
enable_heartbeat: false, | ||
) | ||
if ServerEngine.windows? | ||
@pm = ProcessManager.new( | ||
auto_tick: false, | ||
graceful_kill_signal: Daemon::Signals::GRACEFUL_STOP, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
immediate_kill_signal: false, | ||
enable_heartbeat: false, | ||
) | ||
else | ||
@pm = ProcessManager.new( | ||
auto_tick: false, | ||
graceful_kill_signal: Daemon::Signals::GRACEFUL_STOP, | ||
immediate_kill_signal: Daemon::Signals::IMMEDIATE_STOP, | ||
enable_heartbeat: false, | ||
) | ||
end | ||
|
||
super(worker_module, load_config_proc, &block) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,9 @@ | |
module ServerEngine | ||
|
||
require 'fcntl' | ||
if ServerEngine.windows? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please add |
||
require 'win32/pipe' | ||
end | ||
|
||
class ProcessManager | ||
def initialize(config={}) | ||
|
@@ -146,9 +149,18 @@ def spawn(*args) | |
rpipe, wpipe = new_pipe_pair | ||
|
||
begin | ||
options[[wpipe.fileno]] = wpipe | ||
if @enable_heartbeat | ||
env['SERVERENGINE_HEARTBEAT_PIPE'] = wpipe.fileno.to_s | ||
|
||
if ServerEngine.windows? | ||
pipe_name = "SERVERENGINE_HEARTBEAT_PIPE_%016X" % Random.new.rand(2**128) | ||
rpipe = Win32::Pipe::Server.new(pipe_name, 0, Win32::Pipe::ACCESS_DUPLEX | Win32::Pipe::FILE_FLAG_OVERLAPPED) | ||
if @enable_heartbeat | ||
env['SERVERENGINE_HEARTBEAT_PIPE'] = pipe_name | ||
end | ||
else | ||
options[[wpipe.fileno]] = wpipe | ||
if @enable_heartbeat | ||
env['SERVERENGINE_HEARTBEAT_PIPE'] = wpipe.fileno.to_s | ||
end | ||
end | ||
|
||
pid = Process.spawn(env, *args, options) | ||
|
@@ -204,14 +216,26 @@ def tick(blocking_timeout=0) | |
return nil | ||
end | ||
|
||
ready_pipes, _, _ = IO.select(@rpipes.keys, nil, nil, blocking_timeout) | ||
if ServerEngine.windows? | ||
# TODO: should use WaitForMultipleObjects? | ||
ready_pipes = @rpipes.keys | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because of semantic differences of pipes, this code could be tricky:
An idea is, as you mention here in the comment, using WaitForMultipleObjects to wait for both pipe and exits of child processes. |
||
else | ||
ready_pipes, _, _ = IO.select(@rpipes.keys, nil, nil, blocking_timeout) | ||
end | ||
|
||
time ||= Time.now | ||
|
||
if ready_pipes | ||
ready_pipes.each do |r| | ||
begin | ||
r.read_nonblock(1024, @read_buffer) | ||
if ServerEngine.windows? | ||
read_flag = r.read | ||
if read_flag | ||
@read_buffer = r.buffer | ||
end | ||
else | ||
r.read_nonblock(1024, @read_buffer) | ||
end | ||
rescue Errno::EAGAIN, Errno::EINTR | ||
next | ||
rescue #EOFError | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,12 +66,14 @@ def install_signal_handlers | |
s = self | ||
SignalThread.new do |st| | ||
st.trap(Daemon::Signals::GRACEFUL_STOP) { s.stop(true) } | ||
st.trap(Daemon::Signals::IMMEDIATE_STOP) { s.stop(false) } | ||
st.trap(Daemon::Signals::GRACEFUL_RESTART) { s.restart(true) } | ||
st.trap(Daemon::Signals::IMMEDIATE_RESTART) { s.restart(false) } | ||
st.trap(Daemon::Signals::RELOAD) { s.reload } | ||
st.trap(Daemon::Signals::DETACH) { s.stop(true) } | ||
st.trap(Daemon::Signals::DUMP) { Sigdump.dump } | ||
unless ServerEngine.windows? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, then let's add comments here:
|
||
st.trap(Daemon::Signals::IMMEDIATE_STOP) { s.stop(false) } | ||
st.trap(Daemon::Signals::GRACEFUL_RESTART) { s.restart(true) } | ||
st.trap(Daemon::Signals::IMMEDIATE_RESTART) { s.restart(false) } | ||
st.trap(Daemon::Signals::RELOAD) { s.reload } | ||
st.trap(Daemon::Signals::DUMP) { Sigdump.dump } | ||
end | ||
end | ||
end | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that QUIT signal doesn't work on Windows. Does KILL signal work on Windows?
If not,
ProcessManager#tick
needs a hack likesystem("taskkill /f /pid #{pid}")
when it sends KILL signal like:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or TerminateProcess win32 API.