threadimpl.nim 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. var
  2. nimThreadDestructionHandlers* {.rtlThreadVar.}: seq[proc () {.closure, gcsafe, raises: [].}]
  3. when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions):
  4. proc deallocOsPages() {.rtl, raises: [].}
  5. proc threadTrouble() {.raises: [], gcsafe.}
  6. # create for the main thread. Note: do not insert this data into the list
  7. # of all threads; it's not to be stopped etc.
  8. when not defined(useNimRtl):
  9. #when not defined(createNimRtl): initStackBottom()
  10. when declared(initGC):
  11. initGC()
  12. when not emulatedThreadVars:
  13. type ThreadType {.pure.} = enum
  14. None = 0,
  15. NimThread = 1,
  16. ForeignThread = 2
  17. var
  18. threadType {.rtlThreadVar.}: ThreadType
  19. threadType = ThreadType.NimThread
  20. when defined(gcDestructors):
  21. proc deallocThreadStorage(p: pointer) = c_free(p)
  22. else:
  23. template deallocThreadStorage(p: pointer) = deallocShared(p)
  24. template afterThreadRuns() =
  25. for i in countdown(nimThreadDestructionHandlers.len-1, 0):
  26. nimThreadDestructionHandlers[i]()
  27. proc onThreadDestruction*(handler: proc () {.closure, gcsafe, raises: [].}) =
  28. ## Registers a *thread local* handler that is called at the thread's
  29. ## destruction.
  30. ##
  31. ## A thread is destructed when the `.thread` proc returns
  32. ## normally or when it raises an exception. Note that unhandled exceptions
  33. ## in a thread nevertheless cause the whole process to die.
  34. nimThreadDestructionHandlers.add handler
  35. when defined(boehmgc):
  36. type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
  37. proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer)
  38. {.importc: "GC_call_with_stack_base", boehmGC.}
  39. proc boehmGC_register_my_thread(sb: pointer)
  40. {.importc: "GC_register_my_thread", boehmGC.}
  41. proc boehmGC_unregister_my_thread()
  42. {.importc: "GC_unregister_my_thread", boehmGC.}
  43. proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv, raises: [].} =
  44. boehmGC_register_my_thread(sb)
  45. try:
  46. let thrd = cast[ptr Thread[TArg]](thrd)
  47. when TArg is void:
  48. thrd.dataFn()
  49. else:
  50. thrd.dataFn(thrd.data)
  51. except:
  52. threadTrouble()
  53. finally:
  54. afterThreadRuns()
  55. boehmGC_unregister_my_thread()
  56. else:
  57. proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) {.raises: [].} =
  58. try:
  59. when TArg is void:
  60. thrd.dataFn()
  61. else:
  62. when defined(nimV2):
  63. thrd.dataFn(thrd.data)
  64. else:
  65. var x: TArg
  66. deepCopy(x, thrd.data)
  67. thrd.dataFn(x)
  68. except:
  69. threadTrouble()
  70. finally:
  71. afterThreadRuns()
  72. when hasAllocStack:
  73. deallocThreadStorage(thrd.rawStack)
  74. proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) {.raises: [].} =
  75. when defined(boehmgc):
  76. boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd)
  77. elif not defined(nogc) and not defined(gogc) and not defined(gcRegions) and not usesDestructors:
  78. var p {.volatile.}: pointer
  79. # init the GC for refc/markandsweep
  80. nimGC_setStackBottom(addr(p))
  81. when declared(initGC):
  82. initGC()
  83. when declared(threadType):
  84. threadType = ThreadType.NimThread
  85. threadProcWrapDispatch[TArg](thrd)
  86. when declared(deallocOsPages): deallocOsPages()
  87. else:
  88. threadProcWrapDispatch(thrd)
  89. template nimThreadProcWrapperBody*(closure: untyped): untyped =
  90. var thrd = cast[ptr Thread[TArg]](closure)
  91. var core = thrd.core
  92. when declared(globalsSlot): threadVarSetValue(globalsSlot, thrd.core)
  93. threadProcWrapStackFrame(thrd)
  94. # Since an unhandled exception terminates the whole process (!), there is
  95. # no need for a ``try finally`` here, nor would it be correct: The current
  96. # exception is tried to be re-raised by the code-gen after the ``finally``!
  97. # However this is doomed to fail, because we already unmapped every heap
  98. # page!
  99. # mark as not running anymore:
  100. thrd.core = nil
  101. thrd.dataFn = nil
  102. deallocThreadStorage(cast[pointer](core))