-- https://github.com/cloudwu/skynet/pull/1419
local skynet = require "skynet"

local coroutine = coroutine
local assert = assert
local tinsert = table.insert
local tremove = table.remove
local setmetatable = setmetatable

-- local scope_lock<close> = lock()

function skynet.lock()
    local current_thread
    local ref = 0
    local thread_queue = {}

    local scope_lock = setmetatable({}, {
        __close = function()
            ref = ref - 1
            if ref == 0 then
                current_thread = tremove(thread_queue, 1)
                if current_thread then
                    skynet.wakeup(current_thread)
                end
            end
        end,
    })

    return function()
        local thread = coroutine.running()
        if current_thread and current_thread ~= thread then
            tinsert(thread_queue, thread)
            skynet.wait()
            assert(ref == 0) -- current_thread == thread
        end
        current_thread = thread

        ref = ref + 1
        return scope_lock
    end
end

return skynet.lock
