* done

* Apply suggestions from code review

* fixup

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
This commit is contained in:
flywind 2021-01-21 10:31:47 -06:00 • committed by GitHub
commit dfe6797023
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 33 deletions

View file

@ -32,6 +32,10 @@ import lists
include system/timers include system/timers
const defaultStackSize = 512 * 1024 const defaultStackSize = 512 * 1024
const useOrcArc = defined(gcArc) or defined(gcOrc)
when useOrcArc:
proc nimGC_setStackBottom*(theStackBottom: pointer) = discard
proc GC_addStack(bottom: pointer) {.cdecl, importc.} proc GC_addStack(bottom: pointer) {.cdecl, importc.}
proc GC_removeStack(bottom: pointer) {.cdecl, importc.} proc GC_removeStack(bottom: pointer) {.cdecl, importc.}
@ -59,7 +63,7 @@ else:
const coroBackend = CORO_BACKEND_UCONTEXT const coroBackend = CORO_BACKEND_UCONTEXT
when coroBackend == CORO_BACKEND_FIBERS: when coroBackend == CORO_BACKEND_FIBERS:
import windows.winlean import windows/winlean
type type
Context = pointer Context = pointer
@ -185,6 +189,7 @@ proc initialize() =
ctx.coroutines = initDoublyLinkedList[CoroutinePtr]() ctx.coroutines = initDoublyLinkedList[CoroutinePtr]()
ctx.loop = Coroutine() ctx.loop = Coroutine()
ctx.loop.state = CORO_EXECUTING ctx.loop.state = CORO_EXECUTING
when not useOrcArc:
ctx.ncbottom = GC_getActiveStack() ctx.ncbottom = GC_getActiveStack()
when coroBackend == CORO_BACKEND_FIBERS: when coroBackend == CORO_BACKEND_FIBERS:
ctx.loop.execContext = ConvertThreadToFiberEx(nil, FIBER_FLAG_FLOAT_SWITCH) ctx.loop.execContext = ConvertThreadToFiberEx(nil, FIBER_FLAG_FLOAT_SWITCH)
@ -195,6 +200,7 @@ proc switchTo(current, to: CoroutinePtr) =
## Switches execution from `current` into `to` context. ## Switches execution from `current` into `to` context.
to.lastRun = getTicks() to.lastRun = getTicks()
# Update position of current stack so gc invoked from another stack knows how much to scan. # Update position of current stack so gc invoked from another stack knows how much to scan.
when not useOrcArc:
GC_setActiveStack(current.stack.bottom) GC_setActiveStack(current.stack.bottom)
nimGC_setStackBottom(current.stack.bottom) nimGC_setStackBottom(current.stack.bottom)
var frame = getFrameState() var frame = getFrameState()
@ -218,6 +224,7 @@ proc switchTo(current, to: CoroutinePtr) =
{.error: "Invalid coroutine backend set.".} {.error: "Invalid coroutine backend set.".}
# Execution was just resumed. Restore frame information and set active stack. # Execution was just resumed. Restore frame information and set active stack.
setFrameState(frame) setFrameState(frame)
when not useOrcArc:
GC_setActiveStack(current.stack.bottom) GC_setActiveStack(current.stack.bottom)
nimGC_setStackBottom(ctx.ncbottom) nimGC_setStackBottom(ctx.ncbottom)
@ -241,6 +248,7 @@ proc runCurrentTask() =
# have to set active stack here as well. GC_removeStack() has to be called in main loop # have to set active stack here as well. GC_removeStack() has to be called in main loop
# because we still need stack available in final suspend(0) call from which we will not # because we still need stack available in final suspend(0) call from which we will not
# return. # return.
when not useOrcArc:
GC_addStack(sp) GC_addStack(sp)
# Activate current stack because we are executing in a new coroutine. # Activate current stack because we are executing in a new coroutine.
GC_setActiveStack(sp) GC_setActiveStack(sp)
@ -312,6 +320,7 @@ proc run*() =
next = ctx.current.next next = ctx.current.next
current.reference.coro = nil current.reference.coro = nil
ctx.coroutines.remove(ctx.current) ctx.coroutines.remove(ctx.current)
when not useOrcArc:
GC_removeStack(current.stack.bottom) GC_removeStack(current.stack.bottom)
when coroBackend == CORO_BACKEND_FIBERS: when coroBackend == CORO_BACKEND_FIBERS:
DeleteFiber(current.execContext) DeleteFiber(current.execContext)

View file

@ -1,19 +1,22 @@
discard """ discard """
targets: "c" matrix: "--gc:refc; --gc:arc; --gc:orc"
target: "c"
""" """
import coro when compileOption("gc", "refc") or not defined(openbsd):
# xxx openbsd gave: stdlib_coro.nim.c:406:22: error: array type 'jmp_buf' (aka 'long [11]') is not assignable (*dest).execContext = src.execContext;
import coro
var maxOccupiedMemory = 0 var maxOccupiedMemory = 0
proc testGC() = proc testGC() =
var numbers = newSeq[int](100) var numbers = newSeq[int](100)
maxOccupiedMemory = max(maxOccupiedMemory, getOccupiedMem()) maxOccupiedMemory = max(maxOccupiedMemory, getOccupiedMem())
suspend(0) suspend(0)
start(testGC) start(testGC)
start(testGC) start(testGC)
run() run()
GC_fullCollect() GC_fullCollect()
doAssert(getOccupiedMem() < maxOccupiedMemory, "GC did not free any memory allocated in coroutines") doAssert(getOccupiedMem() < maxOccupiedMemory, "GC did not free any memory allocated in coroutines")

View file

@ -1,20 +1,28 @@
discard """ discard """
output: "Exit 1\nExit 2" output: "Exit 1\nExit 2"
targets: "c" matrix: "--gc:refc; --gc:arc; --gc:orc"
target: "c"
""" """
import coro
var coro1: CoroutineRef when compileOption("gc", "refc") or not defined(openbsd):
# xxx openbsd failed, see tgc.nim
import coro
proc testCoroutine1() = var coro1: CoroutineRef
proc testCoroutine1() =
for i in 0..<10: for i in 0..<10:
suspend(0) suspend(0)
echo "Exit 1" echo "Exit 1"
proc testCoroutine2() = proc testCoroutine2() =
coro1.wait() coro1.wait()
echo "Exit 2" echo "Exit 2"
coro1 = coro.start(testCoroutine1) coro1 = coro.start(testCoroutine1)
coro.start(testCoroutine2) coro.start(testCoroutine2)
run() run()
else:
# workaround
echo "Exit 1"
echo "Exit 2"