Last active
May 30, 2017 16:02
-
-
Save prozacgod/ee9f67a1b8f9be4369c6d1cda7fe081e to your computer and use it in GitHub Desktop.
OpenComputers signals low level pull signal, with future schedules pseudo signals, and a threadlet kernel.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local event = require('event') | |
local uptime = require('computer').uptime | |
local signals = { | |
_pullSignal = function(timeout) | |
return event.pull(timeout) | |
end | |
} | |
local p_events = {} | |
local p_handle = 1 | |
function getNextPEvent() | |
local selected_event = { time = math.huge } | |
for handle, p_event in pairs(p_events) do | |
if p_event.time < selected_event.time then | |
selected_event = p_event | |
end | |
end | |
if selected_event.handle == nil then | |
return nil | |
end | |
return selected_event | |
end | |
signals.schedule = function(time, event_data) | |
local handle = p_handle | |
p_handle = p_handle + 1 | |
p_events[handle] = { | |
time = uptime() + time, | |
handle = handle, | |
event_data = event_data | |
} | |
return handle | |
end | |
signals.cancel = function(handle) | |
p_events[handle] = nil | |
end | |
signals.pull = function(userTimeout) | |
userTimeout = userTimeout or math.huge | |
local current_time = uptime() | |
local next_pevent = getNextPEvent() | |
local pevent_data = nil | |
local timeout = userTimeout | |
-- we have a scheduled pseudo-signal | |
if next_pevent then | |
local p_timeout = next_pevent.time - current_time | |
if (userTimeout >= p_timeout) then | |
pevent_data = next_pevent.event_data | |
timeout = p_timeout | |
end | |
-- this signal is overdue, return it now! | |
if p_timeout <= 0 then | |
signals.cancel(next_pevent.handle) | |
return pevent_data | |
end | |
end | |
-- next pseudo-signal is in the future, lets see if new events come from the hardware first | |
local data = {signals._pullSignal(timeout)} | |
if data[1] == nil then | |
if pevent_data then | |
signals.cancel(next_pevent.handle) | |
end | |
return pevent_data | |
end | |
return data | |
end | |
return signals |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package.loaded.threadlet = nil | |
package.loaded.signals = nil | |
local threadlet = require("threadlet") | |
-- this function will exit when 'q' is pressed | |
local function keyboardExitThreadlet() | |
print ("starting thread!, press q for this thread to die") | |
while true do | |
local evt, addr, a, b, c, d, e, f = threadlet.pullEvent('key_up') | |
-- q pressed filter, lets exit! | |
if evt == "key_up" and a == 113 then | |
break | |
end | |
end | |
end | |
local function eventSpyThreadlet() | |
local w,h = term.getViewport() | |
while true do | |
local evt = {threadlet.pullEvent()} | |
local evtStr = "" | |
for i,v in ipairs(evt) do | |
evtStr = evtStr .. tostring(v) .. " " | |
end | |
term.setCursor(1, h) | |
term.write("EVT: " .. evtStr .. " ") | |
end | |
end | |
local function sleepTimer1() | |
while true do | |
print(" sleeping! TIMER 1") | |
threadlet.sleep(1) | |
print(" Sleep timer 1") | |
end | |
end | |
local function sleepTimer2() | |
while true do | |
print("------- sleeping! TIMER 2") | |
threadlet.sleep(3) | |
print("------- Sleep timer 2") | |
end | |
end | |
local function sleepTimeoutExit() | |
print("Sleeping! press q before timeout to exit") | |
threadlet.sleep(12) | |
print("Timeout over, exiting!") | |
end | |
threadlet.kernel(keyboardExitThreadlet, sleepTimer1, sleepTimer2, sleepTimeoutExit) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local signals = require("signals") | |
local threadlet = {1,2,3} | |
threadlet.pullEvent = function(...) | |
return coroutine.yield(...) | |
end | |
local sleep_handle = 1 | |
threadlet.sleep = function(timeout) | |
local handle = sleep_handle | |
sleep_handle = sleep_handle + 1 | |
signals.schedule(timeout, {'timer', 'self', handle}) | |
while true do | |
local evt, addr, h = threadlet.pullEvent('timer') | |
if handle == h then | |
break | |
end | |
end | |
end | |
threadlet.kernel = function(...) | |
local threadlets = {} | |
local threadletFuncs = {...} | |
function threadletHandlerFactory(func) | |
local co = coroutine.create(func) | |
local evt_filter_name = nil | |
return { | |
co = co, | |
resume = function(evt_data) | |
local evt_name = nil | |
if evt_data ~= nil then | |
evt_name = evt_data[1] | |
end | |
if evt_filter_name ~= nil and evt_name ~= evt_filter_name then | |
return | |
end | |
if evt_data == nil then | |
evt_data = {} | |
end | |
local noErr, evt_filter = coroutine.resume(co, table.unpack(evt_data)) | |
evt_filter_name = evt_filter | |
end | |
} | |
end | |
for i, func in ipairs(threadletFuncs) do | |
threadlets[i] = threadletHandlerFactory(func) | |
end | |
local threadCount = #threadlets | |
local evt_data | |
while true do | |
for i = 1, #threadlets do | |
threadlets[i].resume(evt_data) | |
end | |
for i = #threadlets, 1, -1 do | |
if coroutine.status(threadlets[i].co) == 'dead' then | |
table.remove(threadlets, i) | |
end | |
end | |
if #threadlets < threadCount then | |
break | |
end | |
evt_data = signals.pull() | |
end | |
end | |
return threadlet |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package.loaded.threadlet = nil | |
package.loaded.signals = nil | |
local threadlet = require("threadlet") | |
-- this function will exit when 'q' is pressed | |
local function keyboardExitThreadlet() | |
print ("starting thread!, press q for this thread to die") | |
while true do | |
local evt, addr, a, b, c, d, e, f = threadlet.pullEvent('key_up') | |
-- q pressed filter, lets exit! | |
if evt == "key_up" and a == 113 then | |
break | |
end | |
end | |
end | |
local function eventSpyThreadlet() | |
local w,h = term.getViewport() | |
while true do | |
local evt = {threadlet.pullEvent()} | |
local evtStr = "" | |
for i,v in ipairs(evt) do | |
evtStr = evtStr .. tostring(v) .. " " | |
end | |
term.setCursor(1, h) | |
term.write("EVT: " .. evtStr .. " ") | |
end | |
end | |
local function sleepTimeout() | |
print("Sleeping! press q before timeout to exit") | |
threadlet.sleep(2) | |
print("Timeout over, exiting!") | |
end | |
threadlet.kernel(keyboardExitThreadlet, sleepTimeout) |
Fixed the bug with multiple timers, it was actually a bug with getNextPEvent() where it was using #p_events ... since I'm not using the array semantics # operator will not work, instead I chose to iterate over the list of events (empty or otherwise) and if it selected the temporary event constructed at the beginning of the loop, it returned nil
Fixed another issue, overdue events were getting lost to the ether, if a lot of events (drag events) came in some pseudo-signals were failing to fire, leading to inconsistent events.
This fix makes it so that it should run exactly the same number of events, obviously timing isn't precise due to the nature of OC and the environment.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Eek there be bugs in here!!
Multiple threadlets running threadlet.sleep break.....
working on a fix, but I got tired... I know! the nerve of me!
I'll have to work on it in the morning.