diff --git a/lib/std/private/threadtypes.nim b/lib/std/private/threadtypes.nim index a1cdf21dc0f7..f68a939bb661 100644 --- a/lib/std/private/threadtypes.nim +++ b/lib/std/private/threadtypes.nim @@ -1,4 +1,5 @@ include system/inclrtl +import std/atomics const hasSharedHeap* = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own @@ -166,9 +167,9 @@ type core*: PGcThread sys*: SysThread when TArg is void: - dataFn*: proc () {.nimcall, gcsafe.} + dataFn*: Atomic[proc () {.nimcall, gcsafe.}] else: - dataFn*: proc (m: TArg) {.nimcall, gcsafe.} + dataFn*: Atomic[proc (m: TArg) {.nimcall, gcsafe.}] data*: TArg when hasAllocStack: rawStack*: pointer diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim index 494baa8abf9f..51cf82374ffb 100644 --- a/lib/std/typedthreads.nim +++ b/lib/std/typedthreads.nim @@ -78,6 +78,7 @@ deinitLock(l) import std/private/[threadtypes] export Thread +import std/atomics import system/ansi_c @@ -149,9 +150,10 @@ else: nimThreadProcWrapperBody(closure) {.pop.} -proc running*[TArg](t: Thread[TArg]): bool {.inline.} = +proc running*[TArg](t: var Thread[TArg]): bool {.inline.} = ## Returns true if `t` is running. - result = t.dataFn != nil + let dataFn = t.dataFn.load() + result = dataFn != nil proc handle*[TArg](t: Thread[TArg]): SysThread {.inline.} = ## Returns the thread handle of `t`. @@ -202,7 +204,7 @@ when false: else: discard pthread_cancel(t.sys) when declared(registerThread): unregisterThread(addr(t)) - t.dataFn = nil + t.dataFn.store nil ## if thread `t` already exited, `t.core` will be `null`. if not isNil(t.core): deallocThreadStorage(t.core) @@ -220,7 +222,7 @@ when hostOS == "windows": t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread))) when TArg isnot void: t.data = param - t.dataFn = tp + t.dataFn.store tp when hasSharedHeap: t.core.stackSize = ThreadStackSize var dummyThreadId: int32 = 0'i32 t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg], @@ -245,7 +247,7 @@ elif defined(genode): t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread))) when TArg isnot void: t.data = param - t.dataFn = tp + t.dataFn.store(tp) when hasSharedHeap: t.stackSize = ThreadStackSize t.sys.initThread( runtimeEnv, @@ -269,7 +271,7 @@ else: t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread))) when TArg isnot void: t.data = param - t.dataFn = tp + t.dataFn.store(tp) when hasSharedHeap: t.core.stackSize = ThreadStackSize var a {.noinit.}: Pthread_attr doAssert pthread_attr_init(a) == 0 diff --git a/lib/system/threadimpl.nim b/lib/system/threadimpl.nim index 093a920a1d53..95fb70f27b39 100644 --- a/lib/system/threadimpl.nim +++ b/lib/system/threadimpl.nim @@ -1,3 +1,5 @@ +import std/atomics + var nimThreadDestructionHandlers* {.rtlThreadVar.}: seq[proc () {.closure, gcsafe, raises: [].}] when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions): @@ -50,10 +52,11 @@ when defined(boehmgc): boehmGC_register_my_thread(sb) try: let thrd = cast[ptr Thread[TArg]](thrd) + let dataFn = thrd.dataFn.load() when TArg is void: - thrd.dataFn() + dataFn() else: - thrd.dataFn(thrd.data) + dataFn(thrd.data) except: threadTrouble() finally: @@ -62,15 +65,16 @@ when defined(boehmgc): else: proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) {.raises: [].} = try: + let dataFn = thrd.dataFn.load() when TArg is void: - thrd.dataFn() + dataFn() else: when defined(nimV2): - thrd.dataFn(thrd.data) + dataFn(thrd.data) else: var x: TArg = default(TArg) deepCopy(x, thrd.data) - thrd.dataFn(x) + dataFn(x) except: threadTrouble() finally: @@ -107,5 +111,5 @@ template nimThreadProcWrapperBody*(closure: untyped): untyped = # mark as not running anymore: thrd.core = nil - thrd.dataFn = nil + thrd.dataFn.store(nil) deallocThreadStorage(cast[pointer](core))