Files
Nim/lib/std/exitprocs.nim
Tail Wag Games cfdac6666f Freeing critical sections via atexit in system/alloc and system/io (#19062)
* adding new system module sysexitprocs and including system exit procedures when registering exit handlers defined in userland

* fixing failing tests and adding initialization guard to handle cases where the module's global init logic isn't invoked first as is the case with some gc implementaions

* js backend shouldn't try to invoke actual system exit procs

* fixing formatting in sysexitprocs.nim

* 256 was too much - my max number of plugins in my engine is 64 and I require two hooks per runtime it looks like with tls emulation turned off, so for my purposes 128 should be sufficient

* so atExit should be enough here, can get rid of all the extra cruft I had added on top since I didn't realize atExit already provided a stack

* done being cute - since newruntime prevents correct cpp codegen for object variants apparently and breaks tests if I try to use std/exitprocs, ddSysExitProc is just going into both modules. Since system doesn't include system/io, polluting system with it doesn't make sense either... at least it is only importc'd when it is required in either module and we don't have to have any weird when defined(nimOwnedEnabled) with a comment explaining why
2021-10-29 13:42:44 +02:00

88 lines
2.1 KiB
Nim

#
#
# Nim's Runtime Library
# (c) Copyright 2020 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import locks
type
FunKind = enum kClosure, kNoconv # extend as needed
Fun = object
case kind: FunKind
of kClosure: fun1: proc () {.closure.}
of kNoconv: fun2: proc () {.noconv.}
var
gFunsLock: Lock
gFuns: seq[Fun]
initLock(gFunsLock)
when defined(js):
proc addAtExit(quitProc: proc() {.noconv.}) =
when defined(nodejs):
asm """
process.on('exit', `quitProc`);
"""
elif defined(js):
asm """
window.onbeforeunload = `quitProc`;
"""
else:
proc addAtExit(quitProc: proc() {.noconv.}) {.
importc: "atexit", header: "<stdlib.h>".}
proc callClosures() {.noconv.} =
withLock gFunsLock:
for i in countdown(gFuns.len-1, 0):
let fun = gFuns[i]
case fun.kind
of kClosure: fun.fun1()
of kNoconv: fun.fun2()
template fun() =
if gFuns.len == 0:
addAtExit(callClosures)
proc addExitProc*(cl: proc () {.closure.}) =
## Adds/registers a quit procedure. Each call to `addExitProc` registers
## another quit procedure. They are executed on a last-in, first-out basis.
# Support for `addExitProc` is done by Ansi C's facilities here.
# In case of an unhandled exception the exit handlers should
# not be called explicitly! The user may decide to do this manually though.
withLock gFunsLock:
fun()
gFuns.add Fun(kind: kClosure, fun1: cl)
proc addExitProc*(cl: proc() {.noconv.}) =
## overload for `noconv` procs.
withLock gFunsLock:
fun()
gFuns.add Fun(kind: kNoconv, fun2: cl)
when not defined(nimscript):
proc getProgramResult*(): int =
when defined(js) and defined(nodejs):
asm """
`result` = process.exitCode;
"""
elif not defined(js):
result = programResult
else:
doAssert false
proc setProgramResult*(a: int) =
# pending https://github.com/nim-lang/Nim/issues/14674
when defined(js) and defined(nodejs):
asm """
process.exitCode = `a`;
"""
elif not defined(js):
programResult = a
else:
doAssert false