summary refs log tree commit diff stats
path: root/lib/pure/coro.nim
diff options
context:
space:
mode:
authoryatsen1 <kitech@sixlan.tk>2020-09-18 23:17:09 +0800
committerGitHub <noreply@github.com>2020-09-18 17:17:09 +0200
commit341cd844b282cc6ed3b1fc4c1ef10c38fc06d5e7 (patch)
tree151533e9e12bd39f9302a3019983c8f603e182c7 /lib/pure/coro.nim
parentd19316bbb986a7dd1d6d091173963f6e74c65991 (diff)
downloadNim-341cd844b282cc6ed3b1fc4c1ef10c38fc06d5e7.tar.gz
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>
Diffstat (limited to 'lib/pure/coro.nim')
-rw-r--r--lib/pure/coro.nim8
1 files changed, 8 insertions, 0 deletions
diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim
index 6e49b6323..2a702b65b 100644
--- a/lib/pure/coro.nim
+++ b/lib/pure/coro.nim
@@ -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