While troubleshooting
this script, I've smelled some issues related to multitasking (which I didn't really understand how it's implemented in Lua, other than "it has semaphores, appears to work, g3gg0 merged it, so it's probably OK"), so I've added a simple test to api_test.lua.
Do not attempt to run it outside QEMU, unless you have a ROM backup and a camera I know how to reflash (550D or 60D).
function taskA()
printf("Task A started.\n")
local i
for i = 1,100 do
printf("Task A: %d\n", i)
task.yield(math.random(10,50))
end
end
function taskB()
printf("Task B started.\n")
local i
for i = 1,100 do
printf("Task B: %d\n", i)
task.yield(math.random(10,50))
end
end
function test_multitasking()
printf("Testing multitasking...\n")
task.create(taskA)
task.create(taskB)
task.yield(5000)
printf("Multitasking tests completed.\n")
printf("\n")
end
This gives camera lockup or reboot, in the best case. Happens on both nightly and lua_fix. It's not hard to imagine an unlucky sequence of events that
may result in permanent camera bricking (hence the above warning).
I've got some partial success with the
ThreadsTutorial page. Removed the current semaphore guards and defined the following:
#define lua_lock(L) lua_take_sem(L, 0, 0)
#define lua_unlock(L) lua_give_sem(L, 0)
/* create this somewhere at startup; single-script testing only */
static struct semaphore * semm = NULL;
int lua_take_sem(lua_State * L, int timeout, struct semaphore ** assoc_semaphore)
{
take_semaphore(semm, 0);
}
int lua_give_sem(lua_State * L, struct semaphore ** assoc_semaphore)
{
give_semaphore(semm);
}
With this, I no longer get crashes or reboots, and the error message looks like this:

The error message is not always the same, but it's along the same lines. Showing two runs (same code) on the lua_fix branch.
What I think it happens: when calling C functions, Lua calls lua_unlock before and lua_lock after the function
(source); therefore, while a C function is running, another thread is free to interrupt at the wrong moment.
This invalidates the following approach:
2. Long running API calls (like camera.shoot) should "give" the semaphore while they are executing.
The ThreadsTutorial page mentions each thread (task in DryOS) needs a separate Lua state, to be created either with lua_open (from scratch) or with lua_newthread (so they can share global variables). I've found
this example using the second method, but it only works on Lua 5.1, and I don't understand Lua internals well enough to port the code to a newer version.
As I have little or no experience with Lua, and zero experience with multithreaded Lua, any help is welcome.
Otherwise, I'm afraid I'll have to remove the multi-threading functionality (event handlers included). I agree this functionality is very useful, but not at the cost of totally random behavior.
@garry23: please double-check you have a backup copy of your ROM, just in case.