I just dropped in AngelScript 2.23.1 (as replacement for 2.23.0) and now my application crashes when I finally want to release the engine. I'm using VC9 under Win7.
When stepping down starting from the following call
mpEngine->Release();
the code line
asDELETE(const_cast<asCScriptEngine*>(this),asCScriptEngine);
calls the destructor of the engine:
asCScriptEngine::~asCScriptEngine()
The last line of the destructor calls
asCThreadManager::Release();
which tries to lock a crit section object:
void asCThreadCriticalSection::Enter()
{
#if defined AS_POSIX_THREADS
pthread_mutex_lock(&criticalSection);
#elif defined AS_WINDOWS_THREADS
EnterCriticalSection(&criticalSection);
#endif
}
The pointer '&criticalSection' is NULL, that's where the code crashes.
When entering the code
void asCThreadManager::Release()
{
// It's necessary to protect this section so no
// other thread attempts to call AddRef or Release
// while clean up is in progress.
ENTERCRITICALSECTION(criticalSection);
if( --threadManager->refCount == 0 )
{
// The last engine has been destroyed, so we
// need to delete the thread manager as well
asDELETE(threadManager,asCThreadManager);
threadManager = 0;
}
LEAVECRITICALSECTION(criticalSection);
}
The expression threadManager->refCount is 1 which seems to be plausible to me.
When looking at the section where the (static) instance of the csritical section should be created:
#ifndef AS_NO_THREADS
static DECLARECRITICALSECTION(criticalSection)
#endif
It seems that I do not define 'AS_NO_THREADS', i.e. this should be fine, too.
Still, the static 'criticalSection' can't be resolved by the debugger...
Do you use multiple script engines in parallel? Perhaps this is what triggers the problem.
When you debug you need to check in which scope you're looking at the criticalSection. The global static criticalSection is of the type asCThreadCriticalSection. That class in itself as a member also called criticalSection (poorly named, I know). It is possible the debugger is seeing one or the other depending on where you're checking.
Do you use multiple script engines in parallel? Perhaps this is what triggers the problem.[/quote]
No, I'm just using one single script engine instance, created through the following code:
mpEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
I'll check again with the scope of the criticalSection during the debug session and post again.
I checked in a minor change in 1291 where I renamed the criticalSections. The global one is now prefixed with 'g_' and the member is prefixed with 'm_'.
I made a test with multiple engines, but it seems to be working properly too.
OK, here's some more information:
I renamed the global criticalSection object (statically allocated in as_Thread.cpp) to 'gCriticalSection'.
In the following code:
void asCThreadCriticalSection::Enter()
{
#if defined AS_POSIX_THREADS
pthread_mutex_lock(&criticalSection);
#elif defined AS_WINDOWS_THREADS
EnterCriticalSection(&criticalSection);
#endif
}
I have a breakpoint on the 'ENterCriticalSection...' line.
My watch window output is attached.
Does that help?
One more observation:
The criticalSection member is initialized during the constructor of asCThreadCriticalSection:
#ifndef AS_NO_THREADS
asCThreadCriticalSection::asCThreadCriticalSection()
{
#if defined AS_POSIX_THREADS
pthread_mutex_init(&criticalSection, 0);
#elif defined AS_WINDOWS_THREADS
InitializeCriticalSection(&criticalSection);
#endif
}
For the global gCriticalSection there is no call to 'InitializeCriticalSection(...)'. Could this be an issue?
Not yet. I haven't done any fixes in the new revision.
But there is definitely something wrong. When I set a breakpoint on EnterCriticalSection in my test bed I get the following values in the member criticalSection:
DebugInfo -> address of an object that holds valid information
LockCount -> -1
The rest of the members are 0.
It looks like the criticalSection in your application has somehow become corrupt. Probably some memory invasion that overwrote the global memory.
I suggest setting a memory break point on the gCriticalSection->criticalSection->DebugInfo to see when the address changes. It should only change once, when the InitializeCriticalSection() is called on start up.
One more observation:
The criticalSection member is initialized during the constructor of asCThreadCriticalSection:
#ifndef AS_NO_THREADS
asCThreadCriticalSection::asCThreadCriticalSection()
{
#if defined AS_POSIX_THREADS
pthread_mutex_init(&criticalSection, 0);
#elif defined AS_WINDOWS_THREADS
InitializeCriticalSection(&criticalSection);
#endif
}
For the global gCriticalSection there is no call to 'InitializeCriticalSection(...)'. Could this be an issue?
Regards,
Thomas
It is the constructor of the global gCriticalSection that calls InitializeCriticalSection() on the member.