system/excpt: let the OS handle termination on signal (#16712)
This commit is contained in:
parent
95664e1524
commit
ccc0667c29
4 changed files with 46 additions and 3 deletions
|
|
@ -159,6 +159,14 @@ provided by the operating system.
|
||||||
`ValueError` when the real command line is not available. `parseopt` was
|
`ValueError` when the real command line is not available. `parseopt` was
|
||||||
previously excluded from `prelude` for JS, as it could not be imported.
|
previously excluded from `prelude` for JS, as it could not be imported.
|
||||||
|
|
||||||
|
- On POSIX systems, the default signal handlers used for Nim programs (it's
|
||||||
|
used for printing the stacktrace on fatal signals) will now re-raise the
|
||||||
|
signal for the OS default handlers to handle.
|
||||||
|
|
||||||
|
This lets the OS perform its default actions, which might include core
|
||||||
|
dumping (on select signals) and notifying the parent process about the cause
|
||||||
|
of termination.
|
||||||
|
|
||||||
## Language changes
|
## Language changes
|
||||||
|
|
||||||
- `nimscript` now handles `except Exception as e`.
|
- `nimscript` now handles `except Exception as e`.
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ else:
|
||||||
C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>".} = object
|
C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>".} = object
|
||||||
|
|
||||||
|
|
||||||
|
type CSighandlerT = proc (a: cint) {.noconv.}
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
const
|
const
|
||||||
SIGABRT* = cint(22)
|
SIGABRT* = cint(22)
|
||||||
|
|
@ -48,6 +49,7 @@ when defined(windows):
|
||||||
SIGINT* = cint(2)
|
SIGINT* = cint(2)
|
||||||
SIGSEGV* = cint(11)
|
SIGSEGV* = cint(11)
|
||||||
SIGTERM = cint(15)
|
SIGTERM = cint(15)
|
||||||
|
SIG_DFL* = cast[CSighandlerT](0)
|
||||||
elif defined(macosx) or defined(linux) or defined(freebsd) or
|
elif defined(macosx) or defined(linux) or defined(freebsd) or
|
||||||
defined(openbsd) or defined(netbsd) or defined(solaris) or
|
defined(openbsd) or defined(netbsd) or defined(solaris) or
|
||||||
defined(dragonfly) or defined(nintendoswitch) or defined(genode) or
|
defined(dragonfly) or defined(nintendoswitch) or defined(genode) or
|
||||||
|
|
@ -60,6 +62,7 @@ elif defined(macosx) or defined(linux) or defined(freebsd) or
|
||||||
SIGSEGV* = cint(11)
|
SIGSEGV* = cint(11)
|
||||||
SIGTERM* = cint(15)
|
SIGTERM* = cint(15)
|
||||||
SIGPIPE* = cint(13)
|
SIGPIPE* = cint(13)
|
||||||
|
SIG_DFL* = cast[CSighandlerT](0)
|
||||||
elif defined(haiku):
|
elif defined(haiku):
|
||||||
const
|
const
|
||||||
SIGABRT* = cint(6)
|
SIGABRT* = cint(6)
|
||||||
|
|
@ -69,6 +72,7 @@ elif defined(haiku):
|
||||||
SIGSEGV* = cint(11)
|
SIGSEGV* = cint(11)
|
||||||
SIGTERM* = cint(15)
|
SIGTERM* = cint(15)
|
||||||
SIGPIPE* = cint(7)
|
SIGPIPE* = cint(7)
|
||||||
|
SIG_DFL* = cast[CSighandlerT](0)
|
||||||
else:
|
else:
|
||||||
when NoFakeVars:
|
when NoFakeVars:
|
||||||
{.error: "SIGABRT not ported to your platform".}
|
{.error: "SIGABRT not ported to your platform".}
|
||||||
|
|
@ -79,6 +83,7 @@ else:
|
||||||
SIGABRT* {.importc: "SIGABRT", nodecl.}: cint
|
SIGABRT* {.importc: "SIGABRT", nodecl.}: cint
|
||||||
SIGFPE* {.importc: "SIGFPE", nodecl.}: cint
|
SIGFPE* {.importc: "SIGFPE", nodecl.}: cint
|
||||||
SIGILL* {.importc: "SIGILL", nodecl.}: cint
|
SIGILL* {.importc: "SIGILL", nodecl.}: cint
|
||||||
|
SIG_DFL* {.importc: "SIG_DFL", nodecl.}: CSighandlerT
|
||||||
when defined(macosx) or defined(linux):
|
when defined(macosx) or defined(linux):
|
||||||
var SIGPIPE* {.importc: "SIGPIPE", nodecl.}: cint
|
var SIGPIPE* {.importc: "SIGPIPE", nodecl.}: cint
|
||||||
|
|
||||||
|
|
@ -105,9 +110,9 @@ else:
|
||||||
proc c_setjmp*(jmpb: C_JmpBuf): cint {.
|
proc c_setjmp*(jmpb: C_JmpBuf): cint {.
|
||||||
header: "<setjmp.h>", importc: "setjmp".}
|
header: "<setjmp.h>", importc: "setjmp".}
|
||||||
|
|
||||||
type CSighandlerT = proc (a: cint) {.noconv.}
|
proc c_signal*(sign: cint, handler: CSighandlerT): CSighandlerT {.
|
||||||
proc c_signal*(sign: cint, handler: proc (a: cint) {.noconv.}): CSighandlerT {.
|
|
||||||
importc: "signal", header: "<signal.h>", discardable.}
|
importc: "signal", header: "<signal.h>", discardable.}
|
||||||
|
proc c_raise*(sign: cint): cint {.importc: "raise", header: "<signal.h>".}
|
||||||
|
|
||||||
type
|
type
|
||||||
CFile {.importc: "FILE", header: "<stdio.h>",
|
CFile {.importc: "FILE", header: "<stdio.h>",
|
||||||
|
|
|
||||||
|
|
@ -643,7 +643,17 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
|
||||||
# unless there's a good reason to use cstring in signal handler to avoid
|
# unless there's a good reason to use cstring in signal handler to avoid
|
||||||
# using gc?
|
# using gc?
|
||||||
showErrorMessage(msg, msg.len)
|
showErrorMessage(msg, msg.len)
|
||||||
quit(1) # always quit when SIGABRT
|
|
||||||
|
when defined(posix):
|
||||||
|
# reset the signal handler to OS default
|
||||||
|
c_signal(sign, SIG_DFL)
|
||||||
|
|
||||||
|
# re-raise the signal, which will arrive once this handler exit.
|
||||||
|
# this lets the OS perform actions like core dumping and will
|
||||||
|
# also return the correct exit code to the shell.
|
||||||
|
discard c_raise(sign)
|
||||||
|
else:
|
||||||
|
quit(1)
|
||||||
|
|
||||||
proc registerSignalHandler() =
|
proc registerSignalHandler() =
|
||||||
c_signal(SIGINT, signalHandler)
|
c_signal(SIGINT, signalHandler)
|
||||||
|
|
|
||||||
20
tests/system/tsigexitcode.nim
Normal file
20
tests/system/tsigexitcode.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
discard """
|
||||||
|
joinable: false
|
||||||
|
disabled: windows
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os, osproc, posix, strutils
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
if paramCount() > 0:
|
||||||
|
let signal = cint parseInt paramStr(1)
|
||||||
|
discard posix.raise(signal)
|
||||||
|
else:
|
||||||
|
# synchronize this list with lib/system/except.nim:registerSignalHandler()
|
||||||
|
let fatalSigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS,
|
||||||
|
SIGPIPE]
|
||||||
|
for s in fatalSigs:
|
||||||
|
let (_, exitCode) = execCmdEx(quoteShellCommand [getAppFilename(), $s])
|
||||||
|
doAssert exitCode == 128 + s, "mismatched exit code for signal " & $s
|
||||||
|
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue