iLua Module API

iLua modules are simply DLL files that export a single function used to populate the Lua state. By default, the function should be named StartModule, but the name can be overridden in the require statement. The following function signature should be used:

extern "C" __declspec(dllexport) void StartModule(lua_State* L)

Building a module

Modules need to dynamically link to Lua core library. The version currently used is 5.2.1, built with Visual Studio 2010. Additionally, a small set of header/source files is available to allow modules to interact with the core engine, as described below.

Multithreading considerations

Since the engine tries to simulate multithreading, additional constraints are placed on C functions. All functions that can take a long time to execute should suspend the Lua thread and return immediately, while doing the processing in a separate Windows thread. When finished, the Lua thread should be resumed. The ilua::SlowOperation class is provided to simplify this process.

When calling a Lua function from C, keep in mind that the engine might force it to yield. In this case, Lua will raise an error unless a continuation function was specified in lua_callk. This makes the design of such functions fairly complicated, see the source code for examples (for example, re_sub in core/api/regexp.cpp).

Library contents

ilua.h contains Lua helper functions, functions for creating new data types, and core module interfaces. slowop.h contains a helper class for slow C functions. stream.h defines a base class for data streams.

void luaL_printf(luaL_Buffer *B, const char *fmt, ...)
Appends formatted text to buffer B (see luaL_Buffer).
void ilua::openlib(lua_State* L, char const* name)
Pushes an existing or new global table named name on the stack.
void ilua::bindmethod(lua_State* L, char const* name, lua_CFunction func)
Sets the C function func as field name of the table on top of the stack. Equivalent to the following:
lua_pushcfunction(L, func);
lua_setfield(L, -2, name);
void ilua::settabss(lua_State* L, char const* n, char const* s)
void ilua::settabsi(lua_State* L, char const* n, int i)
void ilua::settabsn(lua_State* L, char const* n)
int ilua::gettabsi(lua_State* L, int idx, char const* n)
Inline functions to set a field of the table on top of the stack to a string, integer and nil, respectively. Last function reads an integer field.
int ilua::ycall(lua_State* L, int args, int ret)
Call lua_callk with continuation function that keeps all results on the stack. Use in a return statement in case the function doesn't yield.
int ilua::checkoption(lua_State* L, int narg, const char* def, const char* const lst[])
Same as luaL_checkoption, but allows integer arguments.
template<class T>
void newtype(lua_State* L, char const* name = NULL, char const* parent = NULL)
Define a new userdata type. name specifies type name; it is recommended to use lowercase names with periods to separate namespaces. parent optionally specifies the type to inherit from, this copies all parent methods to the new metatable.
Pushes both the metatable and its __index table on the stack. The __newindex metamethod points to a function that creates a new metatable for the object to allow the caller to store additional fields in it (see ilua::totable below).
bool ilua::iskindof(lua_State* L, char const* name, char const* base)
Check if name is a type equal to or derived from base.
void* operator new(size_t count, lua_State* L, char const* name)
Custom allocator for declared object types. Use:
ilua::newtype<Foo>(L, "foo");
...
Foo* ptr = new(L, "foo") Foo(...);
template<class T>
T* ilua::newstruct(lua_State* L, char const* name = NULL, size_t size = sizeof(T))
Alternative allocator for simple types. Do not use with types derived from ilua::Object. Optionally, allows to allocate more space than the structure requires.
bool ilua::iskindof(lua_State* L, int pos, char const* name)
Check if a value at index pos is an object of type name or of a derived type.
template<class T>
bool ilua::iskindof(lua_State* L, int pos)
Similar to the previous function but determines name from the template type (and thus is a bit slower).
template<class T>
T* ilua::toobject(lua_State* L, int pos, char const* name = NULL)
Return a userdata pointer for value at index pos if it is of the correct type, NULL otherwise. If name is omitted, type is determined from the template argument.
template<class T>
T* ilua::tostruct(lua_State* L, int pos)
Similar to the above for internal unnamed data types that are not meant to be accessible from the script.
template<class T>
T* ilua::checkobject(lua_State* L, int pos, char const* name = NULL)
template<class T>
T* ilua::checkstruct(lua_State* L, int pos)
Same as the two previous functions but instead of returning NULL, a Lua error is generated.
int ilua::totable(lua_State* L, int pos)
Creates a new index table for the object so that it can store additional values not defined by the object type. This also allows the lua script to access the object as if it was a table. The following charts show how the object layout changes after this function:
class ilua::Object
Generic base class for Lua objects. Types derived from Object have the following additional functionality:
  • Automatically receive engine pointer on creation (through protected member variable e);
  • Can be pushed on the stack by pointer with ilua::pushobject;
  • Have a reference counter that prevents the object from being garbage collected as long as it is non-zero;
