lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



First of all, gluax is a layer above the Lua C/API, which I personally find too low level for most binding usage. Don't take me wrong, it's perfect for really what it's for: embedding and extending, it gives all the keys. But.. binding code made in pure Lua/ C API is not very readable. Gluax does things s.a. calculating the number of return values pushed automatically; thus eliminating little potential coding errors, and making bindings generally more pleasant to write.

All one needs to use gluax is gluax.h and gluax.c (but more of that some other time?).

The threading issue is but a little part of gluax features. It has a C-side queue for this case, with the following functions:

void _glua_queue_attach( lua_State *L,
                         struct s_Glua_Queue** qref,
                         int closure_argn,
                         uint /*enum e_Glua_QueuePolicy*/ policy );

bool_int _glua_queue_add( struct s_Glua_Queue* queue,
                          void* p,
                          uint /*size_t*/ bytes,
                          uint style );

bool_int _glua_queue_run( lua_State *L,
                          struct s_Glua_Queue* queue );

#define glua_queue_detach( qref ) \
       _glua_queue_attach( _lua_, qref, 0, 0 )

#define glua_queue_run(q)  _glua_queue_run( _lua_, (q) )

Attach is called to set a callback, given a closure on the Lua stack.

Detach removes such binding.

Add takes no lua_State parameter, and can thus be called from other threads; it collects the data provided to it, into a FIFO buffer (or queue) which is emptied when the lua_State has time to go poll it.

Run reduces the FIFO, and calls the closure associated with the data queue to actually handle the data, which was provided from the alien thread, which in turn would come from an interrupt routine.

The 'run' call needs of course be actively polled by the lua_State. There is no concept of asynchronous interrupts in Lua, but the queue poll concept could easily be placed within a coroutine of its own, thus suiting the Lua ideology rather nicely.

What I did, is have the SDL event loop call 'run' if no SDL events were incoming. This keeps GUI responsiveness first, but handles the interrupt-provided data flow very fluently, as well. In fact, I was astound when running the SDL_Mixer demos. They're visually showing music waveforms, while playing the sounds, in all Lua, in real time. This requires about a 1GHz processor, with slower ones the sw works fine but some of the samples are lost (that's why the queing has parameters for allowing loss of data).

Below is the full API section dealing with these features of gluax. It's only about 3% of all gluax API has to offer (60 lines out of 1800). (( This must be the first time I'm implying having lots of lines would actually be good... :))

- Asko




/*--- Asynchronous callbacks -----------*/
//
// Async callbacks (those provided in a separate thread, s.a. SDL_Mixer events) // need to be passed to Lua through a queue. Lua state may not be manipulated
// by the alien threads.

struct s_Glua_Queue;     // opaque implementation details

enum e_Glua_QueuePolicy
{
    // Note: don't change the values, they're part of module ABI!
    GLUA_QUEUE_KEEP_ALL= 0,    // default: keep all data (nothing lost)
GLUA_QUEUE_KEEP_FIRST= 1, // keep first data (lose later until buffer read) GLUA_QUEUE_KEEP_LAST= 2, // keep last data (lose earlier, non- read data)
};

// Array style values are the same as SDL_Mixer's Uint16 'audio_format':
//
#define GLUA_QUEUE_ARRAY_SIGNED (0x8000)
//#define GLUA_QUEUE_ARRAY_TWISTED (0x1000)   // MSB/LBS twist

#if (defined PLATFORM_WIN32) || (defined PLATFORM_WINCE)
#define GLUA_QUEUE_ARRAY_MESSEDUP (0x0800) // special flag to fix an SDL_Mixer bug?
#endif

#define GLUA_QUEUE_ARRAY_S8   (8 | GLUA_QUEUE_ARRAY_SIGNED)
#define GLUA_QUEUE_ARRAY_U8    8
#define GLUA_QUEUE_ARRAY_S16 (16 | GLUA_QUEUE_ARRAY_SIGNED)
#define GLUA_QUEUE_ARRAY_U16  16
#define GLUA_QUEUE_ARRAY_S32 (32 | GLUA_QUEUE_ARRAY_SIGNED)
#define GLUA_QUEUE_ARRAY_U32  32

void _glua_queue_attach( lua_State *L,
                         struct s_Glua_Queue** qref,
                         int closure_argn,
                         uint /*enum e_Glua_QueuePolicy*/ policy );

bool_int _glua_queue_add( struct s_Glua_Queue* queue,
                          void* p,
                          uint /*size_t*/ bytes,
                          uint style );

bool_int _glua_queue_run( lua_State *L,
                          struct s_Glua_Queue* queue );

#define glua_queue_attach( qref, argn, policy ) \
       _glua_queue_attach( _lua_, qref, argn, policy )

#define glua_queue_detach( qref ) \
       _glua_queue_attach( _lua_, qref, 0, 0 )

#define glua_queue_add( q ) \
       _glua_queue_add( q, NULL, 0, 0 )

#define glua_queue_add_int( q, v ) \
       _glua_queue_add( q, &(v), sizeof(int), GLUA_QUEUE_ARRAY_S32 )

#define glua_queue_add_intarray   _glua_queue_add

#define glua_queue_run(q)  _glua_queue_run( _lua_, (q) )



Sam Roberts kirjoitti 6.12.2006 kello 21.22:

On Wed, Dec 06, 2006 at 12:57:48AM +0200, Asko Kauppi wrote:
Use a completely separate dispatch system, to also cover thread
issues.

Cover how?

Callbacks are often thrown from threads other than the one
  ^^^^^^^^^ errors?
where Lua state is running.

And what does gluax do when this occurs?

gluax has such. Lua/C API does not.

I can't even figure out what gluax is for... it appears to be a
duplicate of the lua c api, but minus the state parameter.

Sam