summary refs log tree commit diff stats
path: root/lib/std/exitprocs.nim
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2020-06-16 02:43:48 -0700
committerGitHub <noreply@github.com>2020-06-16 11:43:48 +0200
commitdfe51d10a1f204d0c3ab1a8be1e109029cc54f9b (patch)
tree17eb11f3545d9f690329e02dadd7e015460838e6 /lib/std/exitprocs.nim
parent45cac4afda2272182ea1eb7572493d6c71e2da4e (diff)
downloadNim-dfe51d10a1f204d0c3ab1a8be1e109029cc54f9b.tar.gz
`addQuitProc` now works with closures, and c, js(node/browser) backend; fix some bugs in testament (#14342)
* make addQuitProc great again

* fix bugs in testament

* fix test

* change 2016 => 2020

* addQuitProc => addExitProc + locks

* move to std/exitprocs
Diffstat (limited to 'lib/std/exitprocs.nim')
-rw-r--r--lib/std/exitprocs.nim65
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim
new file mode 100644
index 000000000..b2811735c
--- /dev/null
+++ b/lib/std/exitprocs.nim
@@ -0,0 +1,65 @@
+#
+#
+#            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)