Jump to content




Prevent Program Termination (Ctrl+T)

help

52 replies to this topic

#1 Espen

    Curious Explorer

  • Members
  • 708 posts

Posted 20 February 2012 - 09:57 PM

Why / How does CTRL+T stop my program?
The reason why your programs can be terminated is because you're either using os.pullEvent() somewhere, or because you're calling an external function and that uses os.pullEvent().
os.pullEvent() is the reason why your program will stop execution on pressing CTRL+T:
If you press CTRL+T then the 'terminate' event is created.
os.pullEvent() listens for that event and will throw the error message 'Terminated', which in turn will stop your program.

There are two ways you can prevent CTRL+T from stopping your programs:
  • Catch the error thrown by os.pullEvent() by making use of the pcall() function.
    Quote from lua.org's manual:

    Quote

    pcall (f, arg1, ...)
    Calls function f with the given arguments in protected mode. This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.

    So let's say you have this code:
    		local password = "secret"
    		local input
    		
    		repeat
    		  write("Password: ")
    		  input = read()
    		until input == password
    		

    Since read() is using os.pullEvent(), instead of directly calling read() we can call it via pcall() instead:
    		local password = "secret"
    		local status, input
    		
    		repeat
    		  write("Password: ")
    		  status, input = pcall(read)
    		until input == password
    		
  • Use os.pullEventRaw() instead of os.pullEvent()
    If you take a closer look at how os.pullEvent() is implemented ("bios.lua"), then you can see that it calls os.pullEventRaw() to receive an event and in addition to that throws an error if the event was 'terminate'.
    That means instead of using os.pullEvent() in your program, you can just replace it with os.pullEventRaw() to prevent CTRL+T to throw an error.
    Now, os.pullEventRaw() itself simply wraps coroutine.yield(), but that is not necessary knowledge for this tutorial and deserves its own topic.

    So if your program is something like this...
    		while true do
    		  local sEvent, param = os.pullEvent()
    		
    		  if sEvent == "key" and param == 28 then
    			print("You pressed ENTER")
    		  end
    		end
    		
    ... then simply replace the os.pullEvent() with os.pullEventRaw() to prevent CTRL+T from stopping your program:
    		while true do
    		  local sEvent, param = os.pullEventRaw()
    		
    		  if sEvent == "key" and param == 28 then
    			print("You pressed ENTER")
    		  end
    		end
    		
    The only way to stop this program now would be to reboot the (ingame-) computer.

But which of all the CC-functions make use of os.pullEvent() ?
As of CC version 1.2 the functions making use of os.pullEvent() either directly or indirectly are:
  • sleep
  • read
  • rednet
So if you're using any of these in your program, it can be stopped by CTRL+T.
To prevent that, call them via pcall (as described further up)

The number of functions using os.pullEvent() or the functions themselves might change in the future though.
Therefore it's always a good idea to check them for yourself. All the functions should either be in "bios.lua" or the API files.
Location of "bios.lua": .minecraft\mods\ComputerCraft\lua\
Location of the API files: .minecraft\mods\ComputerCraft\lua\rom\apis\

Example: Does read() make use of os.pullEvent() ?
  • read() is defined within "bios.lua", so we open that file.
  • We search for os.pullEvent() within the read() function and find this line:
    local sEvent, param = os.pullEvent()
  • So yes, CC's read() does use os.pullEvent() and if we'd use it in our program it could be terminated with CTRL+T.


Further Information:
I hope everything was easy to follow and not too complicated.
If you have any further questions or suggestions, feel free to ask.
Cheers! ;)/>

#2 skorbut

  • New Members
  • 1 posts

Posted 29 February 2012 - 03:24 AM

Thanks, helped me alot, is there any chance to prevent CTRL+R ?

#3 Casper7526

    OG of CC

  • Members
  • 362 posts

Posted 29 February 2012 - 03:54 AM

Nope, CTRL+R and CTRL+S are hardcoded

#4 FuzzyPurp

    Part-Time Ninja

  • Members
  • 510 posts
  • LocationHarlem, NY

Posted 29 February 2012 - 04:48 AM

There is no reason to prevent that, it's like asking to remove the power/reset button off your computer.