Types derived from Object should only be constructed with the new operator defined above.
int addref()
int release()
int refcount()
Increment, decrement and get the reference counter of an Object. Objects that have non-zero reference count cannot be garbage collected. Initial reference count is zero.
void ilua::pushobject(lua_State* L, Object* obj)
Push an object onto the stack by its pointer. Only works with types derived from Object.
class ilua::Engine
Provides an interface to the iLua engine. To get the engine interface for a Lua state, use the engine() function.
ilua::Thread* load(char const* file)
Load a Lua file and execute it in a new thread. Returns the new thread object, or NULL. Errors will be displayed in the editor.
bool load_module(char const* name, char const* entry = NULL)
Load a DLL module and calls its entry point on the current state. Duplicate calls are ignored. The default entry point is "StartModule".
lua_State* lock()
void unlock()
Pause/unpause the engine and return a pointer to the Lua state of the current thread. If the stack is modified, it has to be returned to the original state before calling unlock.
int get_counter(int id)
void set_counter(int id, int value)
Get/set the value of a counter. A counter ID can be specified when creating a thread, which will decrement the counter by 1 and increment it when the thread terminates. This can be used to limit the number of parallel executions of an event: specify the initial value with set_counter, and check if the counter is not zero before starting a new thread. ID has to be a positive integer (not 0).
ilua::Thread* create_thread(int narg, int counter = 0)
Create a new thread. To create a thread, push a function on the stack, followed by its arguments. Then call create_thread; narg is the number of arguments pushed onto the stack. counter can be set to a valid counter ID, see the previous functions for explanation.
ilua::Thread* current_thread()
Returns the thread currently being executed. NULL can be returned while transitioning to a new thread, or when no threads are in the queue.
void keepalive()
By default, the engine terminates when all threads have exited (this includes suspended threads, in case they are waiting for a C function to return). Calling keepalive once will prevent the engine from terminating until exit is called explicitly. There is no way to undo this action.
void exit(int code)
Terminates the engine with the specified exit code.
ilua::Engine* ilua::engine(lua_State* L)
Returns the engine interface associated with a Lua state.
class ilua::Thread : public ilua::Object
Represents a Lua thread.
lua_State* state()
Returns the Lua state associated with the thread. Do not attempt to modify the state while the engine is running (use Engine::lock/unlock).
void suspend()
Suspends the thread. Does not yield if the thread was currently running - use lua_yield after calling suspend.
void terminate()
Terminate the thread. Does not yield if the thread was currently running - use lua_yield.
int yield(lua_CFunction cont = NULL, int ctx = 0)
Use instead of lua_yield to pass execution to the next thread. Calling lua_yield directly (without calling suspend or terminate first) will not re-queue the thread, which causes undefined behavior.
int sleep(int time, lua_CFunction cont = NULL, int ctx = 0)
Same as yield but waits the specified number of milliseconds before the thread is allowed to execute. Threads paused with this function have a higher priority than normal threads.
void resume(Object* rc = NULL)
Resume a suspended thread. All values pushed onto the stack since the suspend well be passed as arguments to the continuation function. If rc object is specified, it is also pushed onto the stack and added as an argument.
void lock()
void unlock()
Locking prevents the thread from yielding. Do not abuse - Lua code should try to use synchronization primitives instead.
int id()
Returns thread ID. Threads are assigned consecutive integers, starting with 1 (the ID of the main thread).
int status()
Returns 0 if the thread is still running, 1 if the thread finished execution successfully, -1 in case an error occured.
void* newdata(int size)
void* data()
Allows attaching a block of opaque data to a thread. Creating a block of data will destroy the old block if there was one - only use for private threads.
class ilua::SlowOperation
Base class for slow C functions that suspends the thread while the operation is executing. Below is a sample use case:
class BnIsPrime : public ilua::SlowOperation
{
  bn::Number* num;
  int nchecks;
public:
  BnIsPrime(bn::Number* a, int checks) : num(a), nchecks(checks) {}
  void run()
  {
    int isprime = bn::isprime(num, nchecks);
    lua_State* L = output_begin();
    lua_pushboolean(L, isprime);
    output_end(1);
  }
};

