[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: my module crashes when used with lanes
- From: Benoit Germain <bgermain@...>
- Date: Fri, 11 Dec 2009 11:24:51 +0100
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