removed onThreadCreation; onThreadDestruction is now thread local

This commit is contained in:
Araq 2017-02-26 20:42:19 +01:00
commit 4f062c3be0
3 changed files with 14 additions and 57 deletions

View file

@ -62,8 +62,6 @@ be used:
{.gcsafe.}: {.gcsafe.}:
deepCopy(perThread, someGlobal) deepCopy(perThread, someGlobal)
onThreadCreation(setPerThread)
Future directions: Future directions:

View file

@ -355,58 +355,22 @@ type
{.deprecated: [TThread: Thread, TThreadId: ThreadId].} {.deprecated: [TThread: Thread, TThreadId: ThreadId].}
var var
threadCreationHandlers: array[60, proc () {.nimcall, gcsafe.}] threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe.}]
countThreadCreationHandlers: int
threadDestructionHandlers: array[60, proc () {.nimcall, gcsafe.}] proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) =
countThreadDestructionHandlers: int ## Registers a *thread local* handler that is called at the thread's
## destruction.
proc onThreadCreation*(handler: proc () {.nimcall, gcsafe.}) = ## A thread is destructed when the ``.thread`` proc returns
## Registers a global handler that is called at thread creation. ## normally or when it raises an exception. Note that unhandled exceptions
## This can be used to initialize thread local variables properly.
## Note that the handler has to be .gcafe and so the typical usage
## looks like:
##
## .. code-block:: nim
##
## var
## someGlobal: string = "some string here"
## perThread {.threadvar.}: string
##
## proc setPerThread() =
## {.gcsafe.}:
## deepCopy(perThread, someGlobal)
##
## onThreadCreation(setPerThread)
##
## **Note**: The registration is currently not threadsafe! Better
## call ``onThreadCreation`` before any thread started its work!
threadCreationHandlers[countThreadCreationHandlers] = handler
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. ## in a thread nevertheless cause the whole process to die.
threadDestructionHandlers[countThreadDestructionHandlers] = handler if threadDestructionHandlers.isNil:
inc countThreadDestructionHandlers threadDestructionHandlers = @[]
threadDestructionHandlers.add handler
template beforeThreadRuns() =
for i in 0..countThreadCreationHandlers-1:
threadCreationHandlers[i]()
template afterThreadRuns() = template afterThreadRuns() =
for i in countdown(countThreadDestructionHandlers-1, 0): for i in countdown(threadDestructionHandlers.len-1, 0):
threadDestructionHandlers[i]() threadDestructionHandlers[i]()
proc runOnThreadCreationHandlers*() =
## This runs every registered ``onThreadCreation`` handler and is usually
## used to initialize thread local storage for the main thread. Since the
## main thread is **not** created via ``createThread`` it doesn't run the
## handlers automatically.
beforeThreadRuns()
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcstack): when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcstack):
proc deallocOsPages() proc deallocOsPages()
@ -421,7 +385,6 @@ 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()
try: try:
let thrd = cast[ptr Thread[TArg]](thrd) let thrd = cast[ptr Thread[TArg]](thrd)
when TArg is void: when TArg is void:
@ -433,7 +396,6 @@ when defined(boehmgc):
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()
try: try:
when TArg is void: when TArg is void:
thrd.dataFn() thrd.dataFn()

View file

@ -7,19 +7,16 @@ var
someGlobal: string = "some string here" someGlobal: string = "some string here"
perThread {.threadvar.}: string perThread {.threadvar.}: string
proc setPerThread() = proc threadDied() {.gcsafe.} =
{.gcsafe.}:
deepCopy(perThread, someGlobal)
proc threadDied() {.gcsafe} =
echo "dying ", perThread echo "dying ", perThread
proc foo() {.thread.} = proc foo() {.thread.} =
onThreadDestruction threadDied
{.gcsafe.}:
deepCopy(perThread, someGlobal)
echo perThread echo perThread
proc main = proc main =
onThreadCreation setPerThread
onThreadDestruction threadDied
var t: Thread[void] var t: Thread[void]
createThread[void](t, foo) createThread[void](t, foo)
t.joinThread() t.joinThread()