From 474ad6438f32316a08168c6d2b6e02d7ce958b31 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Tue, 30 Dec 2025 15:14:34 -0500 Subject: [PATCH] V16.1.0 (#69) * Fixed issue with pushstatus * added newTimeout * updated changes and added multi.isTimeout function * new mod feature, helper functions for types and connections * cleaning up * Updated changes.md, enhanced processors * updated docs, added multi.UUID * updated testfile --- README.md | 10 +- docs/changes.md | 126 ++++++++++++- init.lua | 257 +++++++++++++++++++++----- integration/stateManager/init.lua | 1 + tests/runtests.lua | 2 + tests/test.lua | 298 ------------------------------ 6 files changed, 348 insertions(+), 346 deletions(-) create mode 100644 integration/stateManager/init.lua delete mode 100644 tests/test.lua diff --git a/README.md b/README.md index dbec4df..01e9199 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ -# Multi Version: 16.0.1 - Bug fix +# Multi Version: 16.1.0 - The Flow State +**Key Changes** +- Updated Processors to have more controlled over scheduled processes +- Forwarding connections +- New Timeout handling + +Refer to the [Change Log](https://github.com/rayaman/multi/blob/master/docs/changes.md) for more infromation Found an issue? Please [submit it](https://github.com/rayaman/multi/issues) and someone will look into it! @@ -45,7 +51,7 @@ Planned features/TODO - [x] ~~Create test suite (In progress, mostly done)~~ - [ ] Network Parallelism rework -Usage: [Check out the documentation for more info](https://github.com/rayaman/multi/blob/master/Documentation.md) +Usage: [Check out the documentation for more info](https://github.com/rayaman/multi/blob/master/docs/Documentation.md) ----- You can run tests in 2 ways: diff --git a/docs/changes.md b/docs/changes.md index 2b2a6d6..3c3dd05 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,7 +1,8 @@ # Changelog Table of contents --- -[Update 16.0.1 - Bug fix](#update-1531---bug-fix)
+[Update 16.1.0 - The Flow State](#update-1610---the-flow-state)
+[Update 16.0.1 - Bug fix](#update-1601---bug-fix)
[Update 16.0.0 - Connecting the dots](#update-1600---getting-the-priorities-straight)
[Update 15.3.1 - Bug fix](#update-1531---bug-fix)
[Update 15.3.0 - A world of connections](#update-1530---a-world-of-connections)
@@ -59,6 +60,129 @@ Table of contents [Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)
[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different) +# Update 16.1.0 - The Flow State +Added +--- +- `multi.UUID()` generates a uuid7, if chronos is installed that will be used as the initial time seed +- `More control over processors` + - `multi:newProcessor(name, opts, priority)` -- Now accepts a opts table. Old param still works + + | Option | Description | Default | + | --- | --- | --- | + | Attach | If true a hook will be attached to the parent process and will run when Start is called or Start is set | false | + | MaxObjects | Maximum number of objects that a processor can spawn | -1 (disabled) | + | MaxThreads | Maximum number of threads that a processor can spawn | -1 (disabled) | + | Start | If true the processor will start instantlly | false | + | Priority | If true the processor will use the priority handler | false | + | TaskDelay | Sets the task delay in seconds between each tasks execution | 0 | + | TashHandler | If false will disable the task feature of a processor | true | + - `proc:newThread()` returns nil, "errorstring" if it was unable to create a thread + - `proc:new[Object]` now returns {unscheduled}, "errorstring", used to just return the {scheduledObject} and no errorstring + - `proc:getMaxThreads()` -- returns the max thread limit + - `proc:setMaxThreads(n)` -- sets the max thread limit + - `proc:getMaxObjects()` -- gets the max object limit + - `proc:setMaxObjects(n)` -- sets the max object limit + - `proc.Status` -- A table that contains all status errors that occured in a process + Example: + ```lua + local multi, thread = require("multi"):init() + + proc = multi:newProcessor("thread test",{ + Start = true, + MaxThreads = 1, + MaxObjects = 1, + Attach = true, + TaskDelay = .1, + Priority = true, + TaskHandler = false + }) + + print(proc:newThread("testing",function() + while true do + print("STATUS:\n---") + for i,v in ipairs(proc.Status) do + print(i,v) + end + thread.sleep(1) + end + end)) + proc:newThread("testing 2",function() + while true do + print("testing 2...") + thread.sleep(1) + end + end) + proc:newThread("testing 3",function() + while true do + print("testing 3...") + thread.sleep(1) + end + end) + + proc:newLoop(function() + -- + end) + + print(proc:newLoop(function() + -- + end)) + + multi:mainloop() + ``` +- `multi.hasType(typ)` returns true if a type has been registered +- `multi.isMultiObj(obj)` returns true if the object is a multi object +- `multi.forwardConnection(src, dest)` forwards events from one connection to another connection. Doesn't modify anything and both connections are triggered when src is Fired, but not when dest is fired. +- `multi.isTimeout(res)` returns true if the response it gets is a timeout type or a string equal to `multi.TIMEOUT`'s value +- `multi:newTimeout(seconds)` returns a connection that will trigger after a certain amount of time. See example below: +```lua +local multi, thread = require("multi"):init() + +data = multi:newConnection() + +-- This alarm takes too long... We will timeout +multi:newAlarm(4):OnRing(function() + data:Fire({Type="request"},"data is tasty") +end) + +multi:newThread(function() + res, data = thread.hold(data + multi:newTimeout(3)) -- combined connections allow this to work + if multi.isTimeout(res) then + print("We timed out!") + else + print("We got the data:", data) + end + os.exit() +end) + +multi:mainloop() +``` +- `connection % function` can now modify the arguments of a connection. See above example modified below +```lua +local multi, thread = require("multi"):init() + +local data = multi:newAlarm(1).OnRing % function() return {Type="request"}, "data is tasty" end + +multi:newThread(function() + res, data = thread.hold(data + multi:newTimeout(3)) + if multi.isTimeout(res) then + print("We timed out!") + else + print("We got the data:", data) + end + os.exit() +end) + +multi:mainloop() +``` + +If the alarm takes longer the the timeout: `We timed out!` If the alarm is shorter: `We got the data: data is tasty` + +Changed +--- +- `multi:newBase(tp,ins,callback)` now accepts a tp param and a callback function. Callback is expected to return true/false, errorstring. If callback is false it will cancel scheduling of an object. If type is set the type of the object will be set. + + **Note:** This is all internal functionality + # Update 16.0.1 - Bug fix Fixed --- diff --git a/init.lua b/init.lua index 9543ce5..508f240 100644 --- a/init.lua +++ b/init.lua @@ -76,17 +76,23 @@ end local types = {} function multi.registerType(typ, p) - if multi[typ:upper():gsub("_","")] then return typ end - multi[typ:upper():gsub("_","")] = typ + if multi["$"..typ:upper():gsub("_","")] then return typ end + multi["$"..typ:upper():gsub("_","")] = typ table.insert(types, {typ, p or typ}) return typ end +function multi.hasType(typ) + if multi["$"..typ:upper():gsub("_","")] then + return multi["$"..typ:upper():gsub("_","")] + end +end + function multi.getTypes() return types end -multi.Version = "16.0.1" +multi.Version = "16.1.0" multi.Name = "root" multi.NIL = {Type="NIL"} local NIL = multi.NIL @@ -95,7 +101,7 @@ multi.Children = {} multi.Active = true multi.Type = multi.registerType("rootprocess") multi.LinkedPath = multi -multi.TIMEOUT = "TIMEOUT" +multi.TIMEOUT = multi.registerType("TIMEOUT", "timeouts") multi.TID = 0 multi.defaultSettings = {} @@ -185,9 +191,29 @@ function multi.randomString(n) return str end +function multi.isMulitObj(obj) + if type(obj)=="table" then + if obj.Type ~= nil then + return multi.hasType(obj.Type) ~= nil + end + end + return false +end + +function multi.forwardConnection(src, dest) + if multi.isMulitObj(src) and multi.isMulitObj(dest) then + src(function(...) + dest:Fire(...) + end) + else + multi.error("Cannot forward non-connection objects") + end +end + local optimization_stats = {} local ignoreconn = true local empty_func = function() end + function multi:newConnection(protect,func,kill) local processor = self local c={} @@ -221,6 +247,7 @@ function multi:newConnection(protect,func,kill) for i = #conns, 1, -1 do obj.rawadd = true obj(conns[i]) + obj.rawadd = false end return obj end, @@ -230,6 +257,22 @@ function multi:newConnection(protect,func,kill) obj2(function(...) cn:Fire(obj1(...)) end) + elseif type(obj1) == "table" and type(obj2) == "function" then + local conns = obj1:Bind({}) + for i = 1,#conns do + obj1(function(...) + conns[i](obj2(...)) + end) + end + obj1.__connectionAdded = function(conn, func) + obj1:Unconnect(conn) + obj1.rawadd = true + obj1:Connect(function(...) + func(obj2(...)) + end) + obj1.rawadd = false + end + return obj1 else error("Invalid mod!", type(obj1), type(obj2),"Expected function, connection(table)") end @@ -277,6 +320,7 @@ function multi:newConnection(protect,func,kill) end end) end + return obj1 elseif type(obj1) == "table" and type(obj2) == "table" then -- else @@ -492,6 +536,10 @@ function multi:newConnection(protect,func,kill) return temp end + function c:Get() + return fast + end + function c:Remove() local temp = fast fast={} @@ -554,8 +602,7 @@ end -- Advance Timer stuff function multi:SetTime(n) if not n then n=3 end - local c=self:newBase() - c.Type=multi.registerType("timemaster") + local c,err=self:newBase(multi.registerType("timemaster")) c.timer=self:newTimer() c.timer:Start() c.set=n @@ -571,7 +618,7 @@ function multi:SetTime(n) return true end end - return self + return self,err end function multi:ResolveTimer(...) @@ -651,8 +698,49 @@ function multi:isDone() return self.Active~=true end +local time = os.time +local ok, chronos = pcall(require, "chronos") -- hpc + +if ok then + math.randomseed(chronos.nanotime()*1000000000) +else + math.randomseed(time()) +end + +function multi.UUID() + + -- random bytes + local value = {} + for i = 1, 16 do + value[i] = math.random(0, 255) + end + + -- current timestamp in ms + local timestamp = time() * 1000 + + -- timestamp + value[1] = (timestamp >> 40) & 0xFF + value[2] = (timestamp >> 32) & 0xFF + value[3] = (timestamp >> 24) & 0xFF + value[4] = (timestamp >> 16) & 0xFF + value[5] = (timestamp >> 8) & 0xFF + value[6] = timestamp & 0xFF + + -- version and variant + value[7] = (value[7] & 0x0F) | 0x70 + value[9] = (value[9] & 0x3F) | 0x80 + res = "" + for i = 1, #value do + res = res .. string.format('%02x', value[i]) + if i == 4 or i == 6 or i == 8 or i == 10 then + res = res .. "-" + end + end + return res +end + function multi:create(ref) - ref.UID = "U"..multi.randomString(12) + ref.UID = self.UUID() self.OnObjectCreated:Fire(ref, self) return self end @@ -664,7 +752,7 @@ end --Constructors [CORE] local _tid = 0 -function multi:newBase(ins) +function multi:newBase(tp,ins,callback) if not(self.Type==multi.registerType("rootprocess") or self.Type==multi.registerType("process", "processes")) then multi.error('Can only create an object on multi or an interface obj') return false end local c = {} if self.Type==multi.registerType("process", "processes") then @@ -682,6 +770,7 @@ function multi:newBase(ins) c.Act=function() end c.Parent=self c.creationTime = clock() + c.Type = tp function c:Pause() c.Parent.Pause(self) @@ -692,16 +781,30 @@ function multi:newBase(ins) c.Parent.Resume(self) return self end + + _tid = _tid + 1 -- Even if the task isn't scheduled, we want to increment this + + if type(callback) == "function" then + local res, err = callback(tp) + if not res then + return c, err + end + end if ins then table.insert(self.Mainloop,ins,c) else table.insert(self.Mainloop,c) end - _tid = _tid + 1 return c end +function multi:newTimeout(timeout) + local c={} + c.Type = multi.registerType(multi.TIMEOUT, "timeouts") + return function(self) self:Destroy() return c end % self:newAlarm(timeout).OnRing +end + function multi:newTimer() local c={} c.Type=multi.registerType("timer", "timers") @@ -736,8 +839,7 @@ end --Core Actors function multi:newEvent(task, func) - local c=self:newBase() - c.Type=multi.registerType("event", "events") + local c,err=self:newBase(multi.registerType("event", "events")) local task = task or function() end function c:Act() local t = task(self) @@ -759,12 +861,11 @@ function multi:newEvent(task, func) self:setPriority("core") c:setName(c.Type) self:create(c) - return c + return c,err end function multi:newUpdater(skip, func) - local c=self:newBase() - c.Type=multi.registerType("updater", "updaters") + local c,err=self:newBase(multi.registerType("updater", "updaters")) local pos = 1 local skip = skip or 1 function c:Act() @@ -785,12 +886,11 @@ function multi:newUpdater(skip, func) c.OnUpdate(func) end self:create(c) - return c + return c,err end function multi:newAlarm(set, func) - local c=self:newBase() - c.Type=multi.registerType("alarm", "alarms") + local c,err=self:newBase(multi.registerType("alarm", "alarms")) c:setPriority("Low") c.set=set or 0 local count = 0 @@ -826,12 +926,11 @@ function multi:newAlarm(set, func) end c:setName(c.Type) self:create(c) - return c + return c,err end function multi:newLoop(func, notime) - local c=self:newBase() - c.Type = multi.registerType("loop", "loops") + local c,err=self:newBase(multi.registerType("loop", "loops")) local start=clock() if notime then function c:Act() @@ -853,13 +952,12 @@ function multi:newLoop(func, notime) self:create(c) c:setName(c.Type) - return c + return c,err end function multi:newStep(start,reset,count,skip) - local c=self:newBase() + local c,err=self:newBase(multi.registerType("step", "steps")) think=1 - c.Type=multi.registerType("step", "steps") c.pos=start or 1 c.endAt=reset or math.huge c.skip=skip or 0 @@ -913,12 +1011,11 @@ function multi:newStep(start,reset,count,skip) end c:setName(c.Type) self:create(c) - return c + return c,err end function multi:newTLoop(func, set) - local c=self:newBase() - c.Type=multi.registerType("tloop", "tloops") + local c,err=self:newBase(multi.registerType("tloop", "tloops")) c.set=set or 0 c.timer=self:newTimer() c.life=0 @@ -959,7 +1056,7 @@ function multi:newTLoop(func, set) self:create(c) - return c + return c,err end function multi:setTimeout(func, t) @@ -1079,10 +1176,38 @@ end local sandcount = 1 -function multi:newProcessor(name, nothread, priority) +function multi:newProcessor(name, opts, priority) + local nothread, attach + if type(opts) ~= "table" then + attach = not opts + nothread = opts -- support old params + end local c = {} + c.Status = {} setmetatable(c,{__index = multi}) local name = name or "Processor_" .. sandcount + local maxThreads = -1 + local maxObjects = -1 + local taskhandler = true + + rootBase = multi.newBase + + local function setStatus(status) + table.insert(c.Status,status) + return status + end + + local callback = function(tp) + if maxObjects <0 or #c.Mainloop < maxObjects then + return true + end + return false, setStatus(string.format("Unable to create [%s]: MAX_OBJECTS: '%d' current scheduled objects: '%d'", tp, maxObjects, #c.Mainloop)) + end + + function c:newBase(tp,ins) + return rootBase(self,tp,ins,callback) + end + sandcount = sandcount + 1 c.Mainloop = {} c.Type = multi.registerType("process", "processes") @@ -1098,13 +1223,25 @@ function multi:newProcessor(name, nothread, priority) local boost = 1 local handler + if type(opts) == "table" then + priority = opts.Priority or false + Active = opts.Start or false + maxThreads = opts.MaxThreads or -1 + maxObjects = opts.MaxObjects or -1 + task_delay = opts.TaskDelay or 0 + attach = opts.Attach or false + if opts.TaskHandler == false then -- The default was true + taskhandler = false + end + end + if priority then handler = c:createPriorityHandler(c) else handler = c:createHandler(c) end - if not nothread then -- Don't create a loop if we are triggering this manually + if attach then -- Don't create a loop if we are triggering this manually c.process = self:newLoop(function() if Active then c:uManager(true) @@ -1138,7 +1275,10 @@ function multi:newProcessor(name, nothread, priority) end function c:newThread(name, func,...) - return thread.newThread(c, name, func, ...) + if maxThreads < 0 or (#c.threads+#c.startme < maxThreads) then + return thread.newThread(c, name, func, ...) + end + return nil, setStatus(string.format("Unable to create [thread]: '%s' MAX_THREADS: '%d' current scheduled threads: '%d'",name,maxThreads,#c.threads+#c.startme)) end function c:newFunction(func, holdme) @@ -1147,6 +1287,24 @@ function multi:newProcessor(name, nothread, priority) end, holdme)() end + function c:getMaxThreads() + return maxThreads + end + + function c:setMaxThreads(n) + maxThreads = n + return c + end + + function c:getMaxObjects() + return maxObjects + end + + function c:setMaxObjects(n) + maxObjects = n + return c + end + function c:boost(count) boost = count or 1 if boost > 1 then @@ -1202,22 +1360,24 @@ function multi:newProcessor(name, nothread, priority) end end - c:newThread("Task Handler", function() - local self = multi:getCurrentProcess() - local function task_holder() - return #self.tasks > 0 - end - while true do - if #self.tasks > 0 then - table.remove(self.tasks,1)() - else - thread.hold(task_holder) + if taskhandler then + c:newThread("Task Handler", function() + local self = multi:getCurrentProcess() + local function task_holder() + return #self.tasks > 0 end - if task_delay~=0 then - thread.hold(task_delay) + while true do + if #self.tasks > 0 then + table.remove(self.tasks,1)() + else + thread.hold(task_holder) + end + if task_delay~=0 then + thread.hold(task_delay) + end end - end - end).OnError(multi.error) + end).OnError(multi.error) + end table.insert(processes,c) self:create(c) @@ -2228,6 +2388,13 @@ end -- UTILS -------- +function multi.isTimeout(res) + if type(res) == "table" then + return res.Type == multi.TIMEOUT + end + return res == multi.TIMEOUT +end + function table.merge(t1, t2) for k,v in pairs(t2) do if type(v) == 'table' then diff --git a/integration/stateManager/init.lua b/integration/stateManager/init.lua new file mode 100644 index 0000000..2f9e653 --- /dev/null +++ b/integration/stateManager/init.lua @@ -0,0 +1 @@ +-- Allows the creation of states \ No newline at end of file diff --git a/tests/runtests.lua b/tests/runtests.lua index c5b7c13..2e5726e 100644 --- a/tests/runtests.lua +++ b/tests/runtests.lua @@ -4,6 +4,8 @@ local multi, thread = require("multi"):init{print=true,warn=true,error=true}--{p local good = false local proc = multi:newProcessor("Test") +print("Version: "..multi.Version) + proc.Start() proc:newAlarm(3):OnRing(function() diff --git a/tests/test.lua b/tests/test.lua deleted file mode 100644 index d5056db..0000000 --- a/tests/test.lua +++ /dev/null @@ -1,298 +0,0 @@ -package.path = "../?/init.lua;../?.lua;"..package.path -multi, thread = require("multi"):init{print=true,warn=true,debugging=true} --- for i,v in pairs(thread) do --- print(i,v) --- end - --- require("multi.integration.priorityManager") - --- multi.debugging.OnObjectCreated(function(obj, process) --- multi.print("Created:", obj.Type, "in", process.Type, process:getFullName()) --- end) - --- multi.debugging.OnObjectDestroyed(function(obj, process) --- multi.print("Destroyed:", obj.Type, "in", process.Type, process:getFullName()) --- end) - - --- test = multi:newProcessor("Test") --- test:setPriorityScheme(multi.priorityScheme.TimeBased) - --- test:newUpdater(10000000):OnUpdate(function() --- print("Print is slowish") --- end) - --- print("Running...") - --- local conn1, conn2 = multi:newConnection(), multi:newConnection() --- conn3 = conn1 + conn2 - --- conn1(function() --- print("Hi 1") --- end) - --- conn2(function() --- print("Hi 2") --- end) - --- conn3(function() --- print("Hi 3") --- end) - --- function test(a,b,c) --- print("I run before all and control if execution should continue!") --- return a>b --- end - --- conn4 = test .. conn1 - --- conn5 = conn2 .. function() print("I run after it all!") end - --- conn4:Fire(3,2,3) --- -- This second one won't trigger the Hi's --- conn4:Fire(1,2,3) - --- conn5(function() --- print("Test 1") --- end) - --- conn5(function() --- print("Test 2") --- end) - --- conn5(function() --- print("Test 3") --- end) - --- conn5:Fire() - - - - --- multi.print("Testing thread:newProcessor()") - --- proc = thread:newProcessor("Test") - --- proc:newLoop(function() --- multi.print("Running...") --- thread.sleep(1) --- end) - --- proc:newThread(function() --- while true do --- multi.warn("Everything is a thread in this proc!") --- thread.sleep(1) --- end --- end) - --- proc:newAlarm(5):OnRing(function(a) --- multi.print(";) Goodbye") --- a:Destroy() --- end) - --- local func = thread:newFunction(function() --- thread.sleep(4) --- print("Hello!") --- end) - --- multi:newTLoop(func, 1) - --- multi:mainloop() - --- multi:setTaskDelay(.05) --- multi:newTask(function() --- for i = 1, 10 do --- multi:newTask(function() --- print("Task "..i) --- end) --- end --- end) - --- local conn = multi:newConnection() --- conn(function() print("Test 1") end) --- conn(function() print("Test 2") end) --- conn(function() print("Test 3") end) --- conn(function() print("Test 4") end) - --- print("Fire 1") --- conn:Fire() --- conn = -conn --- print("Fire 2") --- conn:Fire() - --- print(#conn) - --- thread:newThread("Test thread", function() --- print("Starting thread!") --- thread.defer(function() -- Runs when the thread finishes execution --- print("Clean up time!") --- end) --- --[[ --- Do lot's of stuff --- ]] --- thread.sleep(3) --- end) - -multi:mainloop() - --- local conn1, conn2, conn3 = multi:newConnection(nil,nil,true), multi:newConnection(), multi:newConnection() - --- local link = conn1(function() --- print("Conn1, first") --- end) - --- local link2 = conn1(function() --- print("Conn1, second") --- end) - --- local link3 = conn1(function() --- print("Conn1, third") --- end) - --- local link4 = conn2(function() --- print("Conn2, first") --- end) - --- local link5 = conn2(function() --- print("Conn2, second") --- end) - --- local link6 = conn2(function() --- print("Conn2, third") --- end) - --- print("Links 1-6",link,link2,link3,link4,link5,link6) --- conn1:Lock(link) --- print("All conns\n-------------") --- conn1:Fire() --- conn2:Fire() - --- conn1:Unlock(link) - --- conn1:Unconnect(link3) --- conn2:Unconnect(link6) --- print("All conns Edit\n---------------------") --- conn1:Fire() --- conn2:Fire() - --- thread:newThread(function() --- print("Awaiting status") --- thread.hold(conn1 + (conn2 * conn3)) --- print("Conn or Conn2 and Conn3") --- end) - --- multi:newAlarm(1):OnRing(function() --- print("Conn") --- conn1:Fire() --- end) --- multi:newAlarm(2):OnRing(function() --- print("Conn2") --- conn2:Fire() --- end) --- multi:newAlarm(3):OnRing(function() --- print("Conn3") --- conn3:Fire() --- os.exit() --- end) - - --- local conn = multi:newSystemThreadedConnection("conn"):init() - --- multi:newSystemThread("Thread_Test_1", function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print(THREAD:getName().." was triggered!",a,b,c) --- end) --- multi:mainloop() --- end) - --- multi:newSystemThread("Thread_Test_2", function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print(THREAD:getName().." was triggered!",a,b,c) --- end) --- multi:newAlarm(2):OnRing(function() --- console.print("Fire 2!!!") --- conn:Fire(4,5,6) --- THREAD.kill() --- end) - --- multi:mainloop() --- end) --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print("Mainloop conn got triggered!",a,b,c) --- end) - --- alarm = multi:newAlarm(1) --- alarm:OnRing(function() --- console.print("Fire 1!!!") --- conn:Fire(1,2,3) --- end) - --- alarm = multi:newAlarm(3):OnRing(function() --- multi:newSystemThread("Thread_Test_3",function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local console = THREAD.getConsole() --- conn(function(a,b,c) --- console.print(THREAD:getName().." was triggered!",a,b,c) --- end) --- multi:newAlarm(4):OnRing(function() --- console.print("Fire 3!!!") --- conn:Fire(7,8,9) --- end) --- multi:mainloop() --- end) --- end) - --- multi:newSystemThread("Thread_Test_4",function() --- local multi, thread = require("multi"):init() --- local conn = GLOBAL["conn"]:init() --- local conn2 = multi:newConnection() --- local console = THREAD.getConsole() --- multi:newAlarm(2):OnRing(function() --- conn2:Fire() --- end) --- multi:newThread(function() --- console.print("Conn Test!") --- thread.hold(conn + conn2) --- console.print("It held!") --- end) --- multi:mainloop() --- end) - --- multi:mainloop() ---[[ - newFunction function: 0x00fad170 - waitFor function: 0x00fad0c8 - request function: 0x00fa4f10 - newThread function: 0x00fad1b8 - --__threads table: 0x00fa4dc8 - defer function: 0x00fa4f98 - isThread function: 0x00facd40 - holdFor function: 0x00fa5058 - yield function: 0x00faccf8 - hold function: 0x00fa51a0 - chain function: 0x00fa5180 - __CORES 32 - newISOThread function: 0x00fad250 - newFunctionBase function: 0x00fad128 - requests table: 0x00fa4e68 - newProcessor function: 0x00fad190 - exec function: 0x00fa50e8 - pushStatus function: 0x00fad108 - kill function: 0x00faccd8 - get function: 0x00fad0a8 - set function: 0x00fad088 - getCores function: 0x00facd60 - skip function: 0x00faccb0 - --_Requests function: 0x00fa50a0 - getRunningThread function: 0x00fa4fb8 - holdWithin function: 0x00facc80 - sleep function: 0x00fa4df0 -]] \ No newline at end of file