threaded alloc (#20492)

* allocator: catch up with multi-threading techniques
* removed the global thread lock
* more atomics for fun and profit
* added important sysAssert
* stats remain thread local and don't have to be atomic
* undo split chunk optimizations in the hope it makes the CI happy
This commit is contained in:
Andreas Rumpf 2022-10-09 11:44:02 +02:00 • committed by GitHub
commit fbc6975922
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 262 additions and 133 deletions

View file

@ -53,13 +53,23 @@ when defined(nimPreviewSlimSystem):
const
hasAllocStack = defined(zephyr) # maybe freertos too?
when defined(gcDestructors):
proc allocThreadStorage(size: int): pointer =
result = c_malloc(csize_t size)
zeroMem(result, size)
proc deallocThreadStorage(p: pointer) = c_free(p)
else:
template allocThreadStorage(size: untyped): untyped = allocShared0(size)
template deallocThreadStorage(p: pointer) = deallocShared(p)
when hasAllocStack or defined(zephyr) or defined(freertos):
const
nimThreadStackSize {.intdefine.} = 8192
nimThreadStackSize {.intdefine.} = 8192
nimThreadStackGuard {.intdefine.} = 128
StackGuardSize = nimThreadStackGuard
ThreadStackSize = nimThreadStackSize - nimThreadStackGuard
StackGuardSize = nimThreadStackGuard
ThreadStackSize = nimThreadStackSize - nimThreadStackGuard
else:
const
StackGuardSize = 4096
@ -176,7 +186,7 @@ else:
finally:
afterThreadRuns()
when hasAllocStack:
deallocShared(thrd.rawStack)
deallocThreadStorage(thrd.rawStack)
proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) {.raises: [].} =
when defined(boehmgc):
@ -207,7 +217,7 @@ template threadProcWrapperBody(closure: untyped): untyped =
# mark as not running anymore:
thrd.core = nil
thrd.dataFn = nil
deallocShared(cast[pointer](core))
deallocThreadStorage(cast[pointer](core))
{.push stack_trace:off.}
when defined(windows):
@ -278,7 +288,7 @@ when false:
t.dataFn = nil
## if thread `t` already exited, `t.core` will be `null`.
if not isNil(t.core):
deallocShared(t.core)
deallocThreadStorage(t.core)
t.core = nil
when hostOS == "windows":
@ -290,7 +300,7 @@ when hostOS == "windows":
## Entry point is the proc `tp`.
## `param` is passed to `tp`. `TArg` can be `void` if you
## don't need to pass any data to the thread.
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread)))
when TArg isnot void: t.data = param
t.dataFn = tp
@ -315,7 +325,7 @@ elif defined(genode):
proc createThread*[TArg](t: var Thread[TArg],
tp: proc (arg: TArg) {.thread, nimcall.},
param: TArg) =
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread)))
when TArg isnot void: t.data = param
t.dataFn = tp
@ -339,7 +349,7 @@ else:
## Entry point is the proc `tp`. `param` is passed to `tp`.
## `TArg` can be `void` if you
## don't need to pass any data to the thread.
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
t.core = cast[PGcThread](allocThreadStorage(sizeof(GcThread)))
when TArg isnot void: t.data = param
t.dataFn = tp
@ -348,7 +358,7 @@ else:
doAssert pthread_attr_init(a) == 0
when hasAllocStack:
var
rawstk = allocShared0(ThreadStackSize + StackGuardSize)
rawstk = allocThreadStorage(ThreadStackSize + StackGuardSize)
stk = cast[pointer](cast[uint](rawstk) + StackGuardSize)
let setstacksizeResult = pthread_attr_setstack(addr a, stk, ThreadStackSize)
t.rawStack = rawstk