diff options
| author | ruki <[email protected]> | 2017-06-29 10:23:38 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2017-06-29 10:23:38 +0800 |
| commit | 741d881be8b5f0ba62dd38bdb5f7fe32909f1263 (patch) | |
| tree | 3e2a479cd5a482eae1da00614dacd037edf3fb20 | |
| parent | c45a4613ce40f939b52c2ccd883712ff30d54dcc (diff) | |
avoid detect the same program in the same time leading to deadlock
| -rw-r--r-- | core/src/xmake/process/waitlist.c | 2 | ||||
| -rw-r--r-- | xmake/core/base/process.lua | 104 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/detect/find_program.lua | 13 | ||||
| -rw-r--r-- | xmake/modules/lib/detect/has_cxsnippets.lua | 4 |
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 |
