This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Creator's profile picture

Coroutine management system

Started by Creator, 23 March 2015 - 10:30 PM
Creator #1
Posted 23 March 2015 - 11:30 PM
I have kind of written a corourine management system:

Multitasking manager

--[[
TheOS Kernel
by Creator
for TheOS &
you to learn
from it!
theoriginalbit
also gets credit for
his safePairs function.
]]--
local args = {...}
local w,h = term.getSize()
local currTerm = term.current()
local routines = {}
local routinesToKill = {}
local activeRoutine = ""
local eventGlobal = true
local halfH = math.floor(h/2 +2)
local first = true
local function drawClosed()
paintutils.drawLine(w,1,w,h,colors.black)
term.setTextColor(colors.white)
term.setBackgroundColor(colors.black)
term.setCursorPos(w,halfH)
term.write("<")
end
local function safePairs(t)
  local keys = {}
  for k,v in pairs(t) do
	keys[#keys+1] = k
  end
  local i = 0
  return function()
	i = i + 1
	return keys[i], t[keys[i]]
  end
end
local function drawOpen()
paintutils.drawFilledBox(w-15,1,w,h,colors.black)
local xVsProcess = {}
local curr = 1
term.setTextColor(colors.white)
for i,v in pairs(routines) do
  term.setCursorPos(w-14,(curr*2))
  term.write("x "..v.title)
  term.setCursorPos(w-12,(curr*2)+1)
  term.write(coroutine.status(v.routine))
  xVsProcess[curr*2] = v.ID
  curr = curr + 1
end
local notH = true
local switchRoutine = false
local toDelete = false
while notH do
  evnt = {os.pullEventRaw("mouse_click")}
  if w-12 <= evnt[3] and evnt[3] <= w then
   print(event[3])
   if xVsProcess[evnt[4]] ~= nil then
	notH = false
	switchRoutine = true
   end
  elseif w-14 == evnt[3] then
   term.setCursorPos(evnt[3],evnt[4])
   if xVsProcess[evnt[4]] ~= nil then
	notH = false
	toDelete = true
   end
  else
   notH = false
  end
end
print(toDelete)
if switchRoutine then
  print(xVsProcess[evnt[4]])
  routines[activeRoutine].window.setVisible( false )
  print(activeRoutine)
  activeRoutine = xVsProcess[evnt[4]]
  print(activeRoutine)
  --os.pullEventRaw()
  --term.clear()
  routines[activeRoutine].window.setVisible(true)
  routines[activeRoutine].window.redraw()
elseif toDelete then
  if activeRoutine == xVsProcess[evnt[4]] then activeRoutine = "Desktop1" end
  if not xVsProcess[evnt[4]] == "Desktop1" then
   routines[xVsProcess[evnt[4]]] = nil
   routines[activeRoutine].window.setVisible(true)
   routines[activeRoutine].window.redraw()
  end
end
end
function newRoutine(name,func,...)
local sName = name
name = name.."1"
local notUnique = true
local tries = 1
while notUnique do
  tries = tries + 1
  if routines[name] ~= nil then
   name = name:sub(1,-2)..tostring(tries)
  else
   notUnique = false
  end
end
local arguments = {...}
routines[name] = {}
routines[name].routine = coroutine.create(func)
if first then
  routines[name].window = window.create(term.current(),1,1,w-1,h,true)
  activeRoutine = name
  first = false
else
  routines[name].window = window.create(term.current(),1,1,w-1,h,false)
end
routines[name].title = sName
routines[name].ID = name
routines[name].arguments = arguments
routines[name].hasRun = false
end
local function checkIfDead(routine)
local wasDead = false
status = coroutine.status(routines[routine].routine)
if status == "dead" then
  wasDead = true
  if routine == activeRoutine then activeRoutine = "Desktop1" end
  routines[routine] = nil
  routines.Desktop1.window.setVisible(true)
  routines.Desktop1.window.redraw()
end
return wasDead
end
local function main()
os.queueEvent("mouse_click",1,1,1)
while true do
  routinesToKill = {}
  event = {os.pullEventRaw()}
  if (event[1] == "mouse_click" or event[1] == "monitor_touch") and event[3] == w then
   drawOpen()
   term.setBackgroundColor(colors.black)
   term.clear()
   drawClosed()
   routines[activeRoutine].window.redraw()
  elseif event[1] == "key" or event[1] == "mouse_click" or event[1] == "monitor_touch" or event[1] == "paste" or event[1] == "char" then
   checkIfDead(activeRoutine)
   if routines[activeRoutine].hasRun == true then
	term.redirect(routines[activeRoutine].window)
	routines[activeRoutine].window.redraw()
	coroutine.resume(routines[activeRoutine].routine,unpack(event))
	term.redirect(currTerm)
   else
	term.redirect(routines[activeRoutine].window)
	routines[activeRoutine].window.redraw()
	coroutine.resume(routines[activeRoutine].routine,unpack(routines[activeRoutine].arguments))
	routines[activeRoutine].hasRun = true
	term.redirect(currTerm)
   end
  else
   for i,v in safePairs(routines) do
	if not checkIfDead(i) then
	 if routines[i].hasRun == true then
	  term.redirect(routines[i].window)
	  coroutine.resume(routines[i].routine,unpack(event))
	  term.redirect(currTerm)
	 else
	  term.redirect(routines[i].window)
	  coroutine.resume(routines[i].routine,unpack(routines[activeRoutine].arguments))
	  routines[i].hasRun = true
	  term.redirect(currTerm)
	 end
	end
   end
  end
end
end

drawClosed()
newRoutine(unpack(args))
main()

For some reason it does not fully work, but I guess it is the basics.

What does not work is that it does not draw the windows linked with the processes at the right moments.

Any help is appreciated

Thanks in advance

Creator
Edited on 24 March 2015 - 06:26 AM
Lyqyd #2
Posted 24 March 2015 - 12:27 AM
Split into new post. Please create a new topic for help with your code next time rather than using someone else's topic.
Creator #3
Posted 24 March 2015 - 09:04 PM
Why is nobody answering? Is something wrong with the post? Is it unclear? Is my english bad?

Please tell so I can correct it and make the understandin of the post easier.

Guys I really need this help. It is the Core (litterally) of my OS, so if you want to see something nice comming completely for free, help me with this. It is all I am asking about.

Thanks in advance,

Creator
Lyqyd #4
Posted 24 March 2015 - 10:03 PM
Have you read the "Read This Post Before Asking Questions" sticky post? Some of the tips toward the bottom may help you to more fully describe the issue and help people find the issue you're having. What you've described so far is essentially, "It doesn't work like I want it to," which does not give us much to go on.
Creator #5
Posted 24 March 2015 - 10:24 PM
Thanks Lyqyd.

The exact problem is the following: I have this coroutine manager which has some threads. On the right side there is a button. If you click it a menu shows up and ou can choose between the different tasks. When I select a different taks, by clicking on the name, the screen goes black. Afterwards, when I change againg to the desktop, the manager draws the previous screen, but what is actually loaded is the Desktop. I have to click on one of the bottons that are on the desktop in order to draw the desktop. The issue is that is does not draw the current process.

I hope I have been clear enough,

Creator

PS: Thaks in advance ;)/>

