On This Page
Description
LuaStepper is a module to help lua programs control simultaneous execution of multiple Lua threads without them needing to be coroutines. So it is like pre-emptive multitasking but instead of the operating system controlling the task switch and time slicing the Lua parent process does that with the API of this module.Dependencies
LuaStepper has no dependencies. It just needs Lua >= 5.1Installation and source code
Compile LuaStepper.c in the repository at Github and then copy the library module LuaStepper.dll/so to package.cpath directory and lstepper.lua to package.path directory. Or use LuaRocks to install it like:Basic Usage
The demo.lua file is in the test subdirectory of the source on Github. Once the module is installed the demo file can be directly run. The file is listed below:The demo loads 2 scripts to run in parallel and runs them. It suspends 1 script for some time and then resumes it. It also shows how to run initialization code when the script is loaded and how to read and pass data to a script.
lStepper Lua module vs LuaStepper C module
The demo shows that you just need to require lStepper which is the interface to the LuaStepper C module written in Lua. The LuaStepper C module can also be used directly but lStepper makes it easier to use the C module without any loss of functionality. lStepper requires LuaStepper and uses its API.Thread creation details
- Each thread environment contains all standard lua libraries supplied with Lua except debug, package, io and os libraries. These libraries are excluded since they can make the thread get stuck so alternatives can be provided when needed. Although if you want to provide them you can use the runCode function described in the API below.
- The environment has a table called _LS, which has the following functions and objects:
- tableToString: FUNCTION : Function to convert a table to a string. Keys can be a number, string or table, values can be number, string table or boolean. Recursive tables are handled but metatables are not handled. This function can be used to serialize and communicate data with the parent state. This is the function that is used by the LuaStepper API to communicate data to the controller state.
- Each thread runs in its separate Lua state
API Reference
lStepper
The API provided by the lua interface is accessed by requiring 'lStepper'. This is the recommended way to access the LuaStepper module.API
addTask
This adds a task to the task list. All the tasks in the task list are stepped through with the indicated number of steps when the runLoop function is executed.Syntax:
Usage Example:
Inputs:
- script - is the string containing the Lua script that is the task
- Initialization code - is an optional Lua script as a string which is executed without stepping before the actual code starts running in the environment.
- number of steps - is the optional number of steps to step the script each time runLoop executes a loop. These number of steps may not correspond to the lines of code.
- urgent pile - is an optional boolean indicating whether this task has to be placed in the urgent quota.
- NOTE: Urgent tasks are placed with task Indices beginning after the main task indices. This facility is provided to have an extra buffer to add urgent tasks without removing the normal tasks. Recommended way to use them would be add a urgent task. Suspend all the main tasks and then run the urgent task to get something done and then clean the urgent task slot and then resume the main tasks again.
- nil and a error message on failure
- task index if successful
runLoop
This runs each task in the task List with their respective indicated number of steps.Syntax:
Usage Example:
Inputs:
- number of runs - is an integer which specifies the number of times the loop has to run, by default it is run just once.
- nil if there are no tasks
- nil and error message if failure
- table with keys as the task index and the values are tables with at most 2 elements representing the status of each task in the pile. The 1st element of each status table can be:
- GOOD - Task is running good
- FIN - Task Finished
- ERROR - Task produced an error and stopped. The second element is the error message
- NE-PREVERR - Task was not executed because it had a previous error. Second element is the Error code type i.e."LUA_ERRRUN" or "LUA_ERRMEM"
- NE-FIN - Task was not executed because it finished already
- NE-SUSPEND - Task was not executed because it was suspended before
- In case of multiple loop runs the status is what was generated in the last iteration.
suspendTask
Suspends a task's execution till resumed by calling resumeTask.Syntax:
Usage Example:
Inputs:
- task index- index of the task that needs to be suspended
- nil and a error message in case of failure
- nil if the task did not exist or had already finished or suspended.
- true if suspend was successful
resumeTask
Resumes a suspended task's execution.Syntax:
Usage Example:
Inputs:
- task index- index of the task that needs to be resumed
- nil and a error message in case of failure
- nil if the task did not exist or was not suspended or was finished.
- true if resume was successful
taskStatus
To poll the status of a taskSyntax:
Usage Example:
Inputs:
- task index - index of the task whose status is being queried
- nil and a error message in case of failure
- GOOD - Task is running good
- SUSPENDED - Task is in suspended state and is not being executed when runLoop is called
- NE-PREVERR - Task exited with an error when it was last executed. Second return is the Error code type i.e."LUA_ERRRUN" or "LUA_ERRMEM"
- NE-FIN - Task finished already
setTaskData
To pass data to a task's environmentSyntax:
Usage Example:
Inputs:
- task index - index of the task to which data has to be passed
- data table - table containing key value pairs that have to be set in the task's Lua environment. It would overwrite same keys all values in the Global environment of the task. The keys can be number or string while the values can be string, number, boolean or table
- nil and a error message if error
- true if successful
getTaskData
To read data from a task's environmentSyntax:
Usage Example:
Inputs:
- task index - index of the task to which the table has to be passed
- variable name - name of the variable in the task's global environment whose value is to be retrieved
- nil and a error message if error
- the value if success
getNumOfTasks
To return the number of tasks in the tasks listSyntax:
Usage Example:
Returns:
- nil and error message if error
- number of tasks in the task List as the 1st return and number of urgent tasks in the list as the 2nd return
closeTask
The close the task and free up its index in the listSyntax:
Usage Example:
Inputs:
- task index - index of the task which is to be closed
- nil if task was not there at the index
- nil and error message if error
- true if successful
registerCallBack
To register a callback function with LuaStepper. This function is accessible to any task's runCode function and other function it creates by calling lstep.callParentFunc. That means you can call this registered function by doing the following:So this allows passing arguments directly to your parent. Another way could be exposing a function to the thread which can then in turn call the call back function. So we could have:
Here runCode exposed a function called newFunc to the thread code which can pass data to the call back function and also tells the call back function about its own name so the call back function can detect where the call came from and take appropriate action and return the result.
The Call back function
The call back function is called with the 1st argument as the task index followed by all the arguments passed to the call back function in the task. So in the above case the call back function call would be something like this:
The second argument being the function name is not enforced but should be followed since when the task calls require the call back function is called with its second argument "require". So following this standard would lead to consistent call back function programming.
The call back function can return 2 values. Both may be strings, the 1st can be nil.
By default the require function exposed to the task's code uses the call back function to allow exposing external code to the thread. So if you don't have any call back registered in LuaStepper then require won't work in any task's code. So when the thread code calls require it calls this call back function to tell the parent thread of the require request.
Syntax:
Usage Example:
Inputs:
- callback - Call back function to be exposed to all thread's runCode function
- nil and error message if error
- true if success
runCode
Allows the parent thread to run some code in the thread environment without doing the stepping. This is useful to provide resources as requested by the thread in the thread environment.Syntax:
Usage Example:
Inputs:
- task index - index of the task where the code needs to be run
- Lua Code - Lua code script to run
- nil and error message if error
- true if success
The environment in which the code runs is the global environment of the thread plus it has access to the following extra functions/tables which the thread cannot access:
- pack table - containing the original package table
- req function - containing the original require function
- lstep table - table containing special functions used by the thread management functions. It is only accessible via runCode or with functions provided to the task by runCode. Its members are:
- callParentFunc - Function that calls the function that is registered by the parent thread using registerCallBack
- getswitchstatus - which toggles between -1 and 1 for every switch that LuaStepper does away from the task. This can be used by the thread management functions to detect a switch.
- oslib library - containing the original os library
- iolib library - containing the original io library
Objects
_VERSION
Returns the version number of the moduleLuaStepper
The API provided by the LuaStepper C module is accessed by requiring 'LuaStepper'. Although this can be used directly the Lua interface is the preferred way of accessing the LuaStepper module.API
The API functions are as follows:addTask
This adds a task to the task list. All the tasks in the task list are stepped through with the indicated number of steps when the runLoop function is executed.Syntax:
Usage Example:
Inputs:
- script - is the string containing the Lua script that is the task
- Initialization code - is an optional Lua script as a string which is executed without stepping before the actual code starts running in the environment.
- number of steps - is the optional number of steps to step the script each time runLoop executes a loop. These number of steps may not correspond to the lines of code.
- urgent pile - is an optional boolean indicating whether this task has to be placed in the urgent quota.
- NOTE: Urgent tasks are placed with task Indices beginning after the main task indices. This facility is provided to have an extra buffer to add urgent tasks without removing the normal tasks. Recommended way to use them would be add a urgent task. Suspend all the main tasks and then run the urgent task to get something done and then clean the urgent task slot and then resume the main tasks again.
- nil and a error message on failure
- task index if successful
runLoop
This runs each task in the task List with their respective indicated number of steps.Syntax:
Usage Example:
Inputs:
- number of runs - is an integer which specifies the number of times the loop has to run, by default it is run just once.
- nil if there are no tasks
- nil and error message if failure
- table with keys as the task index and the values are tables with at most 2 elements representing the status of each task in the pile. The 1st element of each status table can be:
- GOOD - Task is running good
- FIN - Task Finished
- ERROR - Task produced an error and stopped. The second element is the error message
- NE-PREVERR - Task was not executed because it had a previous error. Second element is the Error code type i.e."LUA_ERRRUN" or "LUA_ERRMEM"
- NE-FIN - Task was not executed because it finished already
- NE-SUSPEND - Task was not executed because it was suspended before
- In case of multiple loop runs the status is what was generated in the last iteration.
suspendTask
Suspends a task's execution till resumed by calling resumeTask.Syntax:
Usage Example:
Inputs:
- task index- index of the task that needs to be suspended
- nil and a error message in case of failure
- nil if the task did not exist or had already finished or suspended.
- true if suspend was successful
resumeTask
Resumes a suspended task's execution.Syntax:
Usage Example:
Inputs:
- task index- index of the task that needs to be resumed
- nil and a error message in case of failure
- nil if the task did not exist or was not suspended or was finished.
- true if resume was successful
taskStatus
To poll the status of a taskSyntax:
Usage Example:
Inputs:
- task index - index of the task whose status is being queried
- nil and a error message in case of failure
- GOOD - Task is running good
- SUSPENDED - Task is in suspended state and is not being executed when runLoop is called
- NE-PREVERR - Task exited with an error when it was last executed. Second return is the Error code type i.e."LUA_ERRRUN" or "LUA_ERRMEM"
- NE-FIN - Task finished already
setTaskData
To pass data to a task's environmentSyntax:
Usage Example:
Inputs:
- task index - index of the task to which data has to be passed
- data table - table containing key value pairs that have to be set in the task's Lua environment. It would overwrite same keys all values in the Global environment of the task. The keys can be number or string while the values can be string, number, boolean.
- nil and a error message if error
- true if successful
setTaskTable
To pass a table to a task's environment. Note this function is not present in lStepper module since the function setTaskData there combines the functionality of this function as well.Syntax:
Usage Example:
Inputs:
- task index - index of the task to which the table has to be passed
- table name - is the name by which the table will be referenced in the task's environment
- table script - a Lua script as a string which when executed will generate the table in the value t0 in the script.
- nil and a error message in case of error
- true if success.
getTaskData
To read data from a task's environmentSyntax:
Usage Example:
Inputs:
- task index - index of the task to which the table has to be passed
- variable name - name of the variable in the task's global environment whose value is to be retrieved
- nil and a error message if error
- the value if the value was of the type string, number, boolean
- the table as a table generation script string and "TABLE" if the value was a table. To convert the string to the table simply load and execute the string and take the value of 't0' from the execution environment.
getNumOfTasks
To return the number of tasks in the tasks listSyntax:
Usage Example:
Returns:
- nil and error message if error
- number of tasks in the task List as the 1st return and number of urgent tasks in the list as the 2nd return
closeTask
The close the task and free up its index in the listSyntax:
Usage Example:
Inputs:
- task index - index of the task which is to be closed
- nil if task was not there at the index
- nil and error message if error
- true if successful
registerCallBack
To register a callback function with LuaStepper. This function is accessible to any task's runCode function and other function it creates by calling lstep.callParentFunc. That means you can call this registered function by doing the following:So this allows passing arguments directly to your parent. Another way could be exposing a function to the thread which can then in turn call the call back function. So we could have:
Here runCode exposed a function called newFunc to the thread code which can pass data to the call back function and also tells the call back function about its own name so the call back function can detect where the call came from and take appropriate action and return the result.
The Call back function
The call back function is called with the 1st argument as the task index followed by all the arguments passed to the call back function in the task. So in the above case the call back function call would be something like this:
The second argument being the function name is not enforced but should be followed since when the task calls require the call back function is called with its second argument "require". So following this standard would lead to consistent call back function programming.
The call back function can return 2 values. Both may be strings, the 1st can be nil.
By default the require function exposed to the task's code uses the call back function to allow exposing external code to the thread. So if you don't have any call back registered in LuaStepper then require won't work in any task's code. So when the thread code calls require it calls this call back function to tell the parent thread of the require request.
Syntax:
Usage Example:
Inputs:
- callback - Call back function to be exposed to all thread's runCode function
- nil and error message if error
- true if success
runCode
Allows the parent thread to run some code in the thread environment without doing the stepping. This is useful to provide resources as requested by the thread in the thread environment.Syntax:
Usage Example:
Inputs:
- task index - index of the task where the code needs to be run
- Lua Code - Lua code script to run
- nil and error message if error
- true if success
The environment in which the code runs is the global environment of the thread plus it has access to the following extra functions/tables which the thread cannot access:
- pack table - containing the original package table
- req function - containing the original require function
- lstep table - table containing special functions used by the thread management functions. It is only accessible via runCode or with functions provided to the task by runCode. Its members are:
- callParentFunc - Function that calls the function that is registered by the parent thread using registerCallBack
- getswitchstatus - which toggles between -1 and 1 for every switch that LuaStepper does away from the task. This can be used by the thread management functions to detect a switch.
- oslib library - containing the original os library
- iolib library - containing the original io library
Objects
_VERSION
Returns the version number of the moduleTo Do
- Add function for utility code to yield the thread it is running in
- Implement coroutine.wrap in the thread code.