Erroring presumably due to the task scheduler resuming a dead thread

Reproduction Steps

coroutine.wrap(function()
    local co = coroutine.running()

    local function f()   
        task.wait(2)
        coroutine.resume(co)
    end

    task.spawn(f)

    task.wait(5)

    print("wait interrupted")
end)

Expected Behavior
I’d expect the following code to print "wait interrupted" after 2 seconds.

Actual Behavior
It does this, but errors at some point with the message “attempt to call a nil value”, that has no traceback (meaning it’s an internal error). Most importantly, the error happens after 5 seconds, so after the second wait has stopped yielding and is planning to resume the coroutine again, which is dead, and this is presumably the issue internally (which I assume can be fixed with a simple if statement).

Workaround
Adding a coroutine.yield() at the end, which works as explained above because the wait tries to resume the coroutine again, but it’s yielded, not dead.

Issue Area: Engine
Issue Type: Other
Impact: Low
Frequency: Constantly

5 Likes

This seems like expected behavior to me, you’re resuming a thread which is already scheduled for resumption by the engine scheduler. Not throwing this error could lead to situations where a thread is scheduled for resumption but the engine fails silently because some other part of your code unexpectedly resumed it.

You can solve this in a fairly trivial way:

function foo()
    local thread = coroutine.running()
    local resumed = false

    local function resume(...)
        if not resumed then
            resumed = true
            task.spawn(thread, ...)
        end
    end

    task.delay(5, resume, false)

    task.spawn(function ()
        -- do something which yields
        resume(true)
    end)

    local interrupted = coroutine.yield()
    print("Wait interrupted:", interrupted)
end

At the end of the day, you shouldn’t be trying to resume a thread which you’ve already told the scheduler to resume. This will only lead to race-conditions and conflicts between the two systems that try to resume the thread.

1 Like

Agreed that it’s a bad idea to resume it anyway. However, this silent nil error seems quite obscure. It should be a clear error, including a traceback, saying something like “tried to resume coroutine twice”

4 Likes

Thanks for your report! This is not a bug, you are resuming threads that have already been scheduled for resumption by the engine.

This topic was automatically closed after 6 days. New replies are no longer allowed.