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 Process.on_terminate #13694

Merged
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e153e8e
pass details on interrupt
stakach Jul 22, 2023
2ad9331
fix win32 handler def
stakach Jul 22, 2023
006ce08
update public interface
stakach Jul 22, 2023
4ef574f
fix windows build
stakach Jul 23, 2023
0fa95aa
add missed windows constants
stakach Jul 23, 2023
7f54152
Merge branch 'master' into improve-process-on_interrupt
stakach Aug 18, 2023
cbd80e9
Merge branch 'master' into improve-process-on_interrupt
stakach Aug 19, 2023
78c27f1
Merge branch 'master' into improve-process-on_interrupt
stakach Aug 22, 2023
1ed9f63
Merge branch 'master' into improve-process-on_interrupt
stakach Sep 13, 2023
f9a6263
Merge branch 'master' into improve-process-on_interrupt
stakach Sep 17, 2023
2044e94
use Process::ExitReason enum
stakach Sep 18, 2023
360a3b5
remove alias
stakach Sep 18, 2023
2533fad
fix windows class vars
stakach Sep 19, 2023
6d94721
Merge branch 'master' into improve-process-on_interrupt
stakach Sep 22, 2023
0604bd2
Merge branch 'master' into improve-process-on_interrupt
stakach Nov 2, 2023
8e43767
Merge branch 'master' into improve-process-on_interrupt
stakach Nov 13, 2023
ee8f672
Merge branch 'master' into improve-process-on_interrupt
stakach Nov 16, 2023
0ea6ecb
win32 backwards compat
stakach Nov 16, 2023
118baff
remove type requirements
stakach Nov 16, 2023
793f0a6
fix wasi compatibility
stakach Nov 16, 2023
5765c73
unix with compatibility
stakach Nov 16, 2023
2352065
fix compilation
stakach Nov 16, 2023
33c9ac6
improve readability of win32 proc type
stakach Nov 16, 2023
0a11eb5
Update src/process.cr
stakach Nov 16, 2023
bdc8541
Update src/process/status.cr
stakach Nov 16, 2023
a2bc368
Update src/process/status.cr
stakach Nov 16, 2023
6bcf166
fix win32 compilation
stakach Nov 16, 2023
d497f08
minor performance improvement
stakach Nov 16, 2023
721444e
Merge branch 'master' into improve-process-on_interrupt
stakach Dec 1, 2023
38c8b51
Merge branch 'master' into improve-process-on_interrupt
stakach Dec 20, 2023
f81bb9b
Merge branch 'master' into improve-process-on_interrupt
stakach Dec 23, 2023
56115e0
Merge branch 'master' into improve-process-on_interrupt
stakach Jan 10, 2024
22a9b34
Merge branch 'master' into improve-process-on_interrupt
stakach Jan 22, 2024
78e8047
deprecate on_interrupt and use on_terminate
stakach Jan 23, 2024
d70ee33
fix call to on_terminate
stakach Jan 23, 2024
f460d5c
fix win32
stakach Jan 23, 2024
a740d4a
improve win32 on_terminate
stakach Jan 23, 2024
757079b
update docs
stakach Jan 23, 2024
79cbc17
change wording in description
stakach Jan 24, 2024
bc66bdb
add example code
stakach Jan 24, 2024
2b91b7d
crystal tool format
stakach Jan 24, 2024
fc279c4
Merge branch 'master' into improve-process-on_interrupt
stakach Jan 30, 2024
79c848d
Merge branch 'master' into improve-process-on_interrupt
stakach Jan 30, 2024
35471c9
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 2, 2024
962d654
fix comments and specs for new enum values
stakach Feb 3, 2024
3ceb646
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 4, 2024
8972255
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 6, 2024
539b998
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 8, 2024
0319fc3
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 9, 2024
66b4ce0
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 12, 2024
f4a3374
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 26, 2024
bfdef38
Merge branch 'master' into improve-process-on_interrupt
stakach Feb 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/crystal/system/process.cr
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct Crystal::System::Process

# Installs *handler* as the new handler for interrupt requests. Removes any
# previously set interrupt handler.
# def self.on_interrupt(&handler : ->)
# def self.on_interrupt(&handler : ::Process::ExitReason ->)
stakach marked this conversation as resolved.
Show resolved Hide resolved

# Ignores all interrupt requests. Removes any custom interrupt handler set
# def self.ignore_interrupts!
Expand Down
30 changes: 28 additions & 2 deletions src/crystal/system/unix/process.cr
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,34 @@ struct Crystal::System::Process
raise RuntimeError.from_errno("kill") if ret < 0
end

def self.on_interrupt(&handler : ->) : Nil
::Signal::INT.trap { |_signal| handler.call }
def self.on_interrupt(&handler) : Nil
sig_handler = Proc(::Signal, Nil).new do |signal|
int_type = case signal
when .int?
::Process::ExitReason::Interrupted
when .hup?
::Process::ExitReason::TerminalDisconnected
when .term?
::Process::ExitReason::SessionEnded
else
::Process::ExitReason::Interrupted
end
stakach marked this conversation as resolved.
Show resolved Hide resolved

# maintain backwards compatibility
stakach marked this conversation as resolved.
Show resolved Hide resolved
if handler.is_a? Proc(Nil)
handler.call
else
handler.call int_type
end

# ignore prevents system defaults and clears registered interrupts
# hence we need to re-register
signal.ignore
Process.on_interrupt &handler
end
::Signal::INT.trap &sig_handler
::Signal::HUP.trap &sig_handler
::Signal::TERM.trap &sig_handler
end

