diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2017-01-18 13:41:55 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-01-18 13:41:55 +0100 |
commit | 61937974e2a7fcf3ff6427510f793c4b580f1b62 (patch) | |
tree | 3cc11bc32a1bf760a9715d62b1640a66dd08c78b | |
parent | 2f08fdf6238baefca633ebbd2776ec366288e96d (diff) | |
download | Nim-61937974e2a7fcf3ff6427510f793c4b580f1b62.tar.gz |
added system.onThreadCreation feature for safe thread local storage initializations
-rw-r--r-- | lib/system/threads.nim | 31 | ||||
-rw-r--r-- | tests/testament/categories.nim | 1 | ||||
-rw-r--r-- | tests/threads/tonthreadcreation.nim | 22 |
3 files changed, 54 insertions, 0 deletions
diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 3f8387459..dea6fff1c 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -307,6 +307,35 @@ type ## a pointer as a thread ID. {.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): proc deallocOsPages() @@ -321,6 +350,7 @@ when defined(boehmgc): proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} = boehmGC_register_my_thread(sb) + beforeThreadRuns() let thrd = cast[ptr Thread[TArg]](thrd) when TArg is void: thrd.dataFn() @@ -329,6 +359,7 @@ when defined(boehmgc): boehmGC_unregister_my_thread() else: proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) = + beforeThreadRuns() when TArg is void: thrd.dataFn() else: diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index c1aebedfa..a7e0909c2 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -200,6 +200,7 @@ proc threadTests(r: var TResults, cat: Category, options: string) = test "tthreadanalysis2" #test "tthreadanalysis3" test "tthreadheapviolation1" + test "tonthreadcreation" # ------------------------- IO tests ------------------------------------------ diff --git a/tests/threads/tonthreadcreation.nim b/tests/threads/tonthreadcreation.nim new file mode 100644 index 000000000..c96e86d4d --- /dev/null +++ b/tests/threads/tonthreadcreation.nim @@ -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() |