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

Gps.locate() Consumes My Timer Event

Started by davemac30, 03 September 2013 - 08:26 AM
davemac30 #1
Posted 03 September 2013 - 10:26 AM
Whilst debugging some event driven code, I found that my timer events were sporadically disappearing. I traced the problem to the gps.locate() function. I've recreated the issue with a much smaller program here:

t = os.startTimer(1)
print(t)
os.sleep(2)
gps.locate(2, true)
while true do
  e, p = os.pullEvent()
  print(string.format("%s: %s", e, p))
  if p == t then break end
end

gps.locate() calls os.pullEvent() and discards events it's not interested in.

Should I raise this as a bug?
Lyqyd #2
Posted 03 September 2013 - 01:31 PM
Split into new topic.

This isn't a bug.

Regardless of whether or not gps.locate eats your timer events, in that code, you start a one-second timer, then sleep for two seconds, which means that your timer event has already fired and disappeared before you even call gps.locate.

gps.locate does, in fact, eat other events, just like sleep, read, rednet.receive, and the turtle functions. If you need to prevent it from eating your events, you could run it in a coroutine controlled by your program. Bear in mind that if this is for a turtle, your turtle function calls will eat events too.
davemac30 #3
Posted 04 September 2013 - 05:56 AM
Thanks for your feedback - really helpful.

My example was a bit trivial - I didn't want to paste my entire program because I wanted to try and illustrate the problem I'm having. Here's a (still trivial) but slightly more realistic example.

My turtle starts two timers. One for moving and one for working (the application is a farm where the turtle wanders around randomly harvesting and sowing). This code roughly approximates this:


function move()
  gps.locate(2, false)
  print("move()")
end

function work()
  print("work()")
end

m = os.startTimer(1)
w = os.startTimer(5)
while true do
  e, p = os.pullEvent()
  if p == m then
	move()
	m = os.startTimer(1)
  elseif p == w then
	work()
	w = os.startTimer(5)
  end
end

At some point, the work timer event gets grabbed (and discarded) in gps.locate() and so my work() function never gets called again. It would be nice if the ROM programs/apis could requeue events which they are not interested in.

Interesting what you say about coroutines - do coroutines maintain separate event queues?
theoriginalbit #4
Posted 04 September 2013 - 06:05 AM
It would be nice if the ROM programs/apis could requeue events which they are not interested in.
This is very, very, very, problematic to do this (also very difficult to do accurately), how they function is correct and they should not function any differently.

Interesting what you say about coroutines - do coroutines maintain separate event queues?
Yes, when using the Parallel API each coroutine is supplied with the event, meaning that each routine will receive the event. However if you do coroutines manually you will have to be in charge of making sure that each coroutine gets the event, it is not automatically done for you.

EDIT: As Lyqyd stated the some functions consume events, here is a list of all the ones that I can think of off the top of my head that consume events:
  • sleep/os.sleep
  • read/io.read
  • turtle functions
  • rednet.receive
  • gps.locate (as you know)
  • http functions
and the reason that they do is because they are all looking for a particular event and make use of os.pullEvent/os.pullEventRaw/coroutine.yield which grabs an event from the event queue for them.
Edited on 04 September 2013 - 04:12 AM
davemac30 #5
Posted 04 September 2013 - 06:14 AM
Thanks.

Probably worth mentioning in the Wiki somewhere that event delivery is not reliable by design. I guess Minecraft is a game after all :)/>
theoriginalbit #6
Posted 04 September 2013 - 06:31 AM
Probably worth mentioning in the Wiki somewhere that event delivery is not reliable by design. I guess Minecraft is a game after all :)/>
I think it does in the os.pullEvent thread. Also it should be stated that it is reliable as possible, it cannot become anymore reliable than it is.