Merge branch 'new_spawn' of https://github.com/Araq/Nimrod into new_spawn
This commit is contained in:
commit
387593bcaa
3 changed files with 34 additions and 13 deletions
|
|
@ -205,20 +205,30 @@ proc createNimCreatePromiseCall(prom, threadParam: PNode): PNode =
|
||||||
let castExpr = newNodeIT(nkCast, prom.info, prom.typ)
|
let castExpr = newNodeIT(nkCast, prom.info, prom.typ)
|
||||||
castExpr.add emptyNode
|
castExpr.add emptyNode
|
||||||
castExpr.add callCodeGenProc("nimCreatePromise", threadParam, size)
|
castExpr.add callCodeGenProc("nimCreatePromise", threadParam, size)
|
||||||
result = newFastAsgnStmt(prom, castExpr)
|
result = castExpr
|
||||||
|
|
||||||
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||||
varSection, call, barrier, prom: PNode;
|
varSection, call, barrier, prom: PNode;
|
||||||
spawnKind: TSpawnResult): PSym =
|
spawnKind: TSpawnResult): PSym =
|
||||||
var body = newNodeI(nkStmtList, f.info)
|
var body = newNodeI(nkStmtList, f.info)
|
||||||
|
var threadLocalBarrier: PSym
|
||||||
if barrier != nil:
|
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
|
var threadLocalProm: PSym
|
||||||
if spawnKind == srByVar:
|
if spawnKind == srByVar:
|
||||||
threadLocalProm = addLocalVar(varSection, argsParam.owner, prom.typ, prom)
|
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
|
body.add varSection
|
||||||
if prom != nil and spawnKind != srByVar:
|
if prom != nil and spawnKind != srByVar:
|
||||||
body.add createNimCreatePromiseCall(prom, threadParam.newSymNode)
|
body.add newFastAsgnStmt(prom, threadLocalProm.newSymNode)
|
||||||
if barrier == nil:
|
if barrier == nil:
|
||||||
body.add callCodeGenProc("nimPromiseCreateCondVar", prom)
|
body.add callCodeGenProc("nimPromiseCreateCondVar", prom)
|
||||||
|
|
||||||
|
|
@ -230,14 +240,16 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||||
if fk == promInvalid:
|
if fk == promInvalid:
|
||||||
localError(f.info, "cannot create a promise of type: " &
|
localError(f.info, "cannot create a promise of type: " &
|
||||||
typeToString(prom.typ.sons[1]))
|
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 fk == promGC: "data" else: "blob", prom.info), call)
|
||||||
if barrier == nil:
|
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:
|
else:
|
||||||
body.add call
|
body.add call
|
||||||
if barrier != nil:
|
if barrier != nil:
|
||||||
body.add callCodeGenProc("barrierLeave", barrier)
|
body.add callCodeGenProc("barrierLeave", threadLocalBarrier.newSymNode)
|
||||||
|
|
||||||
var params = newNodeI(nkFormalParams, f.info)
|
var params = newNodeI(nkFormalParams, f.info)
|
||||||
params.add emptyNode
|
params.add emptyNode
|
||||||
|
|
|
||||||
|
|
@ -42,22 +42,30 @@ proc signal(cv: var CondVar) =
|
||||||
|
|
||||||
type
|
type
|
||||||
Barrier* {.compilerProc.} = object
|
Barrier* {.compilerProc.} = object
|
||||||
counter: int
|
entered: int
|
||||||
cv: CondVar
|
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.} =
|
proc barrierEnter*(b: ptr Barrier) {.compilerProc.} =
|
||||||
atomicInc b.counter
|
atomicInc b.entered
|
||||||
|
|
||||||
proc barrierLeave*(b: ptr Barrier) {.compilerProc.} =
|
proc barrierLeave*(b: ptr Barrier) {.compilerProc.} =
|
||||||
atomicDec b.counter
|
atomicInc b.left
|
||||||
if b.counter <= 0: signal(b.cv)
|
# 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.} =
|
proc openBarrier*(b: ptr Barrier) {.compilerProc.} =
|
||||||
b.counter = 0
|
b.entered = 0
|
||||||
b.cv = createCondVar()
|
b.cv = createCondVar()
|
||||||
|
b.left = -1
|
||||||
|
|
||||||
proc closeBarrier*(b: ptr Barrier) {.compilerProc.} =
|
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)
|
destroyCondVar(b.cv)
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
@ -151,7 +159,7 @@ proc await*[T](prom: Promise[T]) =
|
||||||
if prom.usesCondVar: await(prom.cv)
|
if prom.usesCondVar: await(prom.cv)
|
||||||
|
|
||||||
proc awaitAndThen*[T](prom: Promise[T]; action: proc (x: T) {.closure.}) =
|
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
|
## 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
|
## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can
|
||||||
## sometimes be more efficient than ``^``.
|
## sometimes be more efficient than ``^``.
|
||||||
|
|
|
||||||
1
tests/parallel/nimrod.cfg
Normal file
1
tests/parallel/nimrod.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
threads:on
|
||||||
Loading…
Add table
Add a link
Reference in a new issue