The side menu is handled by the openMeny function. You can find the whole OS here. Currently I have put FileX as desktop because desktop was having some problems I am gonna fix tomorow.

To install TheOS, run this:


pastebin get 2DMDuHci TheOS.file

Then run this little script:


pastebin run UTSZHm5s TheOS.file

In the end run this command in the shell:


TheOS/Boot.lua

For some reason, when installed, TheOS does not work. I am fixing that tommorow. Now sleep time.
Edited on 24 March 2015 - 09:47 PM
HPWebcamAble #6
Posted 25 March 2015 - 02:15 AM
This is a pretty complicated problem, a lot of code is involved

I'd recommend adding a 'log' function that saves things to a file
Then you can add some calls to it in your program(s), and see what might be happening
Bomb Bloke #7
Posted 25 March 2015 - 05:13 AM
I suppose this is the relevant code segment (from the bottom of the drawOpen() function - if you can spot where that is. Where's your indentation and spacing?!):

if switchRoutine then
  print(xVsProcess[evnt[4]])
  routines[activeRoutine].window.setVisible( false )
  print(activeRoutine)
  activeRoutine = xVsProcess[evnt[4]]
  print(activeRoutine)
  --os.pullEventRaw()
  --term.clear()
  routines[activeRoutine].window.setVisible(true)
  routines[activeRoutine].window.redraw()
elseif toDelete then
  if activeRoutine == xVsProcess[evnt[4]] then activeRoutine = "Desktop1" end
  if not xVsProcess[evnt[4]] == "Desktop1" then
   routines[xVsProcess[evnt[4]]] = nil
   routines[activeRoutine].window.setVisible(true)
   routines[activeRoutine].window.redraw()
  end
end

You don't seem to be checking if the new process's "hasRun" value is set, so if it hasn't executed anything yet, switching to it won't cause it to start.

If you delete the active process, causing the script to revert to the "desktop", then you don't redraw at all.

Note also that you should only need to trigger a window redraw immediately on switching to a process from another process; and since, at that time, you'll generally be calling window.setVisible(true) (which redraws for you), that means the only time you really need to call redraw() directly is when you close your menu. Speaking of which, that menu is going to cause havok with any timers or rednet messages your processes are trying to keep track of…
Creator #8
Posted 25 March 2015 - 06:01 AM
Why would that cause problems to timers and rednet events? Also thank you for your help. ;)/>

Creator
Bomb Bloke #9
Posted 25 March 2015 - 06:13 AM
While the menu is open, you're pulling mouse_click events while discarding any OTHER events that occur. So if a script is waiting on eg a timer, that menu-handling code may well just throw it away; using os.pullEventRaw() with a filter doesn't stop it from removing other events from the queue, it merely prevents it from actually returning until it finds the exact event it wants.