Skip to content

coroutine

The complete coroutine library. Coroutines are the sanctioned way to write multi-step logic that spans frames — yield inside, resume from a hook.

Wraps function f into a coroutine. Nothing runs until the first resume.

local co = coroutine.create(function(a, b)
print("running", a, b)
end)
print(coroutine.status(co)) --> suspended

Like create, but returns a callable — calling it resumes the coroutine. Errors propagate to the caller (no ok flag).

local step = coroutine.wrap(function()
for i = 1, 3 do
print("step", i)
coroutine.yield()
end
end)
step() --> step 1
step() --> step 2
step() --> step 3

Starts or continues the coroutine; arguments pass to the function (first resume) or become the yield() return values (later resumes). Returns ok plus the yield/return values or the error message.

local co = coroutine.create(function(x)
local got = coroutine.yield(x * 2)
print("resumed with", got)
end)
print(coroutine.resume(co, 21)) --> true 42
print(coroutine.resume(co, "hi")) --> true (prints: resumed with hi)

Pauses the coroutine, sending values to the resumer. When resumed, the arguments of resume come back as yield’s return values.

local co = coroutine.create(function()
local answer = coroutine.yield("ask me")
print("got", answer)
end)
local _, question = coroutine.resume(co)
coroutine.resume(co, 42) --> got 42

One of "suspended", "running", "normal" (resumed another coroutine), or "dead".

local co = coroutine.create(function() coroutine.yield() end)
coroutine.resume(co)
print(coroutine.status(co)) --> suspended
coroutine.resume(co)
print(coroutine.status(co)) --> dead

Returns the running coroutine (or nil on the main thread) and a boolean: is this the main thread?

local co = coroutine.create(function()
local self, isMain = coroutine.running()
print(isMain) --> false
end)
coroutine.resume(co)
print(coroutine.running()) --> nil true

True inside a coroutine that can yield right now.

print(coroutine.isyieldable()) --> false (main thread)

Closes a suspended (or never-started) coroutine, running any pending defer/cleanup, and puts it in the dead state. Closing a running or dead coroutine errors.

local co = coroutine.create(function() coroutine.yield() end)
coroutine.resume(co)
print(coroutine.close(co)) --> true
print(coroutine.status(co)) --> dead

The bread-and-butter use in mods — stateful sequences without callbacks:

-- blink a warning: 0.5s on, 0.5s off, forever
local blink = coroutine.wrap(function()
while true do
print("ON")
coroutine.yield(0.5) -- wait 0.5s
print("OFF")
coroutine.yield(0.5)
end
end)
local wait = 0
usems.hook("frame", function(dt)
wait = wait - dt
if wait <= 0 then
wait = blink() or 0 -- yield returns the next delay
end
end)