Mayby, the better solution is just to do explicit "eager" initialisation of 
threadvars, assuming the dev can insert code at all thread creation points. 
This seems to work:
    
    
    import locks
    
    type
      InitThreadLocalsProc* = proc(): void {.nimcall, gcsafe.}
        ## Type of a proc that initialises threadvars of some module in a new 
Thread.
    
    const MAX_INIT_PROCS = 100
      ## Maximum number of registered InitThreadLocalsProc.
    
    var allInitThreadLocalsProcs: array[MAX_INIT_PROCS,InitThreadLocalsProc]
      ## All registered InitThreadLocalsProc
    var registeredThreadLocalsProcs: int
      ## Number of registered InitThreadLocalsProc.
    var used: bool
      ## Was some thread already initialised?
    var arrayLock: Lock
      ## Lock to allow safe multi-threaded use.
    
    initLock(arrayLock)
    
    proc registerThreadLocalInitialiser*(init: InitThreadLocalsProc) =
      ## Registers a InitThreadLocalsProc.
      ## This cannot be called anymore, after the first call to
      ## runThreadLocalInitialisers().
      if init.isNil:
        raise newException(Exception, "init is nil!")
      acquire(arrayLock)
      try:
        if used:
          raise newException(Exception, "New Threads already initialised!")
        if registeredThreadLocalsProcs == MAX_INIT_PROCS:
          raise newException(Exception, "Too many ThreadLocal Initialisers!")
        allInitThreadLocalsProcs[registeredThreadLocalsProcs] = init
        inc registeredThreadLocalsProcs
      finally:
        release(arrayLock)
    
    proc runThreadLocalInitialisers*() =
      ## Runs all InitThreadLocalsProcs.
      ## Only call this after all initialisers have been registered.
      var initialisers: array[MAX_INIT_PROCS,InitThreadLocalsProc]
      var count: int
      acquire(arrayLock)
      try:
        used = true
        initialisers = allInitThreadLocalsProcs
        count = registeredThreadLocalsProcs
      finally:
        release(arrayLock)
      for i in 0..<count:
        initialisers[i]()
    

And a test:
    
    
    import threadlocal
    
    proc initA() {.gcsafe.} =
      echo("Running initA() in thread ",getThreadId())
    
    proc initB() {.gcsafe.} =
      echo("Running initB() in thread ",getThreadId())
    
    registerThreadLocalInitialiser(initA)
    registerThreadLocalInitialiser(initB)
    
    proc whatever() {.thread.} =
      echo("In Thread ",getThreadId())
      runThreadLocalInitialisers()
      echo("Thread ",getThreadId(), " done")
    
    var thread: Thread[void]
    createThread[void](thread, whatever)
    joinThread(thread)
    
    echo("DONE")
    

Reply via email to