-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use main thread of current Lua state for callbacks, when known
If the library is opened from a Lua thread (coroutine) that is not the main one, the stored L would be to that thread, which may become suspended (by calling yield). It is unsafe to call functions on suspended Lua threads, which luv does a lot (the stored L is used for callbacks). The main thread of a Lua state can never yield, so it is always safe to call callbacks on. This commit ensures the main thread is stored in the luv context instead of the current thread, when we are able to calculate it (LUA_RIDX_MAINTHREAD was added in Lua 5.2, and I have not found a way to determine the main thread in Lua 5.1). This fixes #503
- Loading branch information
Showing
2 changed files
with
61 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
-- This is a standalone test because it specifically requires luv to | ||
-- be initially require()d from a thread/coroutine. | ||
-- Test for issue #503 (PR #734). | ||
|
||
local thread = coroutine.create(function () | ||
local uv = require "luv" | ||
coroutine.yield(); | ||
end); | ||
|
||
-- Resume (start) thread, which will load luv | ||
-- and then it will yield | ||
coroutine.resume(thread); | ||
|
||
-- thread where luv was initially loaded is now suspended | ||
|
||
return require('lib/tap')(function (test) | ||
|
||
if _VERSION == "Lua 5.1" then | ||
-- Lua 5.1 and LuaJIT do not provide an API to determine the main | ||
-- thread. Therefore it is inherently unsafe to require("luv") in | ||
-- a coroutine. | ||
test("callback should be in main thread", function(print,p,expect,uv) | ||
print("Skipping! This test is expected to fail on Lua 5.1 and LuaJIT."); | ||
end); | ||
else | ||
test("callback should be in main thread", function(print,p,expect,uv) | ||
-- Now, in the main thread, load luv and create a timer | ||
local t = uv.new_timer(); | ||
t:start(200, 0, expect(function () | ||
-- If luv calls this callback in the non-main (suspended) thread, | ||
-- it violates a requirement specified in the Lua manual to only | ||
-- call functions on active threads. | ||
|
||
local our_thread, is_main = coroutine.running(); | ||
|
||
-- Basic assertion that we are not running in the suspended thread | ||
assert(our_thread ~= thread) | ||
|
||
-- How coroutine.running() reports "main thread" varies between | ||
-- different Lua versions. This should handle them all. | ||
assert(our_thread == nil or is_main == true) | ||
|
||
-- If we were called in the wrong thread, this may segfault: | ||
-- coroutine.resume(thread) | ||
t:close(); | ||
end)); | ||
uv.run("default"); | ||
end); | ||
end | ||
end); | ||
|