diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/coro.nim | 13 | ||||
-rw-r--r-- | lib/system/gc.nim | 7 | ||||
-rw-r--r-- | lib/system/gc_common.nim | 20 |
3 files changed, 33 insertions, 7 deletions
diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 75cd9ddac..b227a5a3d 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -164,6 +164,7 @@ proc runCurrentTask() proc switchTo(current, to: Coroutine) = ## Switches execution from `current` into `to` context. to.lastRun = getTicks() + # Execution will switch to another fiber now. when coroBackend == CORO_BACKEND_FIBERS: SwitchToFiber(to.execContext) elif coroBackend == CORO_BACKEND_UCONTEXT: @@ -180,13 +181,13 @@ proc switchTo(current, to: Coroutine) = doAssert false else: {.error: "Invalid coroutine backend set.".} + # Execution was just resumed. Set active stack to current one. + GC_setCurrentStack(current.stack.start) proc suspend*(sleepTime: float=0) = ## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds. ## Until then other coroutines are executed. - var sp {.volatile.}: pointer var current = getCurrent() - GC_setCurrentStack(current.stack.start, cast[pointer](addr sp)) current.sleepTime = sleepTime var frame = getFrameState() switchTo(current, ctx.loop) @@ -195,6 +196,9 @@ proc suspend*(sleepTime: float=0) = proc runCurrentTask() = ## Starts execution of current coroutine and updates it's state through coroutine's life. var current = getCurrent() + # Execution of new fiber just started. Since it was entered not through `switchTo` we + # have to set active stack here as well. + GC_setCurrentStack(current.stack.start) current.state = CORO_EXECUTING current.fn() # Start coroutine execution current.state = CORO_FINISHED @@ -228,6 +232,7 @@ proc start*(c: proc(), stacksize: int=defaultStackSize) = coro.execContext.uc_link = addr ctx.loop.execContext makecontext(coro.execContext, runCurrentTask, 0) coro.stack.size = stacksize + coro.state = CORO_CREATED GC_addStack(coro.stack.ends) ctx.coroutines.append(coro) @@ -260,7 +265,9 @@ proc run*() = # are to be scheduled. next = ctx.current.next ctx.coroutines.remove(ctx.current) - when coroBackend != CORO_BACKEND_FIBERS: + when coroBackend == CORO_BACKEND_FIBERS: + DeleteFiber(coro.execContext) + else: dealloc(current.stack.start) current.stack.start = nil current.stack.ends = nil diff --git a/lib/system/gc.nim b/lib/system/gc.nim index c17442a97..eaf68c0c4 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -72,8 +72,11 @@ type GcHeap {.final, pure.} = object # this contains the zero count and # non-zero count table - stack: ptr GcStack - stackBottom: pointer + when defined(nimCoroutines): + stack: ptr GcStack + stackActive: ptr GcStack + else: + stackBottom: pointer cycleThreshold: int when useCellIds: idGenerator: int diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 4116a8525..feea454e7 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -108,12 +108,15 @@ when defined(nimCoroutines): else: stack = stack.next - proc GC_setCurrentStack*(starts, pos: pointer) {.cdecl, exportc.} = + proc GC_setCurrentStack*(starts: pointer) {.cdecl, exportc.} = + var pos {.volatile.}: pointer + pos = addr(pos) var stack = gch.stack while stack != nil: if stack.starts == starts: stack.pos = pos stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts, pos)) + gch.stackActive = stack return stack = stack.next gcAssert(false, "Current stack position does not belong to registered stack") @@ -183,7 +186,11 @@ when not defined(useNimRtl): #c_fprintf(stdout, "stack bottom: %p;\n", theStackBottom) # the first init must be the one that defines the stack bottom: when defined(nimCoroutines): - GC_addStack(theStackBottom) + if gch.stack == nil: + # `setStackBottom()` gets called multiple times from main thread. + # Add it only once. + GC_addStack(theStackBottom) + GC_setCurrentStack(theStackBottom) else: if gch.stackBottom == nil: gch.stackBottom = theStackBottom else: @@ -279,10 +286,19 @@ else: type PStackSlice = ptr array[0..7, pointer] var registers {.noinit.}: C_JmpBuf discard c_setjmp(registers) + gch.stackActive.pos = addr(registers) for stack in items(gch.stack): stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts)) var max = cast[ByteAddress](stack.starts) var sp = cast[ByteAddress](stack.pos) + when defined(amd64): + if stack == gch.stackActive: + # words within the jmp_buf structure may not be properly aligned. + let regEnd = sp +% sizeof(registers) + while sp <% regEnd: + gcMark(gch, cast[PPointer](sp)[]) + gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[]) + sp = sp +% sizeof(pointer) # loop unrolled: while sp <% max - 8*sizeof(pointer): gcMark(gch, cast[PStackSlice](sp)[0]) |