bugfixes for generics; new threads implementation still broken
This commit is contained in:
parent
dc3ace4f37
commit
fd62116f6e
19 changed files with 260 additions and 126 deletions
|
|
@ -104,13 +104,17 @@ proc toAny*[T](x: var T): TAny {.inline.} =
|
|||
proc kind*(x: TAny): TAnyKind {.inline.} =
|
||||
## get the type kind
|
||||
result = TAnyKind(ord(x.rawType.kind))
|
||||
|
||||
proc size*(x: TAny): int {.inline.} =
|
||||
## returns the size of `x`'s type.
|
||||
result = x.rawType.size
|
||||
|
||||
proc baseTypeKind*(x: TAny): TAnyKind {.inline.} =
|
||||
## get the base type's kind; ``akNone`` is returned if `x` has no base type.
|
||||
if x.rawType.base != nil:
|
||||
result = TAnyKind(ord(x.rawType.base.kind))
|
||||
|
||||
proc baseTypeSize*(x: TAny): int =
|
||||
proc baseTypeSize*(x: TAny): int {.inline.} =
|
||||
## returns the size of `x`'s basetype.
|
||||
if x.rawType.base != nil:
|
||||
result = x.rawType.base.size
|
||||
|
|
@ -339,8 +343,8 @@ proc getInt64*(x: TAny): int64 =
|
|||
|
||||
proc getBiggestInt*(x: TAny): biggestInt =
|
||||
## retrieve the integer value out of `x`. `x` needs to represent
|
||||
## some integer, a bool, a char or an enum. The value might be
|
||||
## sign-extended to ``biggestInt``.
|
||||
## some integer, a bool, a char, an enum or a small enough bit set.
|
||||
## The value might be sign-extended to ``biggestInt``.
|
||||
var t = skipRange(x.rawtype)
|
||||
case t.kind
|
||||
of tyInt: result = biggestInt(cast[ptr int](x.value)[])
|
||||
|
|
@ -350,7 +354,7 @@ proc getBiggestInt*(x: TAny): biggestInt =
|
|||
of tyInt64: result = biggestInt(cast[ptr int64](x.value)[])
|
||||
of tyBool: result = biggestInt(cast[ptr bool](x.value)[])
|
||||
of tyChar: result = biggestInt(cast[ptr char](x.value)[])
|
||||
of tyEnum:
|
||||
of tyEnum, tySet:
|
||||
case t.size
|
||||
of 1: result = ze64(cast[ptr int8](x.value)[])
|
||||
of 2: result = ze64(cast[ptr int16](x.value)[])
|
||||
|
|
@ -361,7 +365,7 @@ proc getBiggestInt*(x: TAny): biggestInt =
|
|||
|
||||
proc setBiggestInt*(x: TAny, y: biggestInt) =
|
||||
## sets the integer value of `x`. `x` needs to represent
|
||||
## some integer, a bool, a char or an enum.
|
||||
## some integer, a bool, a char, an enum or a small enough bit set.
|
||||
var t = skipRange(x.rawtype)
|
||||
case t.kind
|
||||
of tyInt: cast[ptr int](x.value)[] = int(y)
|
||||
|
|
@ -371,7 +375,7 @@ proc setBiggestInt*(x: TAny, y: biggestInt) =
|
|||
of tyInt64: cast[ptr int64](x.value)[] = int64(y)
|
||||
of tyBool: cast[ptr bool](x.value)[] = y != 0
|
||||
of tyChar: cast[ptr char](x.value)[] = chr(y.int)
|
||||
of tyEnum:
|
||||
of tyEnum, tySet:
|
||||
case t.size
|
||||
of 1: cast[ptr int8](x.value)[] = toU8(y.int)
|
||||
of 2: cast[ptr int16](x.value)[] = toU16(y.int)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ proc spawn*[TIn, TOut](action: proc(
|
|||
self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
|
||||
## creates an actor; that is a thread with an inbox. The caller MUST call
|
||||
## ``join`` because that also frees the associated resources with the actor.
|
||||
result = allocShared0(sizeof(result[]))
|
||||
result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
|
||||
open(result.i)
|
||||
createThread(result.t, action, result)
|
||||
|
||||
|
|
@ -52,8 +52,8 @@ proc recv*[TIn, TOut](a: PActor[TIn, TOut]): TTask[TIn, TOut] =
|
|||
## receives a task from `a`'s inbox.
|
||||
result = recv(a.i)
|
||||
|
||||
proc send*[TIn, TOut, X, Y](sender: PActor[X, Z],
|
||||
receiver: PActor[TIn, TOut], msg: TIn) =
|
||||
proc send*[TIn, TOut, X, Y](receiver: PActor[TIn, TOut], msg: TIn,
|
||||
sender: PActor[X, Y]) =
|
||||
## sends a message to `a`'s inbox.
|
||||
var t: TTask[TIn, TOut]
|
||||
t.receiver = addr(sender.i)
|
||||
|
|
@ -99,9 +99,9 @@ proc poolWorker[TIn, TOut](self: PActor[TIn, TOut]) {.thread.} =
|
|||
var m = self.recv
|
||||
if m.shutDown: break
|
||||
when TOut is void:
|
||||
action(m.data)
|
||||
m.action(m.data)
|
||||
else:
|
||||
self.repy(action(m.data))
|
||||
self.repy(m.action(m.data))
|
||||
|
||||
proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
|
||||
## creates an actor pool.
|
||||
|
|
@ -109,21 +109,20 @@ proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
|
|||
when TOut isnot void:
|
||||
open(a.outputs)
|
||||
for i in 0 .. < a.actors.len:
|
||||
a.actors[i] = spawn(poolWorker)
|
||||
a.actors[i] = spawn(poolWorker[TIn, TOut])
|
||||
|
||||
proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
|
||||
## waits for each actor in the actor pool `a` to finish and frees the
|
||||
## resources attached to `a`.
|
||||
var t: TTask[TIn, TOut]
|
||||
t.shutdown = true
|
||||
for i in 0 .. < a.actors.len: send(a.actors[i], t)
|
||||
for i in 0 .. < a.actors.len: send(a.actors[i].i, t)
|
||||
for i in 0 .. < a.actors.len: join(a.actors[i])
|
||||
when TOut isnot void:
|
||||
close(a.outputs)
|
||||
a.actors = nil
|
||||
|
||||
template setupTask =
|
||||
var t: TTask[TIn, TOut]
|
||||
t.action = action
|
||||
shallowCopy(t.data, input)
|
||||
|
||||
|
|
@ -132,7 +131,7 @@ template schedule =
|
|||
# it remains 'hot' ;-). Round-robin hurts for keeping threads hot.
|
||||
for i in 0..high(a.actors):
|
||||
if a.actors[i].i.ready:
|
||||
a.actors[i].send(t)
|
||||
a.actors[i].i.send(t)
|
||||
return
|
||||
# no thread ready :-( --> send message to the thread which has the least
|
||||
# messages pending:
|
||||
|
|
@ -142,27 +141,29 @@ template schedule =
|
|||
var curr = a.actors[i].i.peek
|
||||
if curr == 0:
|
||||
# ok, is ready now:
|
||||
a.actors[i].send(t)
|
||||
a.actors[i].i.send(t)
|
||||
return
|
||||
if curr < minVal:
|
||||
minVal = curr
|
||||
minIdx = i
|
||||
a.actors[minIdx].send(t)
|
||||
a.actors[minIdx].i.send(t)
|
||||
|
||||
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut],
|
||||
action: proc (input: TIn): TOut {.thread.},
|
||||
input: TIn): ptr TChannel[TOut] =
|
||||
## uses the actor pool to run `action` concurrently. `spawn` is guaranteed
|
||||
## to not block.
|
||||
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
|
||||
action: proc (input: TIn): TOut {.thread.}
|
||||
): ptr TChannel[TOut] =
|
||||
## uses the actor pool to run ``action(input)`` concurrently.
|
||||
## `spawn` is guaranteed to not block.
|
||||
var t: TTask[TIn, TOut]
|
||||
setupTask()
|
||||
result = addr(p.outputs)
|
||||
t.receiver = result
|
||||
schedule()
|
||||
|
||||
proc spawn*[TIn](p: var TActorPool[TIn, void],
|
||||
action: proc (input: TIn) {.thread.},
|
||||
input: TIn) =
|
||||
## uses the actor pool to run `action` concurrently. `spawn` is guaranteed
|
||||
## to not block.
|
||||
proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
|
||||
action: proc (input: TIn) {.thread.}) =
|
||||
## uses the actor pool to run ``action(input)`` concurrently.
|
||||
## `spawn` is guaranteed to not block.
|
||||
var t: TTask[TIn, void]
|
||||
setupTask()
|
||||
schedule()
|
||||
|
||||
|
|
@ -171,7 +172,7 @@ when isMainModule:
|
|||
a: TActorPool[int, void]
|
||||
createActorPool(a)
|
||||
for i in 0 .. < 300:
|
||||
a.spawn(proc (x: int) {.thread.} = echo x)
|
||||
a.spawn(i, proc (x: int) {.thread.} = echo x)
|
||||
|
||||
when false:
|
||||
proc treeDepth(n: PNode): int {.thread.} =
|
||||
|
|
|
|||
|
|
@ -323,6 +323,7 @@ proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
|
|||
if c.tok.kind == tkSymbol:
|
||||
result.value = c.tok.literal
|
||||
else:
|
||||
reset result
|
||||
result.kind = cfgError
|
||||
result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
|
||||
rawGetTok(c, c.tok)
|
||||
|
|
|
|||
|
|
@ -252,8 +252,10 @@ type
|
|||
object of TGcThread ## Nimrod thread. A thread is a heavy object (~14K)
|
||||
## that **must not** be part of a message! Use
|
||||
## a ``TThreadId`` for that.
|
||||
dataFn: proc (m: TArg)
|
||||
when TArg isnot void:
|
||||
when TArg is void:
|
||||
dataFn: proc ()
|
||||
else:
|
||||
dataFn: proc (m: TArg)
|
||||
data: TArg
|
||||
TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
|
||||
## a pointer as a thread ID.
|
||||
|
|
@ -273,7 +275,7 @@ template ThreadProcWrapperBody(closure: expr) =
|
|||
when defined(registerThread):
|
||||
t.stackBottom = addr(t)
|
||||
registerThread(t)
|
||||
if TArg is void: t.dataFn()
|
||||
when TArg is void: t.dataFn()
|
||||
else: t.dataFn(t.data)
|
||||
when defined(registerThread): unregisterThread(t)
|
||||
when defined(deallocOsPages): deallocOsPages()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue