diff options
author | Araq <rumpf_a@web.de> | 2014-06-02 23:32:28 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-06-02 23:32:28 +0200 |
commit | 387593bcaab1d399e87f5f7b596d14858b23dabb (patch) | |
tree | 1579515fdd44cb5dc648b3d82162348d42c4970a | |
parent | be229163af18a5d31fc3656ced853d6857d885ee (diff) | |
parent | 7303c3292f42be78555f7a7241f0c46634557d37 (diff) | |
download | Nim-387593bcaab1d399e87f5f7b596d14858b23dabb.tar.gz |
Merge branch 'new_spawn' of https://github.com/Araq/Nimrod into new_spawn
-rw-r--r-- | compiler/lowerings.nim | 24 | ||||
-rw-r--r-- | lib/pure/concurrency/threadpool.nim | 22 | ||||
-rw-r--r-- | tests/parallel/nimrod.cfg | 1 |
3 files changed, 34 insertions, 13 deletions
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index df2816a0e..af4daf785 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -205,20 +205,30 @@ proc createNimCreatePromiseCall(prom, threadParam: PNode): PNode = let castExpr = newNodeIT(nkCast, prom.info, prom.typ) castExpr.add emptyNode castExpr.add callCodeGenProc("nimCreatePromise", threadParam, size) - result = newFastAsgnStmt(prom, castExpr) + result = castExpr proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; varSection, call, barrier, prom: PNode; spawnKind: TSpawnResult): PSym = var body = newNodeI(nkStmtList, f.info) + var threadLocalBarrier: PSym if barrier != nil: - body.add callCodeGenProc("barrierEnter", barrier) + var varSection = newNodeI(nkVarSection, barrier.info) + threadLocalBarrier = addLocalVar(varSection, argsParam.owner, + barrier.typ, barrier) + body.add varSection + body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode) var threadLocalProm: PSym if spawnKind == srByVar: threadLocalProm = addLocalVar(varSection, argsParam.owner, prom.typ, prom) + elif prom != nil: + internalAssert prom.typ.kind == tyGenericInst + threadLocalProm = addLocalVar(varSection, argsParam.owner, prom.typ, + createNimCreatePromiseCall(prom, threadParam.newSymNode)) + body.add varSection if prom != nil and spawnKind != srByVar: - body.add createNimCreatePromiseCall(prom, threadParam.newSymNode) + body.add newFastAsgnStmt(prom, threadLocalProm.newSymNode) if barrier == nil: body.add callCodeGenProc("nimPromiseCreateCondVar", prom) @@ -230,14 +240,16 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; if fk == promInvalid: localError(f.info, "cannot create a promise of type: " & typeToString(prom.typ.sons[1])) - body.add newAsgnStmt(indirectAccess(prom, + body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, if fk == promGC: "data" else: "blob", prom.info), call) if barrier == nil: - body.add callCodeGenProc("nimPromiseSignal", prom) + # by now 'prom' is shared and thus might have beeen overwritten! we need + # to use the thread-local view instead: + body.add callCodeGenProc("nimPromiseSignal", threadLocalProm.newSymNode) else: body.add call if barrier != nil: - body.add callCodeGenProc("barrierLeave", barrier) + body.add callCodeGenProc("barrierLeave", threadLocalBarrier.newSymNode) var params = newNodeI(nkFormalParams, f.info) params.add emptyNode diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 24cb9ccdd..22f00bc0d 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -42,22 +42,30 @@ proc signal(cv: var CondVar) = type Barrier* {.compilerProc.} = object - counter: int + entered: int cv: CondVar + cacheAlign: array[0..20, byte] # ensure 'left' is not on the same + # cache line as 'entered' + left: int proc barrierEnter*(b: ptr Barrier) {.compilerProc.} = - atomicInc b.counter + atomicInc b.entered proc barrierLeave*(b: ptr Barrier) {.compilerProc.} = - atomicDec b.counter - if b.counter <= 0: signal(b.cv) + atomicInc b.left + # these can only be equal if 'closeBarrier' already signaled its interest + # in this event: + if b.left == b.entered: signal(b.cv) proc openBarrier*(b: ptr Barrier) {.compilerProc.} = - b.counter = 0 + b.entered = 0 b.cv = createCondVar() + b.left = -1 proc closeBarrier*(b: ptr Barrier) {.compilerProc.} = - while b.counter > 0: await(b.cv) + # signal interest in the "all done" event: + atomicInc b.left + while b.left != b.entered: await(b.cv) destroyCondVar(b.cv) {.pop.} @@ -151,7 +159,7 @@ proc await*[T](prom: Promise[T]) = if prom.usesCondVar: await(prom.cv) proc awaitAndThen*[T](prom: Promise[T]; action: proc (x: T) {.closure.}) = - ## blocks until the value is available and then passes this value + ## blocks until the ``prom`` is available and then passes its value ## to ``action``. Note that due to Nimrod's parameter passing semantics this ## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can ## sometimes be more efficient than ``^``. diff --git a/tests/parallel/nimrod.cfg b/tests/parallel/nimrod.cfg new file mode 100644 index 000000000..b81c89721 --- /dev/null +++ b/tests/parallel/nimrod.cfg @@ -0,0 +1 @@ +threads:on |