mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-21 00:40:16 +00:00
fix(library): block first-time callers until NimMain completes
initializeLibrary ran NimMain only on the thread that won `initialized.exchange(true)`; concurrent first-time callers fell straight through and used a half-initialized Nim runtime — a heap-corrupting race when multiple foreign (e.g. Go) threads create the first context at once. Add an `initDone` flag the winner sets after NimMain; the others spin until it is set before proceeding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
342fefa623
commit
e22b887d7c
@ -53,10 +53,13 @@ macro declareLibraryBase*(libraryName: static[string]): untyped =
|
||||
)
|
||||
res.add(procDef)
|
||||
|
||||
# Create: var initialized: Atomic[bool]
|
||||
# Create: var initialized, initDone: Atomic[bool]
|
||||
# `initialized` elects the single thread that runs NimMain; `initDone` signals
|
||||
# that NimMain has finished so concurrent first-time callers can safely proceed.
|
||||
let atomicType = nnkBracketExpr.newTree(ident("Atomic"), ident("bool"))
|
||||
let varStmt = nnkVarSection.newTree(
|
||||
nnkIdentDefs.newTree(ident("initialized"), atomicType, newEmptyNode())
|
||||
nnkIdentDefs.newTree(ident("initialized"), atomicType, newEmptyNode()),
|
||||
nnkIdentDefs.newTree(ident("initDone"), atomicType, newEmptyNode()),
|
||||
)
|
||||
res.add(varStmt)
|
||||
|
||||
@ -80,6 +83,13 @@ macro declareLibraryBase*(libraryName: static[string]): untyped =
|
||||
## Being `<yourprefix>` the value given in the optional
|
||||
## compilation flag --nimMainPrefix:yourprefix
|
||||
`nimMainName`()
|
||||
initDone.store(true)
|
||||
else:
|
||||
## Another thread won the election and is running (or has run) NimMain.
|
||||
## Block until it finishes: proceeding now would race a half-initialized
|
||||
## Nim runtime/GC and corrupt the heap on concurrent first-time calls.
|
||||
while not initDone.load():
|
||||
discard
|
||||
when declared(setupForeignThreadGc):
|
||||
setupForeignThreadGc()
|
||||
when declared(nimGC_setStackBottom):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user