static int bn_isprime(lua_State* L)
{
  bn::Number* a = bn_get(L, 1);
  int checks = luaL_optinteger(L, 2, 0);
  return (new(L) BnIsPrime(a, checks))->start(L);
}
We derive a class from ilua::SlowOperation that defines the run method. Inside that method we perform the calculations, and call output_begin/output_end to return the output to Lua (the engine is paused between these two calls). To run the operation, we create an instance of our class with a custom allocator and call its start method.
virtual void run() = 0
Derived classes should provide an implementation for this method. It will be called in a separate Windows thread.
lua_State* output_begin()
void output_end()
Locks the engine and returns a pointer to the thread state. Returned values should be pushed onto the stack between these two calls Lua state should not be accessed outside of these calls. If these functions are not called, it is assumed that there are no return values.
int start(lua_State* L)
Suspends the current thread, starts the operation and yields execution. Use as part of the return statement.
void* operator new(size_t sz, lua_State* L)
Allocator that creates the object on Lua stack.
class ilua::Stream : public ilua::Object
Base class for data streams such as files. Most functions have empty default implementations for streams that do not support those operations.
virtual char getc()
virtual int putc(char c)
Overridable methods for reading/writing a single character. putc should return the number of bytes written - that is, 0 or 1. Default implementation calls read/write.
virtual int read(void* buf, int count)
virtual int write(void const* buf, int count)
Overridable methods for reading/writing a chunk of data. Return the number of bytes read/written.
virtual void seek(int64 pos, int rel)
Overridable method to change current position. pos specifies the offset from base position defined by rel (SEEK_CUR from current position, SEEK_SET from beginning of file, SEEK_END from end of file).
virtual int64 tell()
Overridable method to retrieve current position.
virtual int64 size()
Overridable method to retrieve total stream size.
virtual bool eof()
Overridable method to check whether the current position is at the end of file (defaults to tell() >= size()).
virtual void resize(int64 newsize)
Overridable method to change stream size. Attempting to write past the end of stream should also resize it.
virtual void flush()
Overridable method to flush any buffered operations.
unsigned short read16(bool big = false)
unsigned long read32(bool big = false)
float readfloat(bool big = false)
double readdouble(bool big = false)
Read a 16-bit, 32-bit integer, a 32-bit float, or a 64-bit double. Optionally reverses byte order.
void write16(unsigned short n, bool big = false)
void write32(unsigned long n, bool big = false)
void writefloat(float f, bool big = false)
void writedouble(double f, bool big = false)
Write a 16-bit, 32-bit integer, a 32-bit float, or a 64-bit double. Optionally reverses byte order.
int readstr(char* str, int size)
void writestr(char const* str)
Read/write a null terminated string. readstr reads up to size characters and returns the number of characters read (not including the null terminator).
virtual int64 copy(Stream* stream, int64 count = 0)
Copy up to count bytes from stream (specify 0 to copy all available bytes), equivalent to a combination of read/write. Can be overridden to provide a faster implementation (e.g. read directly to stream memory).
void serialize(lua_State* L, int index)
void deserialize(lua_State* L)
Write/read a binary chunk representing a Lua value. Accepts a nil, number, string, Lua function or a table containing listed types. Supports recursive tables and metatables. Note that it does not check Lua functions for validity, do not use on untrusted data (see Lua manual).
virtual const char* tolstring(size_t* len)
Optional method to return the entire stream contents to a string. Intended for buffer objects.
void stream_noseek(lua_State* L)
void stream_noread(lua_State* L)
void stream_nowrite(lua_State* L)
Remove all methods associated with seeking/reading/writing from the __index table on top of the stack, for stream types that do not support those operations.
int isbuffer(lua_State* L, int index)
Check if the value at a given index is a stream object or a string. Does not check if the stream supports the tolstring operation.
char const* tobuffer(lua_State* L, int index, size_t* len)
char const* checkbuffer(lua_State* L, int index, size_t* len)
char const* optbuffer(lua_State* L, int index, char const* d, size_t* len)
If the value at a given index is a stream, call its tolstring operation. Otherwise, call the default lua_tostring/luaL_checklstring/luaL_optlstring functions. Intended for functions that may want to accept buffer objects in addition to strings.
void pushbuffer(lua_State* L, void const* data, size_t length)
Create a buffer object from data and push it onto the stack. Initial position will be set to the beginning of stream.

RivSoft.net by Riv (riv@rivsoft.net) - All rights reserved