diff options
author | Dmitry Polienko <dmitry@eldis.ru> | 2016-08-11 03:11:57 -0700 |
---|---|---|
committer | Dmitry Polienko <dmitry@eldis.ru> | 2016-08-11 03:11:57 -0700 |
commit | 2edd3786ce71e1a15fd9de0dd32452ff0996e210 (patch) | |
tree | 2855435e69e124c3bc712f2621501667592a89c6 /lib/pure/concurrency | |
parent | dd84dc85d067f0936746b8a80e7f249611b68da2 (diff) | |
download | Nim-2edd3786ce71e1a15fd9de0dd32452ff0996e210.tar.gz |
Add a workaround for threadpool deadlocks on recursion
Diffstat (limited to 'lib/pure/concurrency')
-rw-r--r-- | lib/pure/concurrency/threadpool.nim | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 9490dbbd5..baa96cacd 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -297,9 +297,17 @@ var gSomeReady : Semaphore readyWorker: ptr Worker +# A workaround for recursion deadlock issue +# https://github.com/nim-lang/Nim/issues/4597 +var + numSlavesRunning: int + numSlavesWaiting: int + isSlave {.threadvar.}: bool + gSomeReady.initSemaphore() proc slave(w: ptr Worker) {.thread.} = + isSlave = true while true: when declared(atomicStoreN): atomicStoreN(addr(w.ready), true, ATOMIC_SEQ_CST) @@ -311,7 +319,11 @@ proc slave(w: ptr Worker) {.thread.} = # XXX Somebody needs to look into this (why does this assertion fail # in Visual Studio?) when not defined(vcc): assert(not w.ready) + + atomicInc numSlavesRunning w.f(w, w.data) + atomicDec numSlavesRunning + if w.q.len != 0: w.cleanFlowVars if w.shutdown: w.shutdown = false @@ -464,10 +476,30 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} = fn(self, data) await(self.taskStarted) return + + if isSlave and numSlavesRunning <= numSlavesWaiting + 1: + # All the other slaves are waiting + # If we wait now, we-re deadlocked until + # an external spawn happens ! + if currentPoolSize < maxPoolSize: + if not workersData[currentPoolSize].initialized: + activateWorkerThread(currentPoolSize) + let w = addr(workersData[currentPoolSize]) + atomicInc currentPoolSize + if selectWorker(w, fn, data): + return else: - await(gSomeReady) - else: - await(gSomeReady) + # There is no place in pool. We're deadlocked. + # echo "Deadlock!" + discard + + if isSlave: + atomicInc numSlavesWaiting + + await(gSomeReady) + + if isSlave: + atomicDec numSlavesWaiting var distinguishedLock: Lock |