added system.onThreadCreation feature for safe thread local storage initializations
This commit is contained in:
parent
2f08fdf623
commit
61937974e2
3 changed files with 54 additions and 0 deletions
|
|
@ -307,6 +307,35 @@ type
|
||||||
## a pointer as a thread ID.
|
## a pointer as a thread ID.
|
||||||
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
|
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
|
||||||
|
|
||||||
|
var
|
||||||
|
threadCreationHandlers: array[60, proc () {.nimcall, gcsafe.}]
|
||||||
|
countThreadCreationHandlers: int
|
||||||
|
|
||||||
|
proc onThreadCreation*(handler: proc () {.nimcall, gcsafe.}) =
|
||||||
|
## Registers a global handler that is called at thread creation.
|
||||||
|
## 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)
|
||||||
|
##
|
||||||
|
## **Note**: The registration is currently not threadsafe! Better
|
||||||
|
## call ``onThreadCreation`` before any thread started its work!
|
||||||
|
threadCreationHandlers[countThreadCreationHandlers] = handler
|
||||||
|
inc countThreadCreationHandlers
|
||||||
|
|
||||||
|
template beforeThreadRuns() =
|
||||||
|
for i in 0..countThreadCreationHandlers-1:
|
||||||
|
threadCreationHandlers[i]()
|
||||||
|
|
||||||
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()
|
||||||
|
|
||||||
|
|
@ -321,6 +350,7 @@ 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()
|
||||||
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()
|
||||||
|
|
@ -329,6 +359,7 @@ 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()
|
||||||
when TArg is void:
|
when TArg is void:
|
||||||
thrd.dataFn()
|
thrd.dataFn()
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,7 @@ proc threadTests(r: var TResults, cat: Category, options: string) =
|
||||||
test "tthreadanalysis2"
|
test "tthreadanalysis2"
|
||||||
#test "tthreadanalysis3"
|
#test "tthreadanalysis3"
|
||||||
test "tthreadheapviolation1"
|
test "tthreadheapviolation1"
|
||||||
|
test "tonthreadcreation"
|
||||||
|
|
||||||
# ------------------------- IO tests ------------------------------------------
|
# ------------------------- IO tests ------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
22
tests/threads/tonthreadcreation.nim
Normal file
22
tests/threads/tonthreadcreation.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
discard """
|
||||||
|
output: '''some string here'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
var
|
||||||
|
someGlobal: string = "some string here"
|
||||||
|
perThread {.threadvar.}: string
|
||||||
|
|
||||||
|
proc setPerThread() =
|
||||||
|
{.gcsafe.}:
|
||||||
|
deepCopy(perThread, someGlobal)
|
||||||
|
|
||||||
|
proc foo() {.thread.} =
|
||||||
|
echo perThread
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
onThreadCreation setPerThread
|
||||||
|
var t: Thread[void]
|
||||||
|
createThread[void](t, foo)
|
||||||
|
t.joinThread()
|
||||||
|
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue