exitprocs.nim 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2020 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module allows adding hooks to program exit.
  10. import std/locks
  11. when defined(js) and not defined(nodejs):
  12. import std/assertions
  13. type
  14. FunKind = enum kClosure, kNoconv # extend as needed
  15. Fun = object
  16. case kind: FunKind
  17. of kClosure: fun1: proc () {.closure.}
  18. of kNoconv: fun2: proc () {.noconv.}
  19. var
  20. gFunsLock: Lock
  21. gFuns {.cursor.}: seq[Fun] #Intentionally use the cursor to break up the lifetime trace and make it compatible with JS.
  22. initLock(gFunsLock)
  23. when defined(js):
  24. proc addAtExit(quitProc: proc() {.noconv.}) =
  25. when defined(nodejs):
  26. {.emit: """
  27. process.on('exit', `quitProc`);
  28. """.}
  29. elif defined(js):
  30. {.emit: """
  31. window.onbeforeunload = `quitProc`;
  32. """.}
  33. else:
  34. proc addAtExit(quitProc: proc() {.noconv.}) {.
  35. importc: "atexit", header: "<stdlib.h>".}
  36. proc callClosures() {.noconv.} =
  37. withLock gFunsLock:
  38. for i in countdown(gFuns.len-1, 0):
  39. let fun = gFuns[i]
  40. case fun.kind
  41. of kClosure: fun.fun1()
  42. of kNoconv: fun.fun2()
  43. gFuns.setLen(0)
  44. template fun() =
  45. if gFuns.len == 0:
  46. addAtExit(callClosures)
  47. proc addExitProc*(cl: proc () {.closure.}) =
  48. ## Adds/registers a quit procedure. Each call to `addExitProc` registers
  49. ## another quit procedure. They are executed on a last-in, first-out basis.
  50. # Support for `addExitProc` is done by Ansi C's facilities here.
  51. # In case of an unhandled exception the exit handlers should
  52. # not be called explicitly! The user may decide to do this manually though.
  53. withLock gFunsLock:
  54. fun()
  55. gFuns.add Fun(kind: kClosure, fun1: cl)
  56. proc addExitProc*(cl: proc() {.noconv.}) =
  57. ## overload for `noconv` procs.
  58. withLock gFunsLock:
  59. fun()
  60. gFuns.add Fun(kind: kNoconv, fun2: cl)
  61. when not defined(nimscript) and (not defined(js) or defined(nodejs)):
  62. proc getProgramResult*(): int =
  63. when defined(js) and defined(nodejs):
  64. {.emit: """
  65. `result` = process.exitCode;
  66. """.}
  67. else:
  68. result = programResult
  69. proc setProgramResult*(a: int) =
  70. when defined(js) and defined(nodejs):
  71. {.emit: """
  72. process.exitCode = `a`;
  73. """.}
  74. else:
  75. programResult = a