13.0.0 Release

Had an issue when managing branches... All fixed now
This commit is contained in:
2019-03-22 21:31:16 -04:00
parent 050549aeef
commit 87d8cfbb5b
19 changed files with 4155 additions and 2293 deletions
+8 -2
View File
@@ -1,7 +1,7 @@
--[[
MIT License
Copyright (c) 2018 Ryan Ward
Copyright (c) 2019 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -37,6 +37,7 @@ multi.OnMouseMoved = multi:newConnection()
multi.OnDraw = multi:newConnection()
multi.OnTextInput = multi:newConnection()
multi.OnUpdate = multi:newConnection()
multi.OnQuit = multi:newConnection()
multi.OnPreLoad(function()
local function Hook(func,conn)
if love[func]~=nil then
@@ -51,6 +52,7 @@ multi.OnPreLoad(function()
end
end
end
Hook("quit",multi.OnQuit)
Hook("keypressed",multi.OnKeyPressed)
Hook("keyreleased",multi.OnKeyReleased)
Hook("mousepressed",multi.OnMousePressed)
@@ -67,4 +69,8 @@ multi.OnPreLoad(function()
end
end)
end)
return multi
multi.OnQuit(function()
multi.Stop()
love.event.quit()
end)
return multi
+1154 -1263
View File
File diff suppressed because it is too large Load Diff
+63 -16
View File
@@ -1,7 +1,7 @@
--[[
MIT License
Copyright (c) 2018 Ryan Ward
Copyright (c) 2019 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -32,6 +32,8 @@ end
-- Step 1 get lanes
lanes=require("lanes").configure()
local multi = require("multi") -- get it all and have it on all lanes
multi.SystemThreads = {}
local thread = thread
multi.isMainThread=true
function multi:canSystemThread()
return true
@@ -39,10 +41,10 @@ end
function multi:getPlatform()
return "lanes"
end
-- Step 2 set up the linda objects
-- Step 2 set up the Linda objects
local __GlobalLinda = lanes.linda() -- handles global stuff
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
-- For convience a GLOBAL table will be constructed to handle requests
-- For convenience a GLOBAL table will be constructed to handle requests
local GLOBAL={}
setmetatable(GLOBAL,{
__index=function(t,k)
@@ -52,7 +54,7 @@ setmetatable(GLOBAL,{
__GlobalLinda:set(k,v)
end,
})
-- Step 3 rewrite the thread methods to use lindas
-- Step 3 rewrite the thread methods to use Lindas
local THREAD={}
function THREAD.set(name,val)
__GlobalLinda:set(name,val)
@@ -82,6 +84,9 @@ end
function THREAD.getCores()
return THREAD.__CORES
end
function THREAD.getThreads()
return GLOBAL.__THREADS__
end
if os.getOS()=="windows" then
THREAD.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else
@@ -93,6 +98,10 @@ end
function THREAD.getName()
return THREAD_NAME
end
function THREAD.getID()
return THREAD_ID
end
_G.THREAD_ID = 0
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
however, a linda recieve will in fact be a idle wait! So we use that and wrap it in a nice package]]
@@ -109,36 +118,74 @@ function THREAD.hold(n)
end
local rand = math.random(1,10000000)
-- Step 5 Basic Threads!
local threads = {}
local count = 1
local started = false
local livingThreads = {}
function multi:newSystemThread(name,func,...)
multi.InitSystemThreadErrorHandler()
rand = math.random(1,10000000)
local c={}
local __self=c
c.name=name
c.Name = name
c.Id = count
livingThreads[count] = {true,name}
local THREAD_ID = count
count = count + 1
c.Type="sthread"
c.creationTime = os.clock()
local THREAD_NAME=name
local function func2(...)
local multi = require("multi")
_G["THREAD_NAME"]=THREAD_NAME
_G["THREAD_ID"]=THREAD_ID
math.randomseed(rand)
func(...)
if _G.__Needs_Multi then
multi:mainloop()
end
THREAD.kill()
end
c.thread=lanes.gen("*", func2)(...)
function c:kill()
--self.status:Destroy()
self.thread:cancel()
print("Thread: '"..self.name.."' has been stopped!")
multi.print("Thread: '"..self.name.."' has been stopped!")
end
c.status=multi:newUpdater(multi.Priority_IDLE)
c.status.link=c
c.status:OnUpdate(function(self)
local v,err,t=self.link.thread:join(.001)
if err then
multi.OnError:Fire(self.link,err,"Error in systemThread: '"..self.link.name.."' <"..err..">")
self:Destroy()
end
end)
table.insert(multi.SystemThreads,c)
c.OnError = multi:newConnection()
GLOBAL["__THREADS__"]=livingThreads
return c
end
print("Integrated Lanes!")
multi.OnSystemThreadDied = multi:newConnection()
function multi.InitSystemThreadErrorHandler()
if started==true then return end
started = true
multi:newThread("ThreadErrorHandler",function()
local threads = multi.SystemThreads
while true do
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
for i=#threads,1,-1 do
local v,err,t=threads[i].thread:join(.001)
if err then
if err:find("Thread was killed!") then
livingThreads[threads[i].Id] = {false,threads[i].Name}
multi.OnSystemThreadDied:Fire(threads[i].Id)
GLOBAL["__THREADS__"]=livingThreads
table.remove(threads,i)
else
threads[i].OnError:Fire(threads[i],err,"Error in systemThread: '"..threads[i].name.."' <"..err..">")
livingThreads[threads[i].Id] = {false,threads[i].Name}
multi.OnSystemThreadDied:Fire(threads[i].Id)
GLOBAL["__THREADS__"]=livingThreads
table.remove(threads,i)
end
end
end
end
end)
end
multi.print("Integrated Lanes!")
multi.integration={} -- for module creators
multi.integration.GLOBAL=GLOBAL
multi.integration.THREAD=THREAD
+50 -6
View File
@@ -1,7 +1,7 @@
--[[
MIT License
Copyright (c) 2018 Ryan Ward
Copyright (c) 2019 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -34,6 +34,7 @@ multi.integration.love2d.ThreadBase=[[
tab={...}
__THREADID__=table.remove(tab,1)
__THREADNAME__=table.remove(tab,1)
THREAD_ID=table.remove(tab,1)
require("love.filesystem")
require("love.system")
require("love.timer")
@@ -167,6 +168,9 @@ end
function sThread.getName()
return __THREADNAME__
end
function sThread.getID()
return THREAD_ID
end
function sThread.kill()
error("Thread was killed!")
end
@@ -195,6 +199,7 @@ func=loadDump([=[INSERT_USER_CODE]=])(unpack(tab))
multi:mainloop()
]]
GLOBAL={} -- Allow main thread to interact with these objects as well
_G.THREAD_ID = 0
__proxy__={}
setmetatable(GLOBAL,{
__index=function(t,k)
@@ -214,9 +219,13 @@ setmetatable(GLOBAL,{
THREAD={} -- Allow main thread to interact with these objects as well
multi.integration.love2d.mainChannel=love.thread.getChannel("__MainChan__")
isMainThread=true
multi.SystemThreads = {}
function THREAD.getName()
return __THREADNAME__
end
function THREAD.getID()
return THREAD_ID
end
function ToStr(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false
depth = depth or 0
@@ -295,12 +304,19 @@ local function randomString(n)
end
return str
end
local count = 1
local livingThreads = {}
function multi:newSystemThread(name,func,...) -- the main method
multi.InitSystemThreadErrorHandler()
local c={}
c.name=name
c.Name = name
c.ID=c.name.."<ID|"..randomString(8)..">"
c.Id=count
count = count + 1
livingThreads[count] = {true,name}
c.thread=love.thread.newThread(multi.integration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func)))
c.thread:start(c.ID,c.name,...)
c.thread:start(c.ID,c.name,THREAD_ID,...)
function c:kill()
multi.integration.GLOBAL["__DIEPLZ"..self.ID.."__"]="__DIEPLZ"..self.ID.."__"
end
@@ -308,7 +324,7 @@ function multi:newSystemThread(name,func,...) -- the main method
end
function love.threaderror( thread, errorstr )
multi.OnError:Fire(thread,errorstr)
print("Error in systemThread: "..tostring(thread)..": "..errorstr)
multi.print("Error in systemThread: "..tostring(thread)..": "..errorstr)
end
local THREAD={}
function THREAD.set(name,val)
@@ -333,8 +349,7 @@ end
__channels__={}
multi.integration.GLOBAL=GLOBAL
multi.integration.THREAD=THREAD
updater=multi:newUpdater()
updater:OnUpdate(function(self)
updater=multi:newLoop(function(self)
local data=multi.integration.love2d.mainChannel:pop()
while data do
if type(data)=="string" then
@@ -365,8 +380,37 @@ updater:OnUpdate(function(self)
data=multi.integration.love2d.mainChannel:pop()
end
end)
multi.OnSystemThreadDied = multi:newConnection()
local started = false
function multi.InitSystemThreadErrorHandler()
if started==true then return end
started = true
multi:newThread("ThreadErrorHandler",function()
local threads = multi.SystemThreads
while true do
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
for i=#threads,1,-1 do
local v,err,t=threads[i].thread:join(.001)
if err then
if err:find("Thread was killed!") then
livingThreads[threads[i].Id] = {false,threads[i].Name}
multi.OnSystemThreadDied:Fire(threads[i].Id)
GLOBAL["__THREADS__"]=livingThreads
table.remove(threads,i)
else
threads[i].OnError:Fire(threads[i],err,"Error in systemThread: '"..threads[i].name.."' <"..err..">")
livingThreads[threads[i].Id] = {false,threads[i].Name}
multi.OnSystemThreadDied:Fire(threads[i].Id)
GLOBAL["__THREADS__"]=livingThreads
table.remove(threads,i)
end
end
end
end
end)
end
require("multi.integration.shared")
print("Integrated Love2d!")
multi.print("Integrated Love2d!")
return {
init=function(t)
if t then
+2 -2
View File
@@ -1,7 +1,7 @@
--[[
MIT License
Copyright (c) 2018 Ryan Ward
Copyright (c) 2019 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -114,7 +114,7 @@ local function _INIT(luvitThread,timer)
luvitThread.start(entry,package.path,name,c.func,...)
return c
end
print("Integrated Luvit!")
multi.print("Integrated Luvit!")
multi.integration={} -- for module creators
multi.integration.GLOBAL=GLOBAL
multi.integration.THREAD=THREAD
+53 -45
View File
@@ -1,7 +1,7 @@
--[[
MIT License
Copyright (c) 2018 Ryan Ward
Copyright (c) 2019 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@ SOFTWARE.
]]
local multi = require("multi")
local net = require("net")
require("bin")
local bin = require("bin")
bin.setBitsInterface(infinabits) -- the bits interface does not work so well, another bug to fix
-- Commands that the master and node will respect, max of 256 commands
@@ -42,6 +42,7 @@ local CMD_CONSOLE = 0x0B
local char = string.char
local byte = string.byte
-- Process to hold all of the networkManager's muilt objects
-- Helper for piecing commands
local function pieceCommand(cmd,...)
@@ -142,17 +143,20 @@ function multi:nodeManager(port)
server.OnDataRecieved(function(server,data,cid,ip,port)
local cmd = data:sub(1,1)
if cmd == "R" then
multi:newTLoop(function(loop)
if server.timeouts[cid]==true then
server.OnNodeRemoved:Fire(server.nodes[cid])
server.nodes[cid] = nil
server.timeouts[cid] = nil
loop:Destroy()
return
multi:newThread("Node Client Manager",function(loop)
while true do
if server.timeouts[cid]==true then
server.OnNodeRemoved:Fire(server.nodes[cid])
server.nodes[cid] = nil
server.timeouts[cid] = nil
thread.kill()
else
server.timeouts[cid] = true
server:send(cid,"ping")
end
thread.sleep(1)
end
server.timeouts[cid] = true
server:send(cid,"ping")
end,1)
end)
server.nodes[cid]=data:sub(2,-1)
server.OnNodeAdded:Fire(server.nodes[cid])
elseif cmd == "G" then
@@ -172,6 +176,7 @@ function multi:nodeManager(port)
end
-- The main driving force of the network manager: Nodes
function multi:newNode(settings)
multi:enableLoadDetection()
settings = settings or {}
-- Here we have to use the net library to broadcast our node across the network
math.randomseed(os.time())
@@ -189,21 +194,21 @@ function multi:newNode(settings)
node.hasFuncs = {}
node.OnError = multi:newConnection()
node.OnError(function(node,err,master)
print("ERROR",err,node.name)
multi.print("ERROR",err,node.name)
local temp = bin.new()
temp:addBlock(#node.name,2)
temp:addBlock(node.name)
temp:addBlock(#err,2)
temp:addBlock(err)
for i,v in pairs(node.connections) do
print(i)
multi.print(i)
v[1]:send(v[2],char(CMD_ERROR)..temp.data,v[3])
end
end)
if settings.managerDetails then
local c = net:newTCPClient(settings.managerDetails[1],settings.managerDetails[2])
if not c then
print("Cannot connect to the node manager! Ensuring broadcast is enabled!") settings.noBroadCast = false
multi.print("Cannot connect to the node manager! Ensuring broadcast is enabled!") settings.noBroadCast = false
else
c.OnDataRecieved(function(self,data)
if data == "ping" then
@@ -215,7 +220,7 @@ function multi:newNode(settings)
end
if not settings.preload then
if node.functions:getSize()~=0 then
print("We have function(s) to preload!")
multi.print("We have function(s) to preload!")
local len = node.functions:getBlock("n",1)
local name,func
while len do
@@ -265,14 +270,14 @@ function multi:newNode(settings)
node.queue:push(resolveData(dat))
elseif cmd == CMD_REG then
if not settings.allowRemoteRegistering then
print(ip..": has attempted to register a function when it is currently not allowed!")
multi.print(ip..": has attempted to register a function when it is currently not allowed!")
return
end
local temp = bin.new(dat)
local len = temp:getBlock("n",1)
local name = temp:getBlock("s",len)
if node.hasFuncs[name] then
print("Function already preloaded onto the node!")
multi.print("Function already preloaded onto the node!")
return
end
len = temp:getBlock("n",2)
@@ -283,7 +288,7 @@ function multi:newNode(settings)
local temp = bin.new(dat)
local len = temp:getBlock("n",1)
local name = temp:getBlock("s",len)
len = temp:getBlock("n",2)
len = temp:getBlock("n",4)
local args = temp:getBlock("s",len)
_G[name](unpack(resolveData(args)))
elseif cmd == CMD_TASK then
@@ -299,13 +304,13 @@ function multi:newNode(settings)
node.OnError:Fire(node,err,server)
end
elseif cmd == CMD_INITNODE then
print("Connected with another node!")
multi.print("Connected with another node!")
node.connections[dat]={server,ip,port}
multi.OnGUpdate(function(k,v)
server:send(ip,table.concat{char(CMD_GLOBAL),k,"|",v},port)
end)-- set this up
elseif cmd == CMD_INITMASTER then
print("Connected to the master!",dat)
multi.print("Connected to the master!",dat)
node.connections[dat]={server,ip,port}
multi.OnGUpdate(function(k,v)
server:send(ip,table.concat{char(CMD_GLOBAL),k,"|",v},port)
@@ -352,7 +357,7 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
if settings.managerDetails then
local client = net:newTCPClient(settings.managerDetails[1],settings.managerDetails[2])
if not client then
print("Cannot connect to the node manager! Ensuring broadcast listening is enabled!") settings.noBroadCast = false
multi.print("Warning: Cannot connect to the node manager! Ensuring broadcast listening is enabled!") settings.noBroadCast = false
else
client.OnDataRecieved(function(client,data)
local cmd = data:sub(1,1)
@@ -402,7 +407,7 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
temp:addBlock(CMD_CALL,1)
temp:addBlock(#name,1)
temp:addBlock(name,#name)
temp:addBlock(#args,2)
temp:addBlock(#args,4)
temp:addBlock(args,#args)
master:sendTo(node,temp.data)
end
@@ -436,12 +441,12 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
name = self:getRandomNode()
end
if name==nil then
multi:newTLoop(function(loop)
if name~=nil then
self:sendTo(name,char(CMD_TASK)..len..aData..len2..fData)
loop:Desrtoy()
end
end,.1)
multi:newEvent(function() return name~=nil end):OnEvent(function(evnt)
self:sendTo(name,char(CMD_TASK)..len..aData..len2..fData)
evnt:Destroy()
end):SetName("DelayedSendTask"):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(function(self)
self:Destroy()
end)
else
self:sendTo(name,char(CMD_TASK)..len..aData..len2..fData)
end
@@ -455,12 +460,12 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
name = "NODE_"..name
end
if self.connections[name]==nil then
multi:newTLoop(function(loop)
if self.connections[name]~=nil then
self.connections[name]:send(data)
loop:Destroy()
end
end,.1)
multi:newEvent(function() return self.connections[name]~=nil end):OnEvent(function(evnt)
self.connections[name]:send(data)
evnt:Destroy()
end):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(function(self)
self:Destroy()
end)
else
self.connections[name]:send(data)
end
@@ -495,16 +500,19 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
client.OnClientReady(function()
client:send(char(CMD_INITMASTER)..master.name) -- Tell the node that you are a master trying to connect
if not settings.managerDetails then
multi:newTLoop(function(loop)
if master.timeouts[name]==true then
master.timeouts[name] = nil
master.connections[name] = nil
loop:Destroy()
return
multi:newThread("Node Data Link Controller",function(loop)
while true do
if master.timeouts[name]==true then
master.timeouts[name] = nil
master.connections[name] = nil
thread.kill()
else
master.timeouts[name] = true
master:sendTo(name,char(CMD_PING))
end
thread.sleep(1)
end
master.timeouts[name] = true
master:sendTo(name,char(CMD_PING))
end,1)
end)
end
client.name = name
client.OnDataRecieved(function(client,data)
@@ -542,7 +550,7 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
return master
end
-- The init function that gets returned
print("Integrated Network Parallelism")
multi.print("Integrated Network Parallelism")
return {init = function()
return GLOBAL
end}
+134 -66
View File
@@ -1,7 +1,7 @@
--[[
MIT License
Copyright (c) 2018 Ryan Ward
Copyright (c) 2019 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -112,30 +112,37 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
end
return c
end
function multi:newSystemThreadedConnection(name,protect)
local c={}
c.name = name or error("You must provide a name for the connection object!")
c.protect = protect or false
c.idle = nil
local sThread=multi.integration.THREAD
local GLOBAL=multi.integration.GLOBAL
c.name = name or error("You must supply a name for this object!")
c.protect = protect or false
c.count = 0
multi:newSystemThreadedQueue(name.."THREADED_CALLFIRE"):init()
local qsm = multi:newSystemThreadedQueue(name.."THREADED_CALLSYNCM"):init()
local qs = multi:newSystemThreadedQueue(name.."THREADED_CALLSYNC"):init()
local connSync = multi:newSystemThreadedQueue(c.name.."_CONN_SYNC")
local connFire = multi:newSystemThreadedQueue(c.name.."_CONN_FIRE")
function c:init()
local multi = require("multi")
if multi:getPlatform()=="love2d" then
if love then -- lets make sure we don't reference up-values if using love2d
GLOBAL=_G.GLOBAL
sThread=_G.sThread
end
local conns = 0
local qF = sThread.waitFor(self.name.."THREADED_CALLFIRE"):init()
local qSM = sThread.waitFor(self.name.."THREADED_CALLSYNCM"):init()
local qS = sThread.waitFor(self.name.."THREADED_CALLSYNC"):init()
qSM:push("OK")
local conn = {}
conn.obj = multi:newConnection(self.protect)
setmetatable(conn,{__call=function(self,...) return self:connect(...) end})
conn.obj = multi:newConnection()
setmetatable(conn,{
__call=function(self,...)
return self:connect(...)
end
})
local ID = sThread.getID()
local sync = sThread.waitFor(self.name.."_CONN_SYNC"):init()
local fire = sThread.waitFor(self.name.."_CONN_FIRE"):init()
local connections = {}
if not multi.isMainThread then
connections = {0}
end
sync:push{"INIT",ID} -- Register this as an active connection!
function conn:connect(func)
return self.obj(func)
end
@@ -146,54 +153,98 @@ function multi:newSystemThreadedConnection(name,protect)
self.obj:Remove()
end
function conn:Fire(...)
local args = {multi.randomString(8),...}
for i = 1, conns do
qF:push(args)
for i = 1,#connections do
fire:push{connections[i],ID,{...}}
end
end
local lastID = ""
local lastCount = 0
multi:newThread("syncer",function()
while true do
thread.skip(1)
local fire = qF:peek()
local count = qS:peek()
if fire and fire[1]~=lastID then
lastID = fire[1]
qF:pop()
table.remove(fire,1)
conn.obj:Fire(unpack(fire))
end
if count and count[1]~=lastCount then
conns = count[2]
lastCount = count[1]
qs:pop()
function conn:FireTo(to,...)
local good = false
for i = 1,#connections do
if connections[i]==to then
good = true
break
end
end
end)
if not good then return multi.print("NonExisting Connection!") end
fire:push{to,ID,{...}}
end
-- FIRE {TO,FROM,{ARGS}}
local data
local clock = os.clock
conn.OnConnectionAdded = multi:newConnection()
multi:newLoop(function()
data = fire:peek()
if type(data)=="table" and data[1]==ID then
if data[2]==ID and conn.IgnoreSelf then
fire:pop()
return
end
fire:pop()
conn.obj:Fire(unpack(data[3]))
end
data = sync:peek()
if data~=nil and data[1]=="SYNCA" and data[2]==ID then
sync:pop()
multi.nextStep(function()
conn.OnConnectionAdded:Fire(data[3])
end)
table.insert(connections,data[3])
end
if type(data)=="table" and data[1]=="SYNCR" and data[2]==ID then
sync:pop()
for i=1,#connections do
if connections[i] == data[3] then
table.remove(connections,i)
end
end
end
end):setName("STConn.syncer")
return conn
end
multi:newThread("connSync",function()
local cleanUp = {}
multi.OnSystemThreadDied(function(ThreadID)
for i=1,#syncs do
connSync:push{"SYNCR",syncs[i],ThreadID}
end
cleanUp[ThreadID] = true
end)
multi:newThread(c.name.." Connection-Handler",function()
local data
local clock = os.clock
local syncs = {}
while true do
thread.skip(1)
local syncIN = qsm:pop()
if syncIN then
if syncIN=="OK" then
c.count = c.count + 1
else
c.count = c.count - 1
if not c.idle then
thread.sleep(.5)
else
if clock() - c.idle >= 15 then
c.idle = nil
end
local rand = math.random(1,1000000)
for i = 1, c.count do
qs:push({rand,c.count})
thread.skip()
end
data = connSync:peek()
if data~= nil and data[1]=="INIT" then
connSync:pop()
c.idle = clock()
table.insert(syncs,data[2])
for i=1,#syncs do
connSync:push{"SYNCA",syncs[i],data[2]}
end
end
data = connFire:peek()
if data~=nil and cleanUp[data[1]] then
local meh = data[1]
connFire:pop() -- lets remove dead thread stuff
multi:newAlarm(15):OnRing(function(a)
cleanUp[meh] = nil
end)
end
end
end)
GLOBAL[name]=c
GLOBAL[c.name]=c
return c
end
function multi:systemThreadedBenchmark(n)
function multi:SystemThreadedBenchmark(n)
n=n or 1
local cores=multi.integration.THREAD.getCores()
local queue=multi:newSystemThreadedQueue("THREAD_BENCH_QUEUE"):init()
@@ -211,6 +262,7 @@ function multi:systemThreadedBenchmark(n)
multi:benchMark(n):OnBench(function(self,count)
queue:push(count)
sThread.kill()
error("Thread was killed!")
end)
multi:mainloop()
end,n)
@@ -240,6 +292,7 @@ function multi:newSystemThreadedConsole(name)
local sThread=multi.integration.THREAD
local GLOBAL=multi.integration.GLOBAL
function c:init()
_G.__Needs_Multi = true
local multi = require("multi")
if multi:getPlatform()=="love2d" then
GLOBAL=_G.GLOBAL
@@ -247,10 +300,10 @@ function multi:newSystemThreadedConsole(name)
end
local cc={}
if multi.isMainThread then
if GLOBAL["__SYSTEM_CONSLOE__"] then
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
if GLOBAL["__SYSTEM_CONSOLE__"] then
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
else
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSLOE__"):init()
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSOLE__"):init()
multi:newLoop(function()
local data = cc.stream:pop()
if data then
@@ -261,10 +314,10 @@ function multi:newSystemThreadedConsole(name)
print(unpack(data))
end
end
end)
end):setName("ST.consoleSyncer")
end
else
cc.stream = sThread.waitFor("__SYSTEM_CONSLOE__"):init()
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
end
function cc:write(msg)
self.stream:push({"w",tostring(msg)})
@@ -281,12 +334,14 @@ function multi:newSystemThreadedConsole(name)
GLOBAL[c.name]=c
return c
end
-- NEEDS WORK
function multi:newSystemThreadedTable(name)
local c={}
c.name=name -- set the name this is important for identifying what is what
local sThread=multi.integration.THREAD
local GLOBAL=multi.integration.GLOBAL
function c:init() -- create an init function so we can mimic on both love2d and lanes
_G.__Needs_Multi = true
local multi = require("multi")
if multi:getPlatform()=="love2d" then
GLOBAL=_G.GLOBAL
@@ -324,14 +379,16 @@ function multi:newSystemThreadedTable(name)
return c
end
local jobqueuecount = 0
local jqueues = {}
function multi:newSystemThreadedJobQueue(a,b)
jobqueuecount=jobqueuecount+1
local GLOBAL=multi.integration.GLOBAL
local sThread=multi.integration.THREAD
local c = {}
c.numberofcores = 4
c.idle = nil
c.name = "SYSTEM_THREADED_JOBQUEUE_"..jobqueuecount
-- This is done to keep backwards compatability for older code
-- This is done to keep backwards compatibility for older code
if type(a)=="string" and not(b) then
c.name = a
elseif type(a)=="number" and not (b) then
@@ -343,6 +400,10 @@ function multi:newSystemThreadedJobQueue(a,b)
c.name = b
c.numberofcores = a
end
if jqueues[c.name] then
error("A job queue by the name: "..c.name.." already exists!")
end
jqueues[c.name] = true
c.isReady = false
c.jobnum=1
c.OnJobCompleted = multi:newConnection()
@@ -359,6 +420,7 @@ function multi:newSystemThreadedJobQueue(a,b)
end
c.tempQueue = {}
function c:pushJob(name,...)
c.idle = os.clock()
if not self.isReady then
table.insert(c.tempQueue,{self.jobnum,name,...})
self.jobnum=self.jobnum+1
@@ -370,8 +432,9 @@ function multi:newSystemThreadedJobQueue(a,b)
end
end
function c:doToAll(func)
local r = multi.randomString(12)
for i = 1, self.numberofcores do
queueDA:push{multi.randomString(12),func}
queueDA:push{r,func}
end
end
for i=1,c.numberofcores do
@@ -425,12 +488,9 @@ function multi:newSystemThreadedJobQueue(a,b)
end
end
end)
multi:newThread("Idler",function()
while true do
if os.clock()-lastjob>1 then
sThread.sleep(.1)
end
thread.sleep(.001)
multi:newLoop(function()
if os.clock()-lastjob>1 then
sThread.sleep(.1)
end
end)
setmetatable(_G,{
@@ -443,11 +503,11 @@ function multi:newSystemThreadedJobQueue(a,b)
end
end,c.name)
end
multi:newThread("counter",function()
print("thread started")
local clock = os.clock
multi:newThread("JQ-"..c.name.." Manager",function()
local _count = 0
while _count<c.numberofcores do
thread.skip(1)
thread.skip()
if queueCC:pop() then
_count = _count + 1
end
@@ -460,9 +520,17 @@ function multi:newSystemThreadedJobQueue(a,b)
c.OnReady:Fire(c)
local dat
while true do
thread.skip(1)
if not c.idle then
thread.sleep(.5)
else
if clock() - c.idle >= 15 then
c.idle = nil
end
thread.skip()
end
dat = queueJD:pop()
if dat then
c.idle = clock()
c.OnJobCompleted:Fire(unpack(dat))
end
end