#5 ENET

  • Members
  • 15 posts

Posted 06 March 2012 - 11:35 PM

Just use this instead.

--At top of program
local oldPull = os.pullEvent;
os.pullEvent = os.pullEventRaw;

--Your program between :unsure:/>

--At end of program
os.pullEvent = oldPull;

[[There is no reason to prevent that, it's like asking to remove the power/reset button off your computer]]

Some programs turn redstone on wait awhile and turn it off. Someone can keep it on by shutting it off. There needs to be no way of stopping it, but there should be a way to detect it.

#6 Espen

    Curious Explorer

  • Members
  • 708 posts

Posted 07 March 2012 - 12:17 AM

@ENET: I'm aware of that, I described it as one possible solution here: http://www.computerc...ndpost__p__2514
It's just that I didn't want to include it at the time, because I thought it wouldn't be a good way to go about it in general, but I changed my mind since then.
Whatever makes people's programs work is my philosophy now. At least here. :unsure:/>

#7 rex41043

  • Members
  • 88 posts

Posted 13 March 2012 - 08:06 AM

RE to:
Casper7526

Posted 29 February 2012 - 04:54 PM
Nope, CTRL+R and CTRL+S are hardcoded

Theres no need if you are doing a password coz u can just code it into the startup file


#8 Mendax

  • Members
  • 366 posts

Posted 14 March 2012 - 07:08 AM

So, how do I make it print something after pcall? Delete this post if you want.

#9 6677

  • Members
  • 197 posts
  • LocationCambridgeshire, England

Posted 14 March 2012 - 02:40 PM

 
--At top of program
local oldPull = os.pullEvent;
os.pullEvent = os.pullEventRaw;

--Your program between :mellow:/>/>

--At end of program
os.pullEvent = oldPull;
 
If I use the above method would this take effect on read etc aswell or would I still need to pcall() them.

#10 Espen

    Curious Explorer

  • Members
  • 708 posts

Posted 14 March 2012 - 03:19 PM

View Post6677, on 14 March 2012 - 02:40 PM, said:

--At top of program
local oldPull = os.pullEvent;
os.pullEvent = os.pullEventRaw;

--Your program between ;)/>/>

--At end of program
os.pullEvent = oldPull;

If I use the above method would this take effect on read etc aswell or would I still need to pcall() them.
Yes, it takes effect on them, i.e. no need for pcall() when doing it this way. (At least if we're only talking about preventing the terminate event). :mellow:/>

All functions which would normally call os.pullEvent(), like e.g. read() or sleep(), will then really call os.pullEventRaw().
This way you don't need to copy stock functions like read() or sleep() and change their code, but just reassign 'pullEvent' to 'pullEventRaw' for the duration of your program.

#11 BlueMond

  • Members
  • 21 posts

Posted 17 March 2012 - 08:32 PM

There is a reason to want to get rid of ctrl+r and ctrl+s. People can insert a floppy that bypasses ur startup and restart the computer.

#12 Liraal

  • New Members
  • 477 posts
  • LocationPoland

Posted 17 March 2012 - 08:39 PM

not if you place a protected disk drive on top of the computer.

#13 Espen

    Curious Explorer

  • Members
  • 708 posts

Posted 17 March 2012 - 10:50 PM

Also,

View PostBlueMond, on 17 March 2012 - 08:32 PM, said:

There is a reason to want to get rid of ctrl+r and ctrl+s. People can insert a floppy that bypasses ur startup and restart the computer.
You can protect against that by a one-time change to the bios.lua.
Take a look at the tutorial section, that should point you in the right direction.

#14 BlackRa1n

  • New Members
  • 69 posts

Posted 23 March 2012 - 09:48 PM

How would you use this for 'sleep'?
I typed:

pcall(3)

for sleeping for 3 seconds. I know this is not right, so what do I put?

#15 Liraal

  • New Members
  • 477 posts
  • LocationPoland

Posted 23 March 2012 - 10:07 PM

pcall(sleep,3)

#16 Espen

    Curious Explorer

  • Members
  • 708 posts

Posted 24 March 2012 - 12:44 AM

View PostBlackRa1n, on 23 March 2012 - 09:48 PM, said:

How would you use this for 'sleep'?
I typed:

pcall(3)

for sleeping for 3 seconds. I know this is not right, so what do I put?
What Liraal said. :(/>

Also you can read up on the definition, which I've linked in the OP.
For your convenience, I'll repost it here: http://www.lua.org/m....html#pdf-pcall
You can also look up all kinds of other functions in that manual, as well as decriptions of how things in Lua work in general.
Mind you, not everything works 1:1 in CC, though. But most of it does.

#17 BlackRa1n

  • New Members
  • 69 posts

Posted 24 March 2012 - 08:29 AM

Ok, thanks, both of you! :(/>

#18 Espen

    Curious Explorer

  • Members
  • 708 posts

Posted 24 March 2012 - 12:20 PM

@BlackRa1n:
But remember: pcall only catches an error and thus let's the program continue running.
The sleep function makes use of timers, for which it then waits by listening for incoming events via os.pullEvent()

That means if you use pcall(sleep, 3) and press CTRL+T, then this will cause the os.pullEvent within the sleep function to throw an error.
But instead of our program now terminating, the pcall catches this error and returns control to your program, i.e. the next line after pcall(sleep, 3) is executed.

So with pcall(sleep, 3) you can prevent CTRL+T to terminate your program, but it still would stop the sleep timer prematurely!
That means, if you want to force a specific waiting time on the user, then using pcall() on the sleep function won't ensure that.

To make that happen you would actually have to prevent the os.pullEvent within the sleep function itself to throw an error to begin with.
To achieve that you can backup the global function os.pullEvent and temporarily overwrite it with os.pullEventRaw.
Because the latter won't throw an error on 'terminate' and thus the sleep function won't either (and neither would the read function btw.).
local oldPullEvent = os.pullEvent
os.pullEvent = os.pullEventRaw


After you're done with your program you just restore os.pullEvent with the backup you made at the beginning and then it will behave as it did before again.
os.pullEvent = oldPullEvent

I didn't include this variation at the beginning, because I thought it wasn't good practice. But now I see more and more people ending up having to use it and also it's pretty much required if you use native CC functions which make use of os.pullEvent.
Therefore I might edit the OP to include this sometime this weekend.

Well, hope this was of any use for you, have fun! :(/>

#19 BlackRa1n

  • New Members
  • 69 posts

Posted 24 March 2012 - 05:40 PM

View PostEspen, on 24 March 2012 - 12:20 PM, said:

@BlackRa1n:
But remember: pcall only catches an error and thus let's the program continue running.
The sleep function makes use of timers, for which it then waits by listening for incoming events via os.pullEvent()

That means if you use pcall(sleep, 3) and press CTRL+T, then this will cause the os.pullEvent within the sleep function to throw an error.
But instead of our program now terminating, the pcall catches this error and returns control to your program, i.e. the next line after pcall(sleep, 3) is executed.

So with pcall(sleep, 3) you can prevent CTRL+T to terminate your program, but it still would stop the sleep timer prematurely!
That means, if you want to force a specific waiting time on the user, then using pcall() on the sleep function won't ensure that.

To make that happen you would actually have to prevent the os.pullEvent within the sleep function itself to throw an error to begin with.
To achieve that you can backup the global function os.pullEvent and temporarily overwrite it with os.pullEventRaw.
Because the latter won't throw an error on 'terminate' and thus the sleep function won't either (and neither would the read function btw.).
local oldPullEvent = os.pullEvent
os.pullEvent = os.pullEventRaw


After you're done with your program you just restore os.pullEvent with the backup you made at the beginning and then it will behave as it did before again.
os.pullEvent = oldPullEvent

I didn't include this variation at the beginning, because I thought it wasn't good practice. But now I see more and more people ending up having to use it and also it's pretty much required if you use native CC functions which make use of os.pullEvent.
Therefore I might edit the OP to include this sometime this weekend.

Well, hope this was of any use for you, have fun! :(/>

Thanks! :)/>

#20 Alex_

  • Members
  • 63 posts
  • LocationPontefract, West Yorkshire, England

Posted 25 March 2012 - 07:42 PM

Thanks ive got a lot of code to rewrite





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users