onThreadDestruction feature added to Nim's threading model

This commit is contained in:
Andreas Rumpf 2017-01-24 12:07:38 +01:00
commit eb96eaa5c2
2 changed files with 38 additions and 12 deletions

View file

@ -311,6 +311,9 @@ var
threadCreationHandlers: array[60, proc () {.nimcall, gcsafe.}] threadCreationHandlers: array[60, proc () {.nimcall, gcsafe.}]
countThreadCreationHandlers: int countThreadCreationHandlers: int
threadDestructionHandlers: array[60, proc () {.nimcall, gcsafe.}]
countThreadDestructionHandlers: int
proc onThreadCreation*(handler: proc () {.nimcall, gcsafe.}) = proc onThreadCreation*(handler: proc () {.nimcall, gcsafe.}) =
## Registers a global handler that is called at thread creation. ## Registers a global handler that is called at thread creation.
## This can be used to initialize thread local variables properly. ## This can be used to initialize thread local variables properly.
@ -334,10 +337,22 @@ proc onThreadCreation*(handler: proc () {.nimcall, gcsafe.}) =
threadCreationHandlers[countThreadCreationHandlers] = handler threadCreationHandlers[countThreadCreationHandlers] = handler
inc countThreadCreationHandlers inc countThreadCreationHandlers
proc onThreadDestruction*(handler: proc () {.nimcall, gcsafe.}) =
## Registers a global handler that is called at thread destruction.
## Threads are destructed when the ``.thread`` proc returns
## normally or raises an exception. Note that unhandled exceptions
## in a thread nevertheless cause the whole process to die.
threadDestructionHandlers[countThreadDestructionHandlers] = handler
inc countThreadDestructionHandlers
template beforeThreadRuns() = template beforeThreadRuns() =
for i in 0..countThreadCreationHandlers-1: for i in 0..countThreadCreationHandlers-1:
threadCreationHandlers[i]() threadCreationHandlers[i]()
template afterThreadRuns() =
for i in 0..countThreadDestructionHandlers-1:
threadDestructionHandlers[i]()
proc runOnThreadCreationHandlers*() = proc runOnThreadCreationHandlers*() =
## This runs every registered ``onThreadCreation`` handler and is usually ## This runs every registered ``onThreadCreation`` handler and is usually
## used to initialize thread local storage for the main thread. Since the ## used to initialize thread local storage for the main thread. Since the
@ -360,21 +375,27 @@ when defined(boehmgc):
proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} = proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} =
boehmGC_register_my_thread(sb) boehmGC_register_my_thread(sb)
beforeThreadRuns() beforeThreadRuns()
try:
let thrd = cast[ptr Thread[TArg]](thrd) let thrd = cast[ptr Thread[TArg]](thrd)
when TArg is void: when TArg is void:
thrd.dataFn() thrd.dataFn()
else: else:
thrd.dataFn(thrd.data) thrd.dataFn(thrd.data)
finally:
afterThreadRuns()
boehmGC_unregister_my_thread() boehmGC_unregister_my_thread()
else: else:
proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) = proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) =
beforeThreadRuns() beforeThreadRuns()
try:
when TArg is void: when TArg is void:
thrd.dataFn() thrd.dataFn()
else: else:
var x: TArg var x: TArg
deepCopy(x, thrd.data) deepCopy(x, thrd.data)
thrd.dataFn(x) thrd.dataFn(x)
finally:
afterThreadRuns()
proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) = proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
when defined(boehmgc): when defined(boehmgc):

View file

@ -1,5 +1,6 @@
discard """ discard """
output: '''some string here''' output: '''some string here
dying some string here'''
""" """
var var
@ -10,11 +11,15 @@ proc setPerThread() =
{.gcsafe.}: {.gcsafe.}:
deepCopy(perThread, someGlobal) deepCopy(perThread, someGlobal)
proc threadDied() {.gcsafe} =
echo "dying ", perThread
proc foo() {.thread.} = proc foo() {.thread.} =
echo perThread echo perThread
proc main = proc main =
onThreadCreation setPerThread onThreadCreation setPerThread
onThreadDestruction threadDied
var t: Thread[void] var t: Thread[void]
createThread[void](t, foo) createThread[void](t, foo)
t.joinThread() t.joinThread()