/**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_rwlockCreate( F_RWLOCK * phReadWriteLock) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = NULL; if( RC_BAD( rc = f_calloc( sizeof( F_RWLOCK_IMP), &pReadWriteLock))) { goto Exit; } pReadWriteLock->hMutex = F_MUTEX_NULL; if( RC_BAD( rc = f_mutexCreate( &pReadWriteLock->hMutex))) { goto Exit; } *phReadWriteLock = (F_RWLOCK)pReadWriteLock; pReadWriteLock = NULL; Exit: if( pReadWriteLock) { f_rwlockDestroy( (F_RWLOCK *)&pReadWriteLock); } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE F_IOBufferMgr::setupBufferMgr( FLMUINT uiMaxBuffers, FLMUINT uiMaxBytes, FLMBOOL bReuseBuffers) { RCODE rc = NE_FLM_OK; f_assert( uiMaxBuffers); f_assert( uiMaxBytes); if( RC_BAD( rc = f_mutexCreate( &m_hMutex))) { goto Exit; } #if !defined( FLM_UNIX) && !defined( FLM_NLM) if( RC_BAD( rc = f_semCreate( &m_hAvailSem))) { goto Exit; } #endif m_uiMaxBuffers = uiMaxBuffers; m_uiMaxBufferBytes = uiMaxBytes; m_bReuseBuffers = bReuseBuffers; Exit: return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ void flmDbgLogInit( void) { char szLogPath[ 256]; RCODE rc = NE_SFLM_OK; flmAssert( g_hDbgLogMutex == F_MUTEX_NULL); // Allocate a buffer for the log if (RC_BAD( rc = f_alloc( DBG_LOG_BUFFER_SIZE + 1024, &g_pszLogBuf))) { goto Exit; } // Create the mutex if (RC_BAD( rc = f_mutexCreate( &g_hDbgLogMutex))) { goto Exit; } // Build the file path #ifdef FLM_NLM f_strcpy( szLogPath, "SYS:\\FLMDBG.LOG"); #else f_sprintf( szLogPath, "FLMDBG.LOG"); #endif // Create the file - truncate if it exists already. if( RC_BAD( rc = gv_SFlmSysData.pFileSystem->Create( szLogPath, XFLM_IO_RDWR | XFLM_IO_SH_DENYNONE | XFLM_IO_DIRECT, &g_pLogFile))) { goto Exit; } Exit: flmAssert( RC_OK( rc)); }
/**************************************************************************** Desc: This routine sets up a new F_Database object, allocating member variables, linking into lists, etc. NOTE: This routine assumes that the global mutex has already been locked. It may unlock it temporarily if there is an error, but will always relock it before exiting. ****************************************************************************/ RCODE F_Database::setupDatabase( const char * pszDbPath, const char * pszDataDir) { RCODE rc = NE_XFLM_OK; FLMUINT uiAllocLen; FLMUINT uiDbNameLen; FLMUINT uiDirNameLen; char szDbPathStr[ F_PATH_MAX_SIZE]; char szDataDirStr[ F_PATH_MAX_SIZE]; if( RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathToStorageString( pszDbPath, szDbPathStr))) { goto Exit; } uiDbNameLen = f_strlen( szDbPathStr) + 1; if( pszDataDir && *pszDataDir) { if( RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathToStorageString( pszDataDir, szDataDirStr))) { goto Exit; } uiDirNameLen = f_strlen( szDataDirStr) + 1; } else { szDataDirStr[0] = 0; uiDirNameLen = 0; } if (RC_BAD( rc = f_mutexCreate( &m_hMutex))) { goto Exit; } uiAllocLen = (FLMUINT)(uiDbNameLen + uiDirNameLen); if (RC_BAD( rc = f_alloc( uiAllocLen, &m_pszDbPath))) { goto Exit; } // Allocate a buffer for writing the DB header // If we are a temporary database, there is no need // for this allocation. if (!m_bTempDb) { if( RC_BAD( rc = f_allocAlignedBuffer( XFLM_MAX_BLOCK_SIZE, (void **)&m_pDbHdrWriteBuf))) { goto Exit; } } // Setup the write buffer managers. if( RC_BAD( rc = FlmAllocIOBufferMgr( MAX_PENDING_WRITES, MAX_WRITE_BUFFER_BYTES, FALSE, &m_pBufferMgr))) { goto Exit; } // Initialize members of F_Database object. m_uiBucket = 0xFFFF; m_uiFlags = DBF_BEING_OPENED; // Copy the database name and directory. // NOTE: uiDbNameLen includes the null terminating byte. // and uiDirNameLen includes the null terminating byte. f_memcpy( m_pszDbPath, szDbPathStr, uiDbNameLen); if (uiDirNameLen) { m_pszDataDir = m_pszDbPath + uiDbNameLen; f_memcpy( m_pszDataDir, szDataDirStr, uiDirNameLen); } // Link the file into the various lists it needs to be linked into. if (RC_BAD( rc = linkToBucket())) { goto Exit; } // Allocate a lock object for write locking. if( RC_BAD( rc = FlmAllocLockObject( &m_pWriteLockObj))) { goto Exit; } // Allocate a lock object for file locking. if( RC_BAD( rc = FlmAllocLockObject( &m_pDatabaseLockObj))) { goto Exit; } Exit: return( rc); }
int __cdecl main( int iArgC, char ** ppszArgV) #endif { int iRetCode = 0; gigaInitGlobalVars(); #ifdef FLM_NLM // Setup the routines to be called when the NLM exits itself atexit( gigaCleanup); #endif if( RC_BAD( FlmStartup())) { iRetCode = 1; goto Exit; } if( RC_BAD( FTXInit( gv_pszTitle, (FLMBYTE)80, (FLMBYTE)50, FLM_BLUE, FLM_LIGHTGRAY, NULL, NULL))) { iRetCode = 1; goto Exit; } FTXSetShutdownFlag( &gv_bShutdown); if( RC_BAD( FTXScreenInit( gv_pszTitle, &gv_pScreen))) { iRetCode = 1; goto Exit; } if( RC_BAD( FTXScreenInitStandardWindows( gv_pScreen, FLM_RED, FLM_WHITE, FLM_BLUE, FLM_WHITE, FALSE, TRUE, gv_pszTitle, NULL, &gv_pWindow))) { iRetCode = 1; goto Exit; } FTXWinGetCanvasSize( gv_pWindow, &gv_uiNumCols, &gv_uiNumRows); if( RC_BAD( f_mutexCreate( &gv_hWindowMutex))) { iRetCode = 99; goto Exit; } if( !gigaGetParams( iArgC, (const char **)ppszArgV)) { iRetCode = 2; goto Exit; } f_pathReduce( gv_szDibName, gv_szDirectoryPath, gv_pszFileName); if( !gv_szDirectoryPath [0]) { f_strcpy( gv_szDirectoryPath, "."); } if( RC_BAD( gigaLoadDatabase())) { iRetCode = 7; goto Exit; } if( !gv_bBatchMode) { gigaOutputErrMsg( "Load complete"); } Exit: if( gv_hWindowMutex != F_MUTEX_NULL) { f_mutexDestroy( &gv_hWindowMutex); } FTXExit(); FlmShutdown(); #ifdef FLM_NLM if (!gv_bSynchronized) { SynchronizeStart(); gv_bSynchronized = TRUE; } #endif gv_bRunning = FALSE; return( iRetCode); }
/**************************************************************************** Name: flstIndexManagerThread Desc: Thread that displays the current status of all indexes in a database Note: The caller must open the database and pass a handle to the thread. The handle will be closed when the thread exits. *****************************************************************************/ RCODE FTKAPI flstIndexManagerThread( IF_Thread * pThread) { RCODE rc = NE_XFLM_OK; F_DynamicList * pList = f_new F_DynamicList; FTX_WINDOW * pTitleWin; FTX_WINDOW * pListWin; FTX_WINDOW * pHeaderWin; FTX_WINDOW * pMsgWin; FLMUINT uiIterations = 0; FLMUINT uiScreenCols; FLMUINT uiScreenRows; FLMUINT uiIndex; FLMUINT uiUpdateInterval; FLMUINT uiLastUpdateTime; IX_DISPLAY_INFO IxDispInfo; IX_DISPLAY_INFO * pDispInfo; DLIST_NODE * pTmpNd; FLMUINT uiKey; FLMBOOL bShowOnline = TRUE; F_Db * pDb = (F_Db *)pThread->getParm1(); FLMUINT uiOneSec; FLMBOOL bScreenLocked = FALSE; IX_Event event; FLMBOOL bRegisteredForEvent = FALSE; IF_DbSystem * pDbSystem = NULL; event.setDispInfo( &IxDispInfo); #define FIMT_TITLE_HEIGHT 1 #define FIMT_HEADER_HEIGHT 4 #define FIMT_LOG_HEIGHT 10 f_memset( &IxDispInfo, 0, sizeof( IX_DISPLAY_INFO)); IxDispInfo.hScreenMutex = F_MUTEX_NULL; IxDispInfo.pDb = (F_Db *)pDb; IxDispInfo.bShowTime = TRUE; if( RC_BAD( f_mutexCreate( &IxDispInfo.hScreenMutex))) { goto Exit; } if( RC_BAD( FTXScreenInit( "Index Manager", &IxDispInfo.pScreen))) { goto Exit; } FTXScreenGetSize( IxDispInfo.pScreen, &uiScreenCols, &uiScreenRows); FTXScreenDisplay( IxDispInfo.pScreen); if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, 0, FIMT_TITLE_HEIGHT, &pTitleWin))) { goto Exit; } FTXWinSetBackFore( pTitleWin, FLM_RED, FLM_WHITE); FTXWinClear( pTitleWin); FTXWinPrintStr( pTitleWin, "FLAIM Index Manager"); FTXWinSetCursorType( pTitleWin, FLM_CURSOR_INVISIBLE); FTXWinOpen( pTitleWin); if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols, FIMT_HEADER_HEIGHT, &pHeaderWin))) { goto Exit; } FTXWinMove( pHeaderWin, 0, FIMT_TITLE_HEIGHT); FTXWinSetBackFore( pHeaderWin, FLM_BLUE, FLM_WHITE); FTXWinClear( pHeaderWin); FTXWinSetCursorType( pHeaderWin, FLM_CURSOR_INVISIBLE); FTXWinSetScroll( pHeaderWin, FALSE); FTXWinSetLineWrap( pHeaderWin, FALSE); FTXWinOpen( pHeaderWin); if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols, uiScreenRows - FIMT_TITLE_HEIGHT - FIMT_HEADER_HEIGHT - FIMT_LOG_HEIGHT, &pListWin))) { goto Exit; } FTXWinMove( pListWin, 0, FIMT_TITLE_HEIGHT + FIMT_HEADER_HEIGHT); FTXWinOpen( pListWin); pList->setup( pListWin); if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols, FIMT_LOG_HEIGHT, &IxDispInfo.pLogWin))) { goto Exit; } FTXWinDrawBorder( IxDispInfo.pLogWin); FTXWinMove( IxDispInfo.pLogWin, 0, uiScreenRows - FIMT_LOG_HEIGHT); FTXWinSetBackFore( IxDispInfo.pLogWin, FLM_BLUE, FLM_WHITE); FTXWinClear( IxDispInfo.pLogWin); FTXWinSetCursorType( IxDispInfo.pLogWin, FLM_CURSOR_INVISIBLE); FTXWinSetScroll( IxDispInfo.pLogWin, TRUE); FTXWinSetLineWrap( IxDispInfo.pLogWin, FALSE); FTXWinOpen( IxDispInfo.pLogWin); if( RC_BAD( rc = FlmAllocDbSystem( &pDbSystem))) { goto Exit; } if (RC_BAD( rc = pDbSystem->registerForEvent( XFLM_EVENT_UPDATES, &event))) { goto Exit; } bRegisteredForEvent = TRUE; FTXWinSetFocus( pListWin); uiIterations = 0; uiUpdateInterval = FLM_SECS_TO_TIMER_UNITS( 1); uiOneSec = FLM_SECS_TO_TIMER_UNITS( 1); uiLastUpdateTime = 0; while( !gv_bShutdown) { FLMUINT uiCurrTime = FLM_GET_TIMER(); if( bScreenLocked) { f_mutexUnlock( IxDispInfo.hScreenMutex); bScreenLocked = FALSE; } if( FLM_ELAPSED_TIME( uiCurrTime, uiLastUpdateTime) >= uiUpdateInterval) { Update_Screen: if( !bScreenLocked) { f_mutexLock( IxDispInfo.hScreenMutex); bScreenLocked = TRUE; } FTXWinSetCursorPos( pHeaderWin, 0, 1); if( IxDispInfo.bShowTime) { FTXWinPrintf( pHeaderWin, "Index Index State Last Rate Keys Documents Time"); } else { FTXWinPrintf( pHeaderWin, "Index Index State Last Rate Keys Documents Trans"); } FTXWinClearToEOL( pHeaderWin); FTXWinPrintf( pHeaderWin, "\n"); FTXWinPrintf( pHeaderWin, "Num. Name DOC"); if (RC_BAD( rc = pDb->transBegin( XFLM_READ_TRANS))) { goto Exit; } pTmpNd = pList->getFirst(); uiIndex = 0; for( ;;) { if( RC_BAD( pDb->indexGetNext( &uiIndex))) { break; } // Remove all invalid entries while( pTmpNd && pTmpNd->uiKey < uiIndex) { uiKey = pTmpNd->uiKey; pTmpNd = pTmpNd->pNext; pList->remove( uiKey); } if (RC_BAD( rc = pDb->indexStatus( uiIndex, &IxDispInfo.IndexStatus))) { goto Exit; } if( !bShowOnline && IxDispInfo.IndexStatus.eState == XFLM_INDEX_ONLINE) { if( pTmpNd && pTmpNd->uiKey == uiIndex) { uiKey = pTmpNd->uiKey; pTmpNd = pTmpNd->pNext; pList->remove( uiKey); } continue; } if( pTmpNd && pTmpNd->uiKey == uiIndex) { FLMUINT uiOldest; FLMUINT uiElapsed; pDispInfo = (IX_DISPLAY_INFO *)pTmpNd->pvData; f_strcpy( IxDispInfo.szName, pDispInfo->szName); // Copy the saved information. f_memcpy( &IxDispInfo.ui64SaveDocsProcessed [0], &pDispInfo->ui64SaveDocsProcessed [0], sizeof( FLMUINT) * MAX_VALS_TO_SAVE); f_memcpy( &IxDispInfo.uiDocSaveTime [0], &pDispInfo->uiDocSaveTime [0], sizeof( FLMUINT) * MAX_VALS_TO_SAVE); uiOldest = IxDispInfo.uiOldestSaved = pDispInfo->uiOldestSaved; // Recalculate the indexing rate. uiCurrTime = FLM_GET_TIMER(); uiElapsed = (uiCurrTime - IxDispInfo.uiDocSaveTime [uiOldest]) / uiOneSec; if (uiElapsed && IxDispInfo.IndexStatus.ui64DocumentsProcessed) { if( IxDispInfo.ui64SaveDocsProcessed[ uiOldest] < IxDispInfo.IndexStatus.ui64DocumentsProcessed) { IxDispInfo.uiIndexingRate = // Records processed in time period (FLMUINT)((IxDispInfo.IndexStatus.ui64DocumentsProcessed - IxDispInfo.ui64SaveDocsProcessed [uiOldest]) / uiElapsed); } else { IxDispInfo.uiIndexingRate = 0; } } else { IxDispInfo.uiIndexingRate = 0; } // Overwrite the oldest with the current data. IxDispInfo.uiDocSaveTime [uiOldest] = uiCurrTime; IxDispInfo.ui64SaveDocsProcessed [uiOldest] = IxDispInfo.IndexStatus.ui64DocumentsProcessed; // Move oldest pointer for next update. if (++IxDispInfo.uiOldestSaved == MAX_VALS_TO_SAVE) { IxDispInfo.uiOldestSaved = 0; } } else { FLMUINT uiLoop; FLMUINT uiBufLen; F_DataVector srchKey; uiCurrTime = FLM_GET_TIMER(); IxDispInfo.uiIndexingRate = 0; for (uiLoop = 0; uiLoop < MAX_VALS_TO_SAVE; uiLoop++) { IxDispInfo.ui64SaveDocsProcessed [uiLoop] = IxDispInfo.IndexStatus.ui64DocumentsProcessed; IxDispInfo.uiDocSaveTime [uiLoop] = uiCurrTime; } IxDispInfo.uiOldestSaved = 0; // Retrieve index name if (RC_BAD( srchKey.setUINT( 0, ELM_INDEX_TAG))) { break; } if (RC_BAD( srchKey.setUINT( 1, uiIndex))) { break; } if (RC_BAD( rc = pDb->keyRetrieve( XFLM_DICT_NUMBER_INDEX, &srchKey, XFLM_EXACT, &srchKey))) { if (rc != NE_XFLM_NOT_FOUND) { break; } } else { F_DOMNode * pNode = NULL; if (RC_BAD( rc = pDb->getNode( XFLM_DICT_COLLECTION, srchKey.getDocumentID(), &pNode))) { if (rc != NE_XFLM_DOM_NODE_NOT_FOUND) { break; } } else { uiBufLen = sizeof( IxDispInfo.szName); rc = pNode->getAttributeValueUTF8( pDb, ATTR_NAME_TAG, (FLMBYTE *)IxDispInfo.szName, uiBufLen); pNode->Release(); if (rc != NE_XFLM_OK && rc != NE_XFLM_DOM_NODE_NOT_FOUND && rc != NE_XFLM_CONV_DEST_OVERFLOW) { break; } } } } pList->update( uiIndex, ixDisplayHook, &IxDispInfo, sizeof( IxDispInfo)); pList->refresh(); if( pTmpNd && pTmpNd->uiKey == uiIndex) { pTmpNd = pTmpNd->pNext; } } pDb->transAbort(); uiLastUpdateTime = FLM_GET_TIMER(); pList->refresh(); } if( !bScreenLocked) { f_mutexLock( IxDispInfo.hScreenMutex); bScreenLocked = TRUE; } if( RC_OK( FTXWinTestKB( pListWin))) { FLMUINT uiChar; FTXWinInputChar( pListWin, &uiChar); f_mutexUnlock( IxDispInfo.hScreenMutex); bScreenLocked = FALSE; switch( uiChar) { case 'O': case 'o': { bShowOnline = !bShowOnline; goto Update_Screen; } case '+': case 'r': { if( (pTmpNd = pList->getCurrent()) != NULL) { if (RC_BAD( rc = pDb->indexResume( pTmpNd->uiKey))) { goto Exit; } goto Update_Screen; } break; } case 's': { if( (pTmpNd = pList->getCurrent()) != NULL) { if (RC_BAD( rc = pDb->indexSuspend( pTmpNd->uiKey))) { goto Exit; } goto Update_Screen; } break; } case FKB_ALT_S: case 'S': { f_mutexLock( IxDispInfo.hScreenMutex); FTXMessageWindow( IxDispInfo.pScreen, FLM_RED, FLM_WHITE, "Suspending all indexes ....", NULL, &pMsgWin); f_mutexUnlock( IxDispInfo.hScreenMutex); if (RC_OK( pDb->transBegin( XFLM_UPDATE_TRANS))) { uiIndex = 0; for( ;;) { if( RC_BAD( pDb->indexGetNext( &uiIndex))) { break; } if (RC_BAD( pDb->indexSuspend( uiIndex))) { break; } } if (RC_BAD( pDb->transCommit())) { (void)pDb->transAbort(); } } if( pMsgWin) { f_mutexLock( IxDispInfo.hScreenMutex); FTXWinFree( &pMsgWin); f_mutexUnlock( IxDispInfo.hScreenMutex); } goto Update_Screen; } case 'R': case FKB_ALT_R: { f_mutexLock( IxDispInfo.hScreenMutex); FTXMessageWindow( IxDispInfo.pScreen, FLM_RED, FLM_WHITE, "Resuming all indexes ", NULL, &pMsgWin); f_mutexUnlock( IxDispInfo.hScreenMutex); if (RC_OK( pDb->transBegin( XFLM_UPDATE_TRANS))) { uiIndex = 0; for( ;;) { if( RC_BAD( pDb->indexGetNext( &uiIndex))) { break; } if (RC_BAD( pDb->indexResume( uiIndex))) { break; } } if (RC_BAD( pDb->transCommit())) { (void)pDb->transAbort(); break; } } if( pMsgWin) { f_mutexLock( IxDispInfo.hScreenMutex); FTXWinFree( &pMsgWin); f_mutexUnlock( IxDispInfo.hScreenMutex); } goto Update_Screen; } case 'T': case 't': { IxDispInfo.bShowTime = !IxDispInfo.bShowTime; goto Update_Screen; } case '?': { FTX_WINDOW * pHelpWin = NULL; FTX_WINDOW * pHelpTitle = NULL; F_DynamicList * pHelpList = NULL; FLMUINT uiItem = 0; char szTmpBuf [100]; f_mutexLock( IxDispInfo.hScreenMutex); bScreenLocked = TRUE; if( (pHelpList = f_new F_DynamicList) == NULL) { goto Help_Exit; } if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols, 1, &pHelpTitle))) { goto Help_Exit; } FTXWinSetBackFore( pHelpTitle, FLM_RED, FLM_WHITE); FTXWinClear( pHelpTitle); FTXWinSetCursorType( pHelpTitle, FLM_CURSOR_INVISIBLE); FTXWinSetScroll( pHelpTitle, FALSE); FTXWinSetLineWrap( pHelpTitle, FALSE); FTXWinPrintf( pHelpTitle, "FLAIM Index Manager - Help"); FTXWinOpen( pHelpTitle); if( RC_BAD( FTXWinInit( IxDispInfo.pScreen, uiScreenCols, uiScreenRows - 1, &pHelpWin))) { goto Help_Exit; } FTXWinDrawBorder( pHelpWin); FTXWinOpen( pHelpWin); pHelpList->setup( pHelpWin); f_sprintf( szTmpBuf, "R, ALT_R Resume all indexes"); pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf)); f_sprintf( szTmpBuf, "S, ALT_S Suspend all indexes"); pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf)); f_sprintf( szTmpBuf, "o, O Toggle display of on-line indexes"); pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf)); f_sprintf( szTmpBuf, "+, r Resume selected index with auto on-line option"); pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf)); f_sprintf( szTmpBuf, "s Suspend selected index"); pHelpList->update( ++uiItem, NULL, szTmpBuf, sizeof( szTmpBuf)); pHelpList->refresh(); pHelpWin = pHelpList->getListWin(); f_mutexUnlock( IxDispInfo.hScreenMutex); bScreenLocked = FALSE; while( !gv_bShutdown) { f_mutexLock( IxDispInfo.hScreenMutex); bScreenLocked = TRUE; if( RC_OK( FTXWinTestKB( pHelpWin))) { FLMUINT uiTmpChar; FTXWinInputChar( pHelpWin, &uiTmpChar); if( uiTmpChar == FKB_ESCAPE) { break; } pHelpList->defaultKeyAction( uiTmpChar); } f_mutexUnlock( IxDispInfo.hScreenMutex); bScreenLocked = FALSE; f_sleep( 10); } Help_Exit: if( !bScreenLocked) { f_mutexLock( IxDispInfo.hScreenMutex); bScreenLocked = TRUE; } if( pHelpList) { pHelpList->Release(); } if( pHelpTitle) { FTXWinFree( &pHelpTitle); } f_mutexUnlock( IxDispInfo.hScreenMutex); bScreenLocked = FALSE; break; } case FKB_ESCAPE: { goto Exit; } default: { f_mutexLock( IxDispInfo.hScreenMutex); pList->defaultKeyAction( uiChar); f_mutexUnlock( IxDispInfo.hScreenMutex); break; } } f_mutexLock( IxDispInfo.hScreenMutex); pList->refresh(); f_mutexUnlock( IxDispInfo.hScreenMutex); } uiIterations++; if( pThread->getShutdownFlag()) { break; } f_sleep( 1); } Exit: if( pList) { pList->Release(); } if (bRegisteredForEvent) { pDbSystem->deregisterForEvent( XFLM_EVENT_UPDATES, &event); } if( IxDispInfo.pScreen) { FTXScreenFree( &IxDispInfo.pScreen); } if( IxDispInfo.hScreenMutex != F_MUTEX_NULL) { f_mutexDestroy( &IxDispInfo.hScreenMutex); } if( pDb != NULL) { pDb->Release(); } if( pDbSystem) { pDbSystem->Release(); } return( rc); }