Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

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)
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