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

Calculation task interruption

Started by MarioBG, 22 October 2016 - 06:54 PM
MarioBG #1
Posted 22 October 2016 - 08:54 PM
Hi!

I'm currently studying Software Engineering, and in the OS subject they offer the possibility to get some extra marks with a voluntary task. They usually suggest modifying https://pdos.csail.mit.edu/6.828/2016/xv6.html Xv6's task manager, but since I've had the idea of making my ComputerCraft OS a multitasking one for quite some time now, I decided to pitch the idea at the professor, and it seemed to go down pretty well.

So, when I got down to it, I realized I'd have to do something about controlling the execution of calculation tasks, e.g. stopping an endless loop before it crashes the computer. I know this can't be done per se in Lua, as it's based on yielding threads, but I've thought of a little trick that may work. It would consist in introducing a little os.pullEventRaw() at the beginning of every loop. What do you think of it? Is it feasible, is there any better alternative? How could it be done? I really want to do this task about ComputerCraft, and I need this fixed for that. Thanks in advance!
KingofGamesYami #2
Posted 22 October 2016 - 09:27 PM
Actually, this is already the behavior of a CC computer. If you're multitasking, the manager can simply catch the "too long without yielding" error. It shuts down the computer only if it is unable to force a yield via the error. An example case would be a ln infinite loop which does not do anything.
Bomb Bloke #3
Posted 23 October 2016 - 12:37 AM
In cases where a loop would completely shut the computer down, my advice is "let it". If the code is bugged, it's better to allow it to fail than to try to hide the problem.
MarioBG #4
Posted 23 October 2016 - 10:30 AM
In cases where a loop would completely shut the computer down, my advice is "let it". If the code is bugged, it's better to allow it to fail than to try to hide the problem.

Thing is, if I am making an OS I'd want to catch the error and not let the whole system go down with a single program, and at the same time I need runtime for the basic OS tasks at every given moment.

Actually, this is already the behavior of a CC computer. If you're multitasking, the manager can simply catch the "too long without yielding" error. It shuts down the computer only if it is unable to force a yield via the error. An example case would be a ln infinite loop which does not do anything.

Well, I've tried this, and the results have not been 'too long without yielding', but rather the computer freezing and then shutting down. Indeed, what I did was an infinite loop with nothing in it, but this is precisely one of the things the professor made in class to show the difference between a calculating task and a yielding one, and it's something I'd rather have covered. Once again, if it's not possible and is something inherent to ComputerCraft, I think I could get away with it, but at least I'd like to know if it could be done.
KingofGamesYami #5
Posted 23 October 2016 - 01:29 PM
Essentially you would have to modify the code before it is run to add a call inside that loop. For example:

getfenv(originalProgramString).idle = function()
  --#check if we need to yield
end
local fixedProgram = originalProgramString:gsub( "while.-do", function( capture ) return capture .. " idle()\n" end )
WARNING: UNTESTED CODE
Bomb Bloke #6
Posted 23 October 2016 - 01:46 PM
Better not the yield, really.

Just to make sure we're all on the same page: as Yami mentioned, ComputerCraft does already do what you're wanting, at least to a point. Whenever you call a native Lua function it checks to see if your coroutine yielded recently, and if not, it straight away makes that function return an error.

If you don't call any such functions, then ComputerCraft can't generate an error - and so if enough time passes, it'll simply kill the computer's parent coroutine, switching that computer off.

So all you really need to do is make sure all loops call a function which is able to generate a "too long without yielding" error - you don't actually need to make those functions yield yourself (and doing so would be a good deal more complex). You'd also put such a call at the top of each script to prevent loops made by recursive script launches causing trouble (though those'll generally lead to a Java array index out of bounds error first, come to think of it - good luck catching that one, you'd need to modify all function calls so's you can monitor the stack!). Easiest to just override loadstring (and anything that does the same sort of job without actually depending on loadstring).

The catch, of course, is that if your users want the system to crash they need only determine which function you're inserting and override it. Well, that and you'll be nerfing general performance in order to deal with a problem that would much more easily be solved by your users not writing faulty code in the first place…