Delete fiber context when it exits (memleak fix)
Few correctness changes to gc stack management.
This commit is contained in:
parent
9a754156d7
commit
ff1bf74554
3 changed files with 33 additions and 7 deletions
|
|
@ -164,6 +164,7 @@ proc runCurrentTask()
|
||||||
proc switchTo(current, to: Coroutine) =
|
proc switchTo(current, to: Coroutine) =
|
||||||
## Switches execution from `current` into `to` context.
|
## Switches execution from `current` into `to` context.
|
||||||
to.lastRun = getTicks()
|
to.lastRun = getTicks()
|
||||||
|
# Execution will switch to another fiber now.
|
||||||
when coroBackend == CORO_BACKEND_FIBERS:
|
when coroBackend == CORO_BACKEND_FIBERS:
|
||||||
SwitchToFiber(to.execContext)
|
SwitchToFiber(to.execContext)
|
||||||
elif coroBackend == CORO_BACKEND_UCONTEXT:
|
elif coroBackend == CORO_BACKEND_UCONTEXT:
|
||||||
|
|
@ -180,13 +181,13 @@ proc switchTo(current, to: Coroutine) =
|
||||||
doAssert false
|
doAssert false
|
||||||
else:
|
else:
|
||||||
{.error: "Invalid coroutine backend set.".}
|
{.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) =
|
proc suspend*(sleepTime: float=0) =
|
||||||
## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds.
|
## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds.
|
||||||
## Until then other coroutines are executed.
|
## Until then other coroutines are executed.
|
||||||
var sp {.volatile.}: pointer
|
|
||||||
var current = getCurrent()
|
var current = getCurrent()
|
||||||
GC_setCurrentStack(current.stack.start, cast[pointer](addr sp))
|
|
||||||
current.sleepTime = sleepTime
|
current.sleepTime = sleepTime
|
||||||
var frame = getFrameState()
|
var frame = getFrameState()
|
||||||
switchTo(current, ctx.loop)
|
switchTo(current, ctx.loop)
|
||||||
|
|
@ -195,6 +196,9 @@ proc suspend*(sleepTime: float=0) =
|
||||||
proc runCurrentTask() =
|
proc runCurrentTask() =
|
||||||
## Starts execution of current coroutine and updates it's state through coroutine's life.
|
## Starts execution of current coroutine and updates it's state through coroutine's life.
|
||||||
var current = getCurrent()
|
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.state = CORO_EXECUTING
|
||||||
current.fn() # Start coroutine execution
|
current.fn() # Start coroutine execution
|
||||||
current.state = CORO_FINISHED
|
current.state = CORO_FINISHED
|
||||||
|
|
@ -228,6 +232,7 @@ proc start*(c: proc(), stacksize: int=defaultStackSize) =
|
||||||
coro.execContext.uc_link = addr ctx.loop.execContext
|
coro.execContext.uc_link = addr ctx.loop.execContext
|
||||||
makecontext(coro.execContext, runCurrentTask, 0)
|
makecontext(coro.execContext, runCurrentTask, 0)
|
||||||
coro.stack.size = stacksize
|
coro.stack.size = stacksize
|
||||||
|
coro.state = CORO_CREATED
|
||||||
GC_addStack(coro.stack.ends)
|
GC_addStack(coro.stack.ends)
|
||||||
ctx.coroutines.append(coro)
|
ctx.coroutines.append(coro)
|
||||||
|
|
||||||
|
|
@ -260,7 +265,9 @@ proc run*() =
|
||||||
# are to be scheduled.
|
# are to be scheduled.
|
||||||
next = ctx.current.next
|
next = ctx.current.next
|
||||||
ctx.coroutines.remove(ctx.current)
|
ctx.coroutines.remove(ctx.current)
|
||||||
when coroBackend != CORO_BACKEND_FIBERS:
|
when coroBackend == CORO_BACKEND_FIBERS:
|
||||||
|
DeleteFiber(coro.execContext)
|
||||||
|
else:
|
||||||
dealloc(current.stack.start)
|
dealloc(current.stack.start)
|
||||||
current.stack.start = nil
|
current.stack.start = nil
|
||||||
current.stack.ends = nil
|
current.stack.ends = nil
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,11 @@ type
|
||||||
|
|
||||||
GcHeap {.final, pure.} = object # this contains the zero count and
|
GcHeap {.final, pure.} = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stack: ptr GcStack
|
when defined(nimCoroutines):
|
||||||
stackBottom: pointer
|
stack: ptr GcStack
|
||||||
|
stackActive: ptr GcStack
|
||||||
|
else:
|
||||||
|
stackBottom: pointer
|
||||||
cycleThreshold: int
|
cycleThreshold: int
|
||||||
when useCellIds:
|
when useCellIds:
|
||||||
idGenerator: int
|
idGenerator: int
|
||||||
|
|
|
||||||
|
|
@ -108,12 +108,15 @@ when defined(nimCoroutines):
|
||||||
else:
|
else:
|
||||||
stack = stack.next
|
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
|
var stack = gch.stack
|
||||||
while stack != nil:
|
while stack != nil:
|
||||||
if stack.starts == starts:
|
if stack.starts == starts:
|
||||||
stack.pos = pos
|
stack.pos = pos
|
||||||
stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts, pos))
|
stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts, pos))
|
||||||
|
gch.stackActive = stack
|
||||||
return
|
return
|
||||||
stack = stack.next
|
stack = stack.next
|
||||||
gcAssert(false, "Current stack position does not belong to registered stack")
|
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)
|
#c_fprintf(stdout, "stack bottom: %p;\n", theStackBottom)
|
||||||
# the first init must be the one that defines the stack bottom:
|
# the first init must be the one that defines the stack bottom:
|
||||||
when defined(nimCoroutines):
|
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:
|
else:
|
||||||
if gch.stackBottom == nil: gch.stackBottom = theStackBottom
|
if gch.stackBottom == nil: gch.stackBottom = theStackBottom
|
||||||
else:
|
else:
|
||||||
|
|
@ -279,10 +286,19 @@ else:
|
||||||
type PStackSlice = ptr array[0..7, pointer]
|
type PStackSlice = ptr array[0..7, pointer]
|
||||||
var registers {.noinit.}: C_JmpBuf
|
var registers {.noinit.}: C_JmpBuf
|
||||||
discard c_setjmp(registers)
|
discard c_setjmp(registers)
|
||||||
|
gch.stackActive.pos = addr(registers)
|
||||||
for stack in items(gch.stack):
|
for stack in items(gch.stack):
|
||||||
stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts))
|
stack.maxStackSize = max(stack.maxStackSize, stackSize(stack.starts))
|
||||||
var max = cast[ByteAddress](stack.starts)
|
var max = cast[ByteAddress](stack.starts)
|
||||||
var sp = cast[ByteAddress](stack.pos)
|
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:
|
# loop unrolled:
|
||||||
while sp <% max - 8*sizeof(pointer):
|
while sp <% max - 8*sizeof(pointer):
|
||||||
gcMark(gch, cast[PStackSlice](sp)[0])
|
gcMark(gch, cast[PStackSlice](sp)[0])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue