local mt = {} mt.newPool = function() local pool = {} pool.threads = {} -- indexed by coroutines, contains their metadata pool.namedThreads = {} -- indexed by coroutine names, contains their metadata also. -- coroutines are named if their metadata has a name field. pool.threadcount = 0 -- used for detecting when all things in a pool are depleted pool.clear = function() pool.threads = {} pool.namedThreads = {} pool.threadcount = 0 end pool.add = function(fn, options) options = options or {} options.co = coroutine.create(fn) pool.threads[options.co] = options if options.name then pool.namedThreads[options.name] = options end pool.threadcount = pool.threadcount + 1 os.queueEvent("pool_fn_added",options,pool) return options.co end pool.rm = function(name) if not pool.namedThreads[name] then return false end pool.threads[pool.namedThreads[name].co] = nil pool.namedThreads[name] = nil pool.threadcount = pool.threadcount - 1 return true end pool.addFile = function(filename, options) pool.add(function() dofile(filename) end,options) end pool.run = function(terminable) terminable = terminable or true -- if false, terminate events will be echoed to coroutines instead of -- terminating this pool while true do local event = {coroutine.yield()} if event[1] == "terminate" and terminable then return end for thread, options in pairs(pool.threads) do if coroutine.status(thread) ~= "dead" then if event[1] == options.filter or options.filter == nil then local x,e,y = pcall(coroutine.resume,thread,unpack(event)) options.filter = y if not x then os.queueEvent("pool_fn_crash",e,options,pool) pool.threadcount = pool.threadcount - 1 end end else os.queueEvent("pool_fn_end",options,pool) pool.threadcount = pool.threadcount - 1 pool.threads[thread] = nil end end if pool.threadcount == 0 then return end end end return pool end return mt