lua-users home
lua-l archive

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


Hello,

I have a module implemented in the form of a full userdata object with a metatable, so that it can get __gc event when collected. Init and  gc are as follows :

struct XbdmUD
{
        HRESULT hr;
        DWORD threadId;
};


int luaxbdm_gc( lua_State * L)
{
        XbdmUD * const ud = static_cast<XbdmUD *>( lua_touserdata( L, 1));
        if( GetCurrentThreadId() != ud->threadId)
        {
                return luaL_error( L, "__gc called from wrong thread!");
        }
        if( ud->hr == S_OK || ud->hr == S_FALSE)
        {
                CoUninitialize();
        }
        return 0;
}

__declspec(dllexport) int luaopen_xbdm( lua_State *L)
{
        // the module will be a full userdata with a metatable containing the exposed interface,
        // so that we get notified of garbage collection and perform cleanup properly
        XbdmUD * const ud = static_cast<XbdmUD *>( lua_newuserdata(L, sizeof(XbdmUD)));          // ud
        // needed to have working COM operations...
        ud->hr = CoInitializeEx( 0x0, COINIT_APARTMENTTHREADED|COINIT_SPEED_OVER_MEMORY);
        ud->threadId = GetCurrentThreadId();
        lua_newtable( L);                                                                        // ud {}
        luaL_register( L, 0x0, gXbdm);                                                           // ud {}
        // we don't want scripts to append items to the module
        lua_pushstring( L, "__newindex");                                                        // ud {} "__newindex"
        lua_pushboolean( L, 0);                                                                  // ud {} "__newindex" false
        lua_rawset( L, -3);                                                                      // ud {...}
        // we want scripts to be able to access the interface
        lua_pushstring( L, "__index");                                                           // ud {...} "__index"
        lua_pushvalue( L, -2);                                                                   // ud {...} "__index" {...}
        lua_rawset( L, -3);                                                                      // ud {...}
        // we want to get notified when the module is unloaded
        lua_pushstring( L, "__gc");                                                              // ud {...} "__gc"
        lua_pushcfunction(L, luaxbdm_gc);                                                        // ud {...} "__gc" func
        lua_rawset( L, -3);                                                                      // ud {...}
        // we don't want scripts to meddle with the metatable
        lua_pushstring( L, "__metatable");                                                       // ud {...} "__metatable"
        lua_pushboolean( L, 0);                                                                  // ud {...} "__metatable" 0
        lua_rawset( L, -3);                                                                      // ud {...}
        // done!
        lua_setmetatable( L, -2);                                                                // ud
        // the module loader won't create the global for us, so do it now
        lua_pushvalue( L, -1);                                                                   // ud ud
        lua_setglobal( L, "xbdm");                                                               // ud
        return 1;
}

M$ doc says that CoInitializeEx and CoUninitialize must be called in pairs from each thread using COM.

However, I get an error using the following script :

require "lanes"
require "xbdm" -- causes xbdm init -> CoInitialize in main thread

local function laneFunc()
                require "xbdm" -- causes xbdm init -> CoInitialize in lane thread
                --local manager = xbdm.getManager()
end

local lanegen = lanes.gen( "package", laneFunc)
local mylane = lanegen() -- lane thread starts -> xbdm required -> CoInitialize called in lane thread
mylane:join() -- lane thread terminates -> xbdm collected -> CoUnititialize not in the lane thread but in main thread!!!

local manager = xbdm.getManager() -- -> wants to get a COM object, fails with "CoInitialize was not called" error!


As you can see, luaopen_xbdm is called from the main thread when my module is required for the first time, but when the lane terminates, the gc event is called on the correct lua_State, but from the main thread, which 
1/ leaves a dangling init from the lane thread
2/breaks the initialisation in the main thread preventing further use of the module.

Is there some way of telling the lane to require my module so that it gets collected in the proper thread, or is this a lanes bug ?

Thanks,


Benoit