autoLoader/threadData.cpp

autoLoader/threadData.cpp
//
// Copyright 2012 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk license
// agreement provided at the time of installation or download, or which
// otherwise accompanies this software in either electronic or hard copy form.
//
//-----------------------------------------------------------------------------
#include "StdAfx.h"
#if !defined( OSWin_ )
#include <unistd.h>
#endif
#include "threadData.h"
#include <maya/MCommonSystemUtils.h>
/*static*/ volatile bool threadData::bThreadToExecute =true ;
/*static*/ volatile bool threadData::bWaitingForCommand =false ;
static threadData tdata ;
struct _threadData *threadData::getThreadData () {
return (&tdata) ;
}
//-----------------------------------------------------------------------------
// Compute function. This function is called from multiple asynchronous threads
MThreadRetVal threadData::AsyncModuleThread (void *data) {
threadData *myData =(threadData *)data ;
while ( threadData::bThreadToExecute ) {
int ithreadDataDelay =threadDataDelayDefault ;
char *val =getenv (threadDataDelayName) ;
if ( val != NULL && *val != _T('\0') )
ithreadDataDelay =atoi (val) ;
MModuleLogic::ModuleDetectionLogicCmdExecute (myData) ;
#if defined(_WIN32) || defined(_WIN64)
Sleep (ithreadDataDelay * 1000) ;
#else
sleep (ithreadDataDelay) ;
#endif
}
return (0) ;
}
//-----------------------------------------------------------------------------
// Variable to track threads. As each thread finishes it's work it
// increments this variable. The main thread will wait until this
// variable is equal to the thread count, meaning all threads have
// completed their work variable will equal the thread count
static volatile int g_async_count =0 ;
static MSpinLock asyncSpinLock ;
// Thread completion callback.
// Increment thread completion variable. Uses a lock to prevent race
// conditions where two threads attempt to update the variable simultaneously
void threadData::AsyncModuleThreadEnded (void *data) {
asyncSpinLock.lock () ;
g_async_count++ ;
asyncSpinLock.unlock () ;
}
MStatus threadData::startThread () {
// Define Thread Laps as an environment variable
if ( MCommonSystemUtils::getEnv (threadDataDelayName) == "" )
{
MCommonSystemUtils::putEnv (threadDataDelayName, szthreadDataDelayDefault) ;
}
// Start threads. Each thread makes a call to AsyncModuleThread
// The stopThread function called in uninitializePlugin() waits until
// all threads have completed (but we got only one here).
threadData::bThreadToExecute =true ;
threadData::bWaitingForCommand =false ;
if ( ms != MS::kSuccess )
return (ms) ;
threadData::AsyncModuleThread,
(void *)threadData::getThreadData (),
threadData::AsyncModuleThreadEnded,
NULL
) ;
return (ms) ;
}
//-----------------------------------------------------------------------------
// Test if variable matches the expected value. Locks required to
// ensure thread safe access to variables.
/*static*/ MSpinLock threadData::exchangeSpinLock ;
bool threadData::Maya_InterlockedCompare (volatile int *variable, int compareValue) {
exchangeSpinLock.lock () ;
bool rtn =(*variable == compareValue) ;
exchangeSpinLock.unlock () ;
return (rtn) ;
}
// Barrier function. Main thread enters here and polls the count
// variable until all worker threads have indicated they have
// completed by incrementing this count.
void threadData::WaitForAsyncThreads (int val) {
while ( !threadData::Maya_InterlockedCompare (&g_async_count, val)) {
#if defined(_WIN32) || defined(_WIN64)
Sleep (0) ;
#else
sleep (0) ;
#endif
}
}
void threadData::stopThread () {
// Ask the thread to terminate
threadData::bThreadToExecute =false ;
// Waits until all threads have completed before continuing
threadData::WaitForAsyncThreads (1) ;
MThreadAsync::release () ; // release async thread
}