OpenMods / OpenPeripheral

https://openmods.info
MIT License
67 stars 25 forks source link

getTankInfo consistently takes non-zero time (1 tick) to execute, and drops events during that time #272

Closed GinjaNinja32 closed 7 years ago

GinjaNinja32 commented 7 years ago

I'm trying to write an interactive program that needs to poll an external tank in a loop, and the fact getTankInfo() is dropping events while executing is making that a lot harder. Is it possible to make it either take no time to execute, or at least not drop events while it takes its tick?

Reproduction:

inventory = peripheral.wrap("left")
tank = peripheral.wrap("right")

-- With os.clock():

a = os.clock()
print(2) -- control, this should never take any time
b = os.clock()
print("print takes ", b-a) -- print takes 0

a = os.clock()
inventory.getAllStacks()
b = os.clock()
print("inventory takes ", b-a) -- inventory takes 0

a = os.clock()
tank.getTankInfo()
b = os.clock()
print("tank takes ", b-a) -- tank takes 0.05

-- With timers:

sleep(2) -- clear event queue

timer1 = os.startTimer(0)
timer2 = os.startTimer(1)

print("starting loop")
for i = 0, 10 do
    inventory.getAllStacks()
end
print("ending loop")

evt, arg = os.pullEvent()

-- timer1 is received
print("timer got ", arg, "; t1=", timer1, "; t2=", timer2) -- timer got 25201; t1=25201; t2=25202

sleep(2) -- clear event queue

timer1 = os.startTimer(0)
timer2 = os.startTimer(1)

print("starting loop")
for i = 0, 10 do
    tank.getTankInfo()
end
print("ending loop")

evt, arg = os.pullEvent()

-- timer2 is received; timer1 was dropped during the above loop
print("timer got ", arg, "; t1=", timer1, "; t2=", timer2) -- timer got 25205; t1=25204; t2=25205

I'm running FTB Infinity 2.6.0, which contains:

ComputerCraft 1.75 OpenModsLib 0.9.1 OpenPeripheralCore 1.3 OpenPeripheralAddons 0.5.1 OpenPeripheralIntegration 0.5

boq commented 7 years ago

It's by design - to access anything in world we need to synchronize (with main thread), otherwise game may crash.

Basically, some of calls in OpenPeripheral (marked as synchronous in documentation) internally look like this:

local task_id = issueMainThreadTask(...) -- function from CC API
while true do
    event, id = os.pullEvent("task_complete")
    if id == task_id then break end
end

return ... -- actual return of function stored somewhere else

This is standard pattern in CC and identical to behaviour of turtle methods (turtle.dig, etc). To get around this, please use built-in parallel module.