https://bitbucket.org/hudson/magic-lantern
Tip revision: a2ff6d4bf23fa5d892b623d08520863de8b4cfd4 authored by alex@thinkpad on 21 June 2018, 06:00:06 UTC
Close branch crop_rec_4k-raw.c_consolidation
Close branch crop_rec_4k-raw.c_consolidation
Tip revision: a2ff6d4
lua_task.c
/***
Task functions
@author Magic Lantern Team
@copyright 2014
@license GPL
@module task
*/
#include <dryos.h>
#include <fileprefix.h>
#include <string.h>
#include "lua_common.h"
struct lua_task_func
{
lua_State * L;
int function_ref;
};
static int luaCB_card_index(lua_State * L);
static int luaCB_card_newindex(lua_State * L);
static void lua_run_task(struct lua_task_func * lua_task_func)
{
if(lua_task_func)
{
lua_State * L = lua_task_func->L;
struct semaphore * sem = NULL;
if(!lua_take_semaphore(L, 0, &sem) && sem)
{
if (lua_get_cant_yield(L) == -1)
{
/* main task was unloaded? continuing would be use after free */
fprintf(stderr, "[%s] will not start new tasks.\n", lua_get_script_filename(L));
goto skip;
}
if(lua_rawgeti(L, LUA_REGISTRYINDEX, lua_task_func->function_ref) == LUA_TFUNCTION)
{
/* script created a task;
* it can't be unloaded while this task is running */
lua_set_cant_unload(L, 1, LUA_TASK_UNLOAD_MASK);
printf("[%s] task starting.\n", lua_get_script_filename(L));
if(docall(L, 0, 0))
{
fprintf(stderr, "[%s] task error:\n%s\n", lua_get_script_filename(L), lua_tostring(L, -1));
lua_save_last_error(L);
}
luaL_unref(L, LUA_REGISTRYINDEX, lua_task_func->function_ref);
printf("[%s] task exiting.\n", lua_get_script_filename(L));
/* If all tasks started by the script are finished
* _before_ the main task ends, the script can be unloaded.
* Note: lua_set_cant_unload keeps a counter of tasks
* (number of calls LUA_TASK_UNLOAD_MASK)
*/
lua_set_cant_unload(L, 0, LUA_TASK_UNLOAD_MASK);
}
else
{
/* should be covered in luaCB_task_create */
ASSERT(0);
}
skip:
give_semaphore(sem);
}
else
{
printf("[%s] semaphore error: run task\n", lua_get_script_filename(L));
}
free(lua_task_func);
}
}
/***
Creates a new task. It will begin executing when you return or call task.yield()
@tparam function f the function to run
@tparam[opt] int priority
@tparam[opt] int stack_size
@function create
*/
static int luaCB_task_create(lua_State * L)
{
if(!lua_isfunction(L, 1)) return luaL_argerror(L, 1, "function expected");
LUA_PARAM_INT_OPTIONAL(priority, 2, 0x1c);
LUA_PARAM_INT_OPTIONAL(stack_size, 3, 0x10000);
struct lua_task_func * func = malloc(sizeof(struct lua_task_func));
if(!func) return luaL_error(L, "malloc error\n");
func->L = L;
func->function_ref = luaL_ref(L, LUA_REGISTRYINDEX);
char task_name[32];
static int lua_task_id = 0;
snprintf(task_name,32,"lua_run_task[%d]",lua_task_id++);
uint32_t ret = (uint32_t) task_create(task_name, priority, stack_size, lua_run_task, func);
if (ret & 1) return luaL_error(L, "task not started\n");
return 0;
}
/***
Yields execution of this script to other tasks and event handlers
(also from the same script).
FIXME: once a task executed yield(), other tasks or event handlers
from the same script, that might interrupt the former, **must not** execute yield().
Otherwise, an error will be thrown to prevent memory corruption, camera lockup or worse.
The above limitation is a very dirty hack - a proper fix should be implemented
by somebody familiar with multitasking in Lua.
Help is more than welcome, as this topic is
[not exactly our cup of tea](http://www.magiclantern.fm/forum/index.php?topic=14828.msg179227#msg179227).
TODO: replace with msleep?
@tparam int duration how long to sleep for in ms.
@function yield
*/
static int luaCB_task_yield(lua_State * L)
{
LUA_PARAM_INT(duration, 1);
/* hack: figure out whether we might be interrupting
* somebody else who called task.yield() */
if (lua_get_cant_yield(L))
{
return luaL_error(L, "FIXME: cannot use task.yield() from two tasks");
}
lua_set_cant_yield(L, 1);
lua_give_semaphore(L, NULL);
msleep(duration);
lua_take_semaphore(L, 0, NULL);
lua_set_cant_yield(L, 0);
return 0;
}
static int luaCB_task_index(lua_State * L)
{
lua_rawget(L, 1);
return 1;
}
static int luaCB_task_newindex(lua_State * L)
{
lua_rawset(L, 1);
return 0;
}
static const char * lua_task_fields[] =
{
NULL
};
const luaL_Reg tasklib[] =
{
{"create", luaCB_task_create},
{"yield", luaCB_task_yield},
{NULL, NULL}
};
LUA_LIB(task)