Skip to content
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

Add Signal#trap_handler? #14126

Merged
merged 10 commits into from
Jan 9, 2024
22 changes: 22 additions & 0 deletions spec/std/signal_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,35 @@ describe "Signal" do
sleep 0.1
end
ran.should be_true
ensure
Signal::USR1.reset
end

it "ignores a signal" do
Signal::USR2.ignore
Process.signal Signal::USR2, Process.pid
end

it "allows chaining of signals" do
ran_first = false
ran_second = false

Signal::USR1.trap { ran_first = true }
existing = Signal::USR1.trap_handler?

Signal::USR1.trap do |signal|
existing.try &.call(signal)
ran_second = true
end

Process.signal Signal::USR1, Process.pid
sleep 0.1
ran_first.should be_true
ran_second.should be_true
ensure
Signal::USR1.reset
end
stakach marked this conversation as resolved.
Show resolved Hide resolved

it "CHLD.reset sets default Crystal child handler" do
Signal::CHLD.reset
child = Process.new("true", shell: true)
Expand Down
3 changes: 3 additions & 0 deletions src/crystal/system/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ module Crystal::System::Signal
# Sets the handler for this signal to the passed function.
# def self.trap(signal, handler) : Nil

# Returns any existing handler set on the signal
# def self.trap_handler?(signal)

# Resets the handler for this signal to the OS default.
# def self.reset(signal) : Nil

Expand Down
6 changes: 5 additions & 1 deletion src/crystal/system/unix/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Crystal::System::Signal
@@pipe = IO.pipe(read_blocking: false, write_blocking: true)
@@handlers = {} of ::Signal => Handler
@@sigset = Sigset.new
class_setter child_handler : Handler?
class_property child_handler : Handler?
@@mutex = Mutex.new(:unchecked)

def self.trap(signal, handler) : Nil
Expand All @@ -30,6 +30,10 @@ module Crystal::System::Signal
end
end

def self.trap_handler?(signal)
@@mutex.synchronize { @@handlers[signal]? }
end

def self.reset(signal) : Nil
set(signal, LibC::SIG_DFL)
end
Expand Down
4 changes: 4 additions & 0 deletions src/crystal/system/wasi/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ module Crystal::System::Signal
raise NotImplementedError.new("Crystal::System::Signal.trap")
end

def self.trap_handler?(signal)
raise NotImplementedError.new("Crystal::System::Signal.trap_handler?")
end

def self.reset(signal) : Nil
raise NotImplementedError.new("Crystal::System::Signal.reset")
end
Expand Down
4 changes: 4 additions & 0 deletions src/crystal/system/win32/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ module Crystal::System::Signal
raise NotImplementedError.new("Crystal::System::Signal.trap")
end

def self.trap_handler?(signal)
raise NotImplementedError.new("Crystal::System::Signal.trap_handler?")
end

def self.reset(signal) : Nil
raise NotImplementedError.new("Crystal::System::Signal.reset")
end
Expand Down
18 changes: 18 additions & 0 deletions src/signal.cr
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,24 @@ enum Signal : Int32
Crystal::System::Signal.trap(self, handler)
end

# Returns any existing handler for this signal
#
# ```
# Signal::USR1.trap { }
# prev_handler = Signal::USR1.trap_handler?
#
# Signal::USR1.trap do |signal|
# prev_handler.try &.call(signal)
# # ...
# end
# ```
def trap_handler?
{% if @type.has_constant?("CHLD") %}
return Crystal::System::Signal.child_handler if self == CHLD
{% end %}
Crystal::System::Signal.trap_handler?(self)
stakach marked this conversation as resolved.
Show resolved Hide resolved
end

# Resets the handler for this signal to the OS default.
#
# Note that trying to reset `CHLD` will actually set the default crystal
Expand Down