summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2017-06-29 10:23:38 +0800
committerruki <[email protected]>2017-06-29 10:23:38 +0800
commit741d881be8b5f0ba62dd38bdb5f7fe32909f1263 (patch)
tree3e2a479cd5a482eae1da00614dacd037edf3fb20
parentc45a4613ce40f939b52c2ccd883712ff30d54dcc (diff)
avoid detect the same program in the same time leading to deadlock
-rw-r--r--core/src/xmake/process/waitlist.c2
-rw-r--r--xmake/core/base/process.lua104
-rw-r--r--xmake/core/sandbox/modules/import/lib/detect/find_program.lua13
-rw-r--r--xmake/modules/lib/detect/has_cxsnippets.lua4
4 files changed, 74 insertions, 49 deletions
diff --git a/core/src/xmake/process/waitlist.c b/core/src/xmake/process/waitlist.c
index 3e5d20aa0..b577c87f4 100644
--- a/core/src/xmake/process/waitlist.c
+++ b/core/src/xmake/process/waitlist.c
@@ -71,7 +71,7 @@ tb_int_t xm_process_waitlist(lua_State* lua)
if (count <= 0 || count > 64)
{
// error
- lua_pushfstring(lua, "invalid process count(%ld) for process.waitlist", count);
+ lua_pushfstring(lua, "invalid process count(%d) for process.waitlist", count);
lua_error(lua);
return 0;
}
diff --git a/xmake/core/base/process.lua b/xmake/core/base/process.lua
index 8cf96b2ea..76af563b4 100644
--- a/xmake/core/base/process.lua
+++ b/xmake/core/base/process.lua
@@ -101,53 +101,51 @@ function process.runjobs(jobfunc, total, comax, timeout, timer)
-- wait processes
local tasks_finished = {}
local procs_count = #procs
+ local procs_infos = nil
if procs_count > 0 then
-
- -- wait them
- local count, procinfos = process.waitlist(procs, utils.ifelse(procs_count < comax and index <= total, 0, timeout))
+ local count = -1
+ count, procs_infos = process.waitlist(procs, utils.ifelse(#tasks < comax and index <= total, 0, timeout))
if count < 0 then
return false, string.format("wait processes(%d) failed(%d)", #procs, count)
end
+ end
- -- timer is triggered? call timer
- if timer and os.mclock() - time > timeout then
- timer(indices)
- time = os.mclock()
- end
-
- -- wait ok
- for _, procinfo in ipairs(procinfos) do
-
- -- the process info
- local proc = procinfo[1]
- local procid = procinfo[2]
- local status = procinfo[3]
-
- -- check
- assert(procs[procid] == proc)
-
- -- resume this task
- local job_task = tasks[procid]
- local ok, job_proc_or_errors = coroutine.resume(job_task, 1, status)
- if not ok then
- return false, job_proc_or_errors
- end
+ -- timer is triggered? call timer
+ if timer and os.mclock() - time > timeout then
+ timer(indices)
+ time = os.mclock()
+ end
- -- the other process is pending for this task?
- if coroutine.status(job_task) ~= "dead" then
+ -- append fake procs_infos for coroutine.yield()
+ procs_infos = procs_infos or {}
+ for taskid = #procs + 1, #tasks do
+ table.insert(procs_infos, {nil, taskid, 0})
+ end
- -- check
- assert(job_proc_or_errors)
+ -- wait ok
+ for _, procinfo in ipairs(procs_infos) do
+
+ -- the process info
+ local proc = procinfo[1]
+ local taskid = procinfo[2]
+ local status = procinfo[3]
- -- update the pending process
- procs[procid] = job_proc_or_errors
+ -- check
+ assert(procs[taskid] == proc)
- -- this task has been finised?
- else
+ -- resume this task
+ local job_task = tasks[taskid]
+ local ok, job_proc_or_errors = coroutine.resume(job_task, 1, status)
+ if not ok then
+ return false, job_proc_or_errors
+ end
- -- mark this task as finised
- tasks_finished[procid] = true
- end
+ -- the other process is pending for this task?
+ if coroutine.status(job_task) ~= "dead" then
+ procs[taskid] = job_proc_or_errors
+ else
+ -- mark this task as finished?
+ tasks_finished[taskid] = true
end
end
@@ -156,18 +154,26 @@ function process.runjobs(jobfunc, total, comax, timeout, timer)
local procs_pending = {}
local indices_pending = {}
for taskid, job_task in ipairs(tasks) do
- if not tasks_finished[taskid] then
+ if not tasks_finished[taskid] and procs[taskid] ~= nil then -- for coroutine.yield(proc) in os.execv
table.insert(tasks_pending, job_task)
table.insert(procs_pending, procs[taskid])
table.insert(indices_pending, indices[taskid])
end
end
+ for taskid, job_task in ipairs(tasks) do
+ if not tasks_finished[taskid] and procs[taskid] == nil then -- for coroutine.yield()
+ table.insert(tasks_pending, job_task)
+ table.insert(indices_pending, indices[taskid])
+ end
+ end
tasks = tasks_pending
procs = procs_pending
indices = indices_pending
-- produce tasks
- while #tasks < comax and index <= total do
+ tasks_pending = {}
+ indices_pending = {}
+ while (#tasks + #tasks_pending) < comax and index <= total do
-- new task
local job_task = coroutine.create(jobfunc)
@@ -180,20 +186,24 @@ function process.runjobs(jobfunc, total, comax, timeout, timer)
-- add pending tasks
if coroutine.status(job_task) ~= "dead" then
-
- -- check
- assert(job_proc_or_errors)
-
- -- put task and proc to the pendings tasks
- table.insert(tasks, job_task)
- table.insert(procs, job_proc_or_errors)
- table.insert(indices, index)
+ if job_proc_or_errors ~= nil then -- for coroutine.yield(proc) in os.execv
+ table.insert(tasks, job_task)
+ table.insert(procs, job_proc_or_errors)
+ table.insert(indices, index)
+ else
+ table.insert(tasks_pending, job_task)
+ table.insert(indices_pending, index)
+ end
end
-- next index
index = index + 1
end
+ -- append pending tasks without process
+ table.join2(tasks, tasks_pending)
+ table.join2(indices, indices_pending)
+
until #tasks == 0
-- ok
diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_program.lua b/xmake/core/sandbox/modules/import/lib/detect/find_program.lua
index a09436d72..e38a3414c 100644
--- a/xmake/core/sandbox/modules/import/lib/detect/find_program.lua
+++ b/xmake/core/sandbox/modules/import/lib/detect/find_program.lua
@@ -37,6 +37,9 @@ local raise = require("sandbox/modules/raise")
local vformat = require("sandbox/modules/vformat")
local cache = require("sandbox/modules/import/lib/detect/cache")
+-- globals
+local checking = nil
+
-- check program
function sandbox_lib_detect_find_program._check(program, check)
@@ -141,6 +144,14 @@ end
--
function sandbox_lib_detect_find_program.main(name, pathes, check)
+ -- @note avoid detect the same program in the same time leading to deadlock if running in the coroutine (.e.g ccache)
+ local coroutine_running = coroutine.running()
+ if coroutine_running then
+ while checking ~= nil and checking == name do
+ coroutine.yield()
+ end
+ end
+
-- attempt to get result from cache first
local cacheinfo = cache.load("find_program")
local result = cacheinfo[name]
@@ -154,7 +165,9 @@ function sandbox_lib_detect_find_program.main(name, pathes, check)
end
-- find executable program
+ checking = utils.ifelse(coroutine_running, name, nil)
result = sandbox_lib_detect_find_program._find(name, pathes, check)
+ checking = nil
-- cache result
cacheinfo[name] = utils.ifelse(result, result, false)
diff --git a/xmake/modules/lib/detect/has_cxsnippets.lua b/xmake/modules/lib/detect/has_cxsnippets.lua
index c00021bb9..233c43d83 100644
--- a/xmake/modules/lib/detect/has_cxsnippets.lua
+++ b/xmake/modules/lib/detect/has_cxsnippets.lua
@@ -185,6 +185,7 @@ function main(snippets, opt)
-- make the source file
local sourcefile = os.tmpfile() .. extension
local objectfile = os.tmpfile() .. ".o"
+ local binaryfile = os.tmpfile() .. ".b"
io.writefile(sourcefile, sourcecode)
-- attempt to compile it
@@ -193,7 +194,7 @@ function main(snippets, opt)
function ()
compiler.compile(sourcefile, objectfile, opt)
if #links > 0 then
- linker.link("binary", {"cc", "cxx"}, objectfile, os.nuldev(), opt)
+ linker.link("binary", {"cc", "cxx"}, objectfile, binaryfile, opt)
end
return true
end,
@@ -210,6 +211,7 @@ function main(snippets, opt)
-- remove some files
os.tryrm(sourcefile)
os.tryrm(objectfile)
+ os.tryrm(binaryfile)
-- trace
if opt.verbose or option.get("verbose") then