Continuing problem with Lua semaphore error

Started by garry23, February 18, 2016, 09:39:51 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

garry23

David

I hope you are watching  :)

I continue to suffer from Lua semaphore errors but can't see why, as I followed you advice.

My script is this:

--[[
Manual Landscape bracketing helper script
Version 0.3.3
Garry George Feb 2016
http://photography.grayheron.net/
First focus at nearest bracket in focus stack then move towards infinity.
Try using ML follow focus to control lens, as opposed to rotating lens by hand.
Yellow means move more towards the infinity end, Red means move more towards macro end,
Green means at the sweet spot. If Green not seen, move to just being in the Yellow from being in the Red.
************************
* Must be in liveview! *
************************
--]]
a1 = lens.dof_near
b1 = lens.dof_far
c1 = 0
fp = lens.focal_distance
inf = 1000000
started = false

function do_bookend()
task.create(function()
current_tv = camera.shutter.apex
current_av = camera.aperture.apex
camera.shutter.apex = 100
camera.aperture.apex = 90
camera.shoot(64, 0)
camera.shutter.apex = current_tv
camera.aperture.apex = current_av
end)
task.yield(100)
end

event.keypress = function(key)
if key == KEY.RATE then
if keymenu.submenu["Bookends"].value == "yes"
then
do_bookend()
end
return true
end
if keymenu.submenu["Turn On/Off"].value == "Off" then started = false end
if fp ~= 0 then
if key == KEY.FULLSHUTTER
then
b1 = lens.dof_far -- in mm
fp = lens.focal_distance -- in cm
if keymenu.submenu["Bracket to bracket overlap"].value == "20%" then
factor = .2
elseif keymenu.submenu["Bracket to bracket overlap"].value == "10%" then
factor = .1
else
factor = .05
end
c1 = b1 - (b1 - fp*10)*factor
started = true
end
end
end

lv.info
{
    name = "Landscape Stacker Info",
    value = "",
    priority = 100,
    update = function(this)
    this.value = ""
if fp == 0 then
this.value = ""
else
    if keymenu.submenu["Turn On/Off"].value == "On"
    then
    if started then
a2 = lens.dof_near
this.value = ""
if a2 > b1 then
this.background = COLOR.RED
elseif a2 < c1 then
this.background = COLOR.YELLOW
this.foreground = COLOR.BLACK
else
this.background = COLOR.GREEN1
end
if lens.dof_far >= inf then
this.value = "Inf"
else
this.value = "   "
end
end
else
this.value = ""
end
end
end
}

keymenu = menu.new
{
parent = "Audio",
name = "Landscape Stacking Helper",
help = "First focus at nearest point in bracket set",
help2 = "and take first picture",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "Turn On/Off",
help = "Switches the script on/off",
depends_on = DEPENDS_ON.LIVEVIEW,
choices = {"Off","On"},
},
{
name = "Bracket to bracket overlap",
help = "Amount to overlap each bracket",
help2 = "% of FP-2-DoF(far) distance",
choices = {"20%","10%", "5%"},
},
{
name = "Bookends",
help = "Adds a dark frame",
choices = {"no","yes"},
}
}
}


When I press the RATE button I start a new task and steal the keypress and call do_bookend. Sometimes I don't get the semaphore error, but usually I do.

Can you suggest what I'm doing wrong?

Cheers

Garry

dmilligan

Why are you calling task.yield at the end of do_bookend?

Maybe it will help if I just explain what causes those errors (and why sometimes, you might just want to ignore them).

As we've discussed previously, the ML Lua API has several "event-oriented" features. Where you define some function you want the backend to call when some event happens. Your particular script has several of these:

task.create(function())
event.keypress = function()
lv.info.update = function()

What's happening in each of these situations is that you are defining a function that you want the Lua backend to execute at some particular later time. When the time comes for the Lua backend to run those functions you defined, it needs to make sure that your script is not currently in the middle of doing something else, because trying to execute your function at while something else is running would corrupt the "Lua state" (the virtual machine) your script is running inside.

So, the Lua backend uses semaphores to "protect" the Lua state from corruption. When something in your script starts executing, the Lua backend "takes" the semaphore associated with your Lua state (each script gets it's own Lua state, and also it's own semaphore, so different scripts can actually execute at the "same" time). Once whatever it was that started executing in your Lua script, finishes executing, the Lua backend "gives" the semaphore back. Now, if during that time while your script was doing something, an event occurred that the Lua backend needed to call one of your functions, it would try to "take" the semaphore, but the semaphore is already "taken", so it has the option now of waiting some specified amount of time for the semaphore to be "given" back by the original "taker". The amount of time to wait (aka timeout) used by the Lua backend varies depending on the situation. For some things the Lua backend is not willing to wait very long, because while it is waiting, it's blocking other things. The best example is event.keypress. If the backend waits to long, it will be blocking ML and Canon code from responding to key events, so it uses a short timeout.

So, if it's time for the backend to run one of your functions, and your script is already doing something else, the backend will wait a little while for whatever it was to finish executing, then once that amount of time is exceeded, guess what? "lua semaphore timeout"

Now, can you guess what task.yield does? When you call it, the backend "gives" the semaphore so other things in your script can execute, then it sleeps for the specified amount of time, then it "takes" the semaphore back and returns from the call and your script continues executing. So calling task.yield() is sort of like saying: "hey, does anything else need to execute right now? be my guest"




There are a couple of things I might could do with the backend that might help some of this:
1. More info about the semaphore timeout (like what CBR it was that was trying to execute, and what was blocking it)
2. Long running API calls (like camera.shoot) should "give" the semaphore while they are executing.

garry23

David

Once again thanks for your detailed feedback.

I put the task.yield in out of desperation, as I get the semaphore error with out it.

As I said, I followed the guidance  you gave me before, ie put the camera.shoot in a create.task wrapper.

But as I say, I just keep getting the error: which I can't ignore as it opens the console and fills the screen with all the other ML/Lua 'stuff'.

I'm really not thick, and I really do read your feedback.

Bottom line: with or without the use of task.yield, ie get the error.