threadimpl.nim 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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 allocThreadStorage(size: int): pointer =
  22. result = c_malloc(csize_t size)
  23. zeroMem(result, size)
  24. proc deallocThreadStorage(p: pointer) = c_free(p)
  25. else:
  26. template allocThreadStorage(size: untyped): untyped = allocShared0(size)
  27. template deallocThreadStorage(p: pointer) = deallocShared(p)
  28. template afterThreadRuns() =
  29. for i in countdown(nimThreadDestructionHandlers.len-1, 0):
  30. nimThreadDestructionHandlers[i]()
  31. proc onThreadDestruction*(handler: proc () {.closure, gcsafe, raises: [].}) =
  32. ## Registers a *thread local* handler that is called at the thread's
  33. ## destruction.
  34. ##
  35. ## A thread is destructed when the `.thread` proc returns
  36. ## normally or when it raises an exception. Note that unhandled exceptions
  37. ## in a thread nevertheless cause the whole process to die.
  38. nimThreadDestructionHandlers.add handler
  39. when defined(boehmgc):
  40. type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
  41. proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer)
  42. {.importc: "GC_call_with_stack_base", boehmGC.}
  43. proc boehmGC_register_my_thread(sb: pointer)
  44. {.importc: "GC_register_my_thread", boehmGC.}
  45. proc boehmGC_unregister_my_thread()
  46. {.importc: "GC_unregister_my_thread", boehmGC.}
  47. proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv, raises: [].} =
  48. boehmGC_register_my_thread(sb)
  49. try:
  50. let thrd = cast[ptr Thread[TArg]](thrd)
  51. when TArg is void:
  52. thrd.dataFn()
  53. else:
  54. thrd.dataFn(thrd.data)
  55. except:
  56. threadTrouble()
  57. finally:
  58. afterThreadRuns()
  59. boehmGC_unregister_my_thread()
  60. else:
  61. proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) {.raises: [].} =
  62. try:
  63. when TArg is void:
  64. thrd.dataFn()
  65. else:
  66. when defined(nimV2):
  67. thrd.dataFn(thrd.data)
  68. else:
  69. var x: TArg
  70. deepCopy(x, thrd.data)
  71. thrd.dataFn(x)
  72. except:
  73. threadTrouble()
  74. finally:
  75. afterThreadRuns()
  76. when hasAllocStack:
  77. deallocThreadStorage(thrd.rawStack)
  78. proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) {.raises: [].} =
  79. when defined(boehmgc):
  80. boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd)
  81. elif not defined(nogc) and not defined(gogc) and not defined(gcRegions) and not usesDestructors:
  82. var p {.volatile.}: pointer
  83. # init the GC for refc/markandsweep
  84. nimGC_setStackBottom(addr(p))
  85. when declared(initGC):
  86. initGC()
  87. when declared(threadType):
  88. threadType = ThreadType.NimThread
  89. threadProcWrapDispatch[TArg](thrd)
  90. when declared(deallocOsPages): deallocOsPages()
  91. else:
  92. threadProcWrapDispatch(thrd)
  93. template nimThreadProcWrapperBody*(closure: untyped): untyped =
  94. var thrd = cast[ptr Thread[TArg]](closure)
  95. var core = thrd.core
  96. when declared(globalsSlot): threadVarSetValue(globalsSlot, thrd.core)
  97. threadProcWrapStackFrame(thrd)
  98. # Since an unhandled exception terminates the whole process (!), there is
  99. # no need for a ``try finally`` here, nor would it be correct: The current
  100. # exception is tried to be re-raised by the code-gen after the ``finally``!
  101. # However this is doomed to fail, because we already unmapped every heap
  102. # page!
  103. # mark as not running anymore:
  104. thrd.core = nil
  105. thrd.dataFn = nil
  106. deallocThreadStorage(cast[pointer](core))