fix coro proc crash for stack problem when run long enough than a GC cycle (#7612) (#11410)

Co-authored-by: drswinghead <drswinghead@gmail.com>
Co-authored-by: Clyybber <darkmine956@gmail.com>
This commit is contained in:
yatsen1
2020-09-18 23:17:09 +08:00
committed by GitHub
parent d19316bbb9
commit 341cd844b2
2 changed files with 14 additions and 0 deletions

View File

@@ -36,6 +36,7 @@ const defaultStackSize = 512 * 1024
proc GC_addStack(bottom: pointer) {.cdecl, importc.}
proc GC_removeStack(bottom: pointer) {.cdecl, importc.}
proc GC_setActiveStack(bottom: pointer) {.cdecl, importc.}
proc GC_getActiveStack() : pointer {.cdecl, importc.}
const
CORO_BACKEND_UCONTEXT = 0
@@ -166,6 +167,7 @@ type
coroutines: DoublyLinkedList[CoroutinePtr]
current: DoublyLinkedNode[CoroutinePtr]
loop: Coroutine
ncbottom: pointer # non coroutine stack botttom
var ctx {.threadvar.}: CoroutineLoopContext
@@ -183,6 +185,7 @@ proc initialize() =
ctx.coroutines = initDoublyLinkedList[CoroutinePtr]()
ctx.loop = Coroutine()
ctx.loop.state = CORO_EXECUTING
ctx.ncbottom = GC_getActiveStack()
when coroBackend == CORO_BACKEND_FIBERS:
ctx.loop.execContext = ConvertThreadToFiberEx(nil, FIBER_FLAG_FLOAT_SWITCH)
@@ -193,6 +196,7 @@ proc switchTo(current, to: CoroutinePtr) =
to.lastRun = getTicks()
# Update position of current stack so gc invoked from another stack knows how much to scan.
GC_setActiveStack(current.stack.bottom)
nimGC_setStackBottom(current.stack.bottom)
var frame = getFrameState()
block:
# Execution will switch to another fiber now. We do not need to update current stack
@@ -215,12 +219,14 @@ proc switchTo(current, to: CoroutinePtr) =
# Execution was just resumed. Restore frame information and set active stack.
setFrameState(frame)
GC_setActiveStack(current.stack.bottom)
nimGC_setStackBottom(ctx.ncbottom)
proc suspend*(sleepTime: float = 0) =
## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds.
## Until then other coroutines are executed.
var current = getCurrent()
current.sleepTime = sleepTime
nimGC_setStackBottom(ctx.ncbottom)
switchTo(current, addr(ctx.loop))
proc runCurrentTask() =
@@ -230,6 +236,7 @@ proc runCurrentTask() =
block:
var current = getCurrent()
current.stack.bottom = sp
nimGC_setStackBottom(current.stack.bottom)
# Execution of new fiber just started. Since it was entered not through `switchTo` we
# 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
@@ -244,6 +251,7 @@ proc runCurrentTask() =
echo "Unhandled exception in coroutine."
writeStackTrace()
current.state = CORO_FINISHED
nimGC_setStackBottom(ctx.ncbottom)
suspend(0) # Exit coroutine without returning from coroExecWithStack()
doAssert false

View File

@@ -273,6 +273,9 @@ when nimCoroutines:
gch.activeStack = gch.stack.find(bottom)
gch.activeStack.setPosition(addr(sp))
proc GC_getActiveStack() : pointer {.cdecl, exportc.} =
return gch.activeStack.bottom
when not defined(useNimRtl):
proc nimGC_setStackBottom(theStackBottom: pointer) =
# Initializes main stack of the thread.
@@ -300,6 +303,9 @@ when not defined(useNimRtl):
else:
gch.stack.bottom = cast[pointer](max(a, b))
when nimCoroutines:
if theStackBottom != nil: gch.stack.bottom = theStackBottom
gch.stack.setPosition(theStackBottom)
{.pop.}