def self.ignore_interrupts! : Nil
Expand Down
2 changes: 1 addition & 1 deletion src/crystal/system/wasi/process.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct Crystal::System::Process
raise NotImplementedError.new("Process.signal")
end

def self.on_interrupt(&handler : ->) : Nil
def self.on_interrupt(&handler) : Nil
raise NotImplementedError.new("Process.on_interrupt")
end

Expand Down
24 changes: 20 additions & 4 deletions src/crystal/system/win32/process.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
@job_object : LibC::HANDLE
@completion_key = IO::Overlapped::CompletionKey.new

@@interrupt_handler : Proc(Nil)?
@@interrupt_handler : Proc(::Process::ExitReason, Nil) | Proc(Nil)?
@@interrupt_count = Crystal::AtomicSemaphore.new
@@win32_interrupt_handler : LibC::PHANDLER_ROUTINE?
@@setup_interrupt_handler = Atomic::Flag.new
@@last_interrupt = ::Process::ExitReason::Interrupted

def initialize(process_info)
@pid = process_info.dwProcessId
Expand Down Expand Up @@ -150,10 +151,19 @@
raise NotImplementedError.new("Process.signal")
end

def self.on_interrupt(&@@interrupt_handler : ->) : Nil
def self.on_interrupt(&@@interrupt_handler) : Nil
restore_interrupts!
@@win32_interrupt_handler = handler = LibC::PHANDLER_ROUTINE.new do |event_type|
next 0 unless event_type.in?(LibC::CTRL_C_EVENT, LibC::CTRL_BREAK_EVENT)
@@last_interrupt = case event_type
when LibC::CTRL_C_EVENT, LibC::CTRL_BREAK_EVENT
::Process::ExitReason::Interrupted
when LibC::CTRL_CLOSE_EVENT
::Process::ExitReason::TerminalDisconnected
when LibC::CTRL_LOGOFF_EVENT, LibC::CTRL_SHUTDOWN_EVENT
::Process::ExitReason::SessionEnded
else
next 0
end
@@interrupt_count.signal
1
end
Expand Down Expand Up @@ -186,8 +196,14 @@

if handler = @@interrupt_handler
non_nil_handler = handler # if handler is closured it will also have the Nil type
int_type = @@last_interrupt
spawn do
non_nil_handler.call
case non_nil_handler
in Proc(Nil)
non_nil_handler.call

Check failure on line 203 in src/crystal/system/win32/process.cr

View workflow job for this annotation

GitHub Actions / x86_64-windows / build

no overload matches 'Proc(Process::ExitReason, Nil)#call'
in Proc(::Process::ExitReason, Nil)
non_nil_handler.call int_type
end
rescue ex
ex.inspect_with_backtrace(STDERR)
STDERR.puts("FATAL: uncaught exception while processing interrupt handler, exiting")
Expand Down
7 changes: 5 additions & 2 deletions src/lib_c/x86_64-windows-msvc/c/consoleapi.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ lib LibC
fun GetConsoleCP : DWORD
fun GetConsoleOutputCP : DWORD

CTRL_C_EVENT = 0
CTRL_BREAK_EVENT = 1
CTRL_C_EVENT = 0
CTRL_BREAK_EVENT = 1
CTRL_CLOSE_EVENT = 2
CTRL_LOGOFF_EVENT = 5
CTRL_SHUTDOWN_EVENT = 6

alias PHANDLER_ROUTINE = DWORD -> BOOL

Expand Down
9 changes: 5 additions & 4 deletions src/process.cr
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ class Process
#
# The handler is executed on a fresh fiber every time an interrupt occurs.
#
# * On Unix-like systems, this traps `SIGINT`.
# * On Windows, this captures <kbd>Ctrl</kbd> + <kbd>C</kbd> and
# <kbd>Ctrl</kbd> + <kbd>Break</kbd> signals sent to a console application.
def self.on_interrupt(&handler : ->) : Nil
# * On Unix-like systems, this traps `SIGINT`, `SIGHUP`, `SIGTERM`.
# * On Windows, this captures <kbd>Ctrl</kbd> + <kbd>C</kbd>,
# <kbd>Ctrl</kbd> + <kbd>Break</kbd>, terminal close, windows logoff
# and shutdown signals sent to a console application.
stakach marked this conversation as resolved.
Show resolved Hide resolved
stakach marked this conversation as resolved.
Show resolved Hide resolved
def self.on_interrupt(&handler) : Nil
Crystal::System::Process.on_interrupt(&handler)
end

Expand Down
12 changes: 12 additions & 0 deletions src/process/status.cr
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ enum Process::ExitReason
# A `Process::Status` that maps to `Unknown` may map to a different value if
# new enum members are added to `ExitReason`.
Unknown

# The process exited due to the user closing the terminal window or ending an ssh session.
#
# * On Unix-like systems, this corresponds to `Signal::HUP`
# * On Windows, this corresponds to the `CTRL_CLOSE_EVENT` message
stakach marked this conversation as resolved.
Show resolved Hide resolved
TerminalDisconnected

# The process exited due to the user logging off or shutting down the OS.
#
# * On Unix-like systems, this corresponds to `Signal::TERM`
# * On Windows, this corresponds to the `CTRL_LOGOFF_EVENT`, `CTRL_SHUTDOWN_EVENT` messages
stakach marked this conversation as resolved.
Show resolved Hide resolved
SessionEnded
end

# The status of a terminated process. Returned by `Process#wait`.
Expand Down