/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI f_rwlockAcquire(
	F_RWLOCK				hReadWriteLock,
	F_SEM					hSem,
	FLMBOOL				bWriter)
{
	RCODE					rc = NE_FLM_OK;
	F_RWLOCK_IMP *		pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock;
	FLMBOOL				bMutexLocked = FALSE;
	
	f_mutexLock( pReadWriteLock->hMutex);
	bMutexLocked = TRUE;
	
	if( bWriter)
	{
		if( pReadWriteLock->iRefCnt != 0)
		{
			rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)((FLMINT)bWriter),
				&pReadWriteLock->pNotifyList); 
		}
		
		if( RC_OK( rc))
		{
			f_assert( !pReadWriteLock->iRefCnt);
			pReadWriteLock->iRefCnt = -1;
			pReadWriteLock->uiWriteThread = f_threadId();
		}
	}
	else
	{	 
		if( pReadWriteLock->iRefCnt < 0 || pReadWriteLock->pNotifyList)
		{
			rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)((FLMINT)bWriter), 
				&pReadWriteLock->pNotifyList); 
		}
		
		if( RC_OK( rc))
		{
			pReadWriteLock->iRefCnt++;
		}
	}
	
	f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt);
	
	if( bMutexLocked)
	{
		f_mutexUnlock( pReadWriteLock->hMutex);
	}
	
	return( rc);
}
Example #2
0
/****************************************************************************
Desc: This routine checks to see if it is OK for another F_Db to use an
		F_Database object.
		If so, it increments the database's use counter.  NOTE: This routine
		assumes that the calling routine has locked the global mutex.
****************************************************************************/
RCODE F_Database::verifyOkToUse(
	FLMBOOL *	pbWaited)
{
	RCODE    rc = NE_XFLM_OK;
	F_SEM		hWaitSem = F_SEM_NULL;

	// Can't open the database if it is being closed by someone else.

	if (m_uiFlags & DBF_BEING_CLOSED)
	{
		rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
		goto Exit;
	}

	// If the file is in the process of being opened by another
	// thread, wait for the open to complete.

	if (m_uiFlags & DBF_BEING_OPENED)
	{
		if( RC_BAD( rc = f_semCreate( &hWaitSem)))
		{
			goto Exit;
		}
		
		*pbWaited = TRUE;
		if( RC_BAD( rc = f_notifyWait( 
			gv_XFlmSysData.hShareMutex, hWaitSem, NULL,&m_pOpenNotifies)))
		{
			// If f_notifyWait returns a bad RC, assume that the other
			// thread will unlock and free the F_Database object.  This
			// routine should only unlock the object if an error occurs at
			// some other point.

			goto Exit;
		}
	}
	else
	{
		*pbWaited = FALSE;
	}

Exit:

	if( hWaitSem != F_SEM_NULL)
	{
		f_semDestroy( &hWaitSem);
	}

	return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FLMAPI f_rwlockPromote(
	F_RWLOCK				hReadWriteLock,
	F_SEM					hSem)
{
	RCODE					rc = NE_FLM_OK;
	F_RWLOCK_IMP *		pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock;
	FLMBOOL				bMutexLocked = FALSE;
	
	f_mutexLock( pReadWriteLock->hMutex);
	bMutexLocked = TRUE;
	
	if( pReadWriteLock->iRefCnt <= 0)
	{
		rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP);
		goto Exit;
	}
	
	pReadWriteLock->iRefCnt--;
		
	if( pReadWriteLock->iRefCnt != 0)
	{
		rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)TRUE, 
			&pReadWriteLock->pNotifyList); 
	}
	
	if( RC_OK( rc))
	{
		f_assert( !pReadWriteLock->iRefCnt);
		pReadWriteLock->iRefCnt = -1;
		pReadWriteLock->uiWriteThread = f_threadId();
	}

Exit:

	f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt);
	
	if( bMutexLocked)
	{
		f_mutexUnlock( pReadWriteLock->hMutex);
	}
	
	return( rc);
}
Example #4
0
/****************************************************************************
Desc:		This routine is used to see if a file is already in use somewhere.
			This is only called for files which are opened directly by the
			application.
Notes:	This routine assumes that the global mutex is locked, but it
			may unlock and re-lock the mutex if needed.
****************************************************************************/
RCODE F_DbSystem::findDatabase(
	const char *	pszDbPath,
	const char *	pszDataDir,
	F_Database **	ppDatabase)
{
	RCODE				rc = NE_XFLM_OK;
	F_BUCKET *		pBucket;
	FLMUINT			uiBucket;
	FLMBOOL			bMutexLocked = TRUE;
	F_Database *	pDatabase;
	char				szDbPathStr1 [F_PATH_MAX_SIZE];
	char				szDbPathStr2 [F_PATH_MAX_SIZE];
	F_SEM				hWaitSem = F_SEM_NULL;

	*ppDatabase = NULL;

	// Normalize the path to a string before looking for it.
	// NOTE: On non-UNIX, non-WIN platforms, this will basically convert
	// the string to upper case.

	if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathToStorageString( 
		pszDbPath, szDbPathStr1)))
	{
		goto Exit;
	}

Retry:

	*ppDatabase = NULL;

	if( !bMutexLocked)
	{
		f_mutexLock( gv_XFlmSysData.hShareMutex);
		bMutexLocked = TRUE;
	}

	pBucket = gv_XFlmSysData.pDatabaseHashTbl;
	uiBucket = f_strHashBucket( szDbPathStr1, pBucket, FILE_HASH_ENTRIES);
	pDatabase = (F_Database *)pBucket [uiBucket].pFirstInBucket;
	while (pDatabase)
	{
		// Compare the strings.  On non-Unix platforms we must use
		// f_stricmp, because case does not matter for file names
		// on those platforms.

#ifdef FLM_UNIX
		if( f_strcmp( szDbPathStr1, pDatabase->m_pszDbPath) == 0)
#else
		if( f_stricmp( szDbPathStr1, pDatabase->m_pszDbPath) == 0)
#endif
		{

			// Make sure data paths match.

			if (pszDataDir && *pszDataDir)
			{
				if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathToStorageString(
					pszDataDir, szDbPathStr2)))
				{
					goto Exit;
				}
				
				if (pDatabase->m_pszDataDir)
				{
					// f_stricmp must be used on non-unix platforms because file
					// names are case insensitive on those platforms.
#ifdef FLM_UNIX
					if (f_strcmp( pDatabase->m_pszDataDir, szDbPathStr2) != 0)
#else
					if (f_stricmp( pDatabase->m_pszDataDir, szDbPathStr2) != 0)
#endif
					{
						rc = RC_SET( NE_XFLM_DATA_PATH_MISMATCH);
						goto Exit;
					}
				}
				else
				{
					rc = RC_SET( NE_XFLM_DATA_PATH_MISMATCH);
					goto Exit;
				}
			}
			else if (pDatabase->m_pszDataDir)
			{
				rc = RC_SET( NE_XFLM_DATA_PATH_MISMATCH);
				goto Exit;
			}
			*ppDatabase = pDatabase;
			break;
		}
		pDatabase = pDatabase->m_pNext;
	}

	if (*ppDatabase && pDatabase->m_uiFlags & DBF_BEING_CLOSED)
	{
		if( RC_BAD( rc = f_semCreate( &hWaitSem)))
		{
			goto Exit;
		}
		
		// Put ourselves into the notify list and then re-try
		// the lookup when we wake up

		if (RC_BAD( rc = f_notifyWait( gv_XFlmSysData.hShareMutex, hWaitSem,
			NULL, &pDatabase->m_pCloseNotifies)))
		{
			goto Exit;
		}
		
		f_semDestroy( &hWaitSem);

		// The mutex will be locked at this point.  Re-try the lookup.
		// IMPORTANT NOTE: pDatabase will have been destroyed by this
		// time.  DO NOT use it for anything!

		goto Retry;
	}

Exit:

	if( hWaitSem != F_SEM_NULL)
	{
		f_semDestroy( &hWaitSem);
	}

	// Make sure the global mutex is re-locked before exiting

	if( !bMutexLocked)
	{
		f_mutexLock( gv_XFlmSysData.hShareMutex);
	}
	

	return( rc);
}
Example #5
0
/****************************************************************************
Desc: This routine obtains exclusive access to a database by creating
		a .lck file.  FLAIM holds the .lck file open as long as the database
		is open.  When the database is finally closed, it deletes the .lck
		file.  This is only used for 3.x databases.
****************************************************************************/
RCODE F_Database::getExclAccess(
	const char *	pszFilePath)
{
	RCODE				rc = NE_XFLM_OK;
	FLMBOOL			bNotifyWaiters = FALSE;
	FLMBOOL			bMutexLocked = FALSE;
	F_SEM				hWaitSem = F_SEM_NULL;

	// If m_pLockFileHdl is non-NULL, it means that we currently
	// have the database locked with a lock file.  There is no need to make
	// this test inside a mutex lock, because the lock file handle can only
	// be set to NULL when the use count goes to zero, meaning that the thread
	// that sets it to NULL will be the only thread accessing it.

	// However, it is possible that two or more threads will simultaneously
	// test m_pLockFileHdl and discover that it is NULL.  In that case,
	// we allow one thread to proceed and attempt to get a lock on the database
	// while the other threads wait to be notified of the results of the
	// attempt to lock the database.

	if (m_pLockFileHdl)
	{
		goto Exit;
	}

	lockMutex();
	bMutexLocked = TRUE;

	if (m_bBeingLocked)
	{
		// If the database is in the process of being locked by another
		// thread, wait for the lock to complete.  NOTE: f_notifyWait will
		// re-lock the mutex before returning.
		
		if( RC_BAD( rc = f_semCreate( &hWaitSem)))
		{
			goto Exit;
		}

		rc = f_notifyWait( m_hMutex, hWaitSem, NULL, &m_pLockNotifies);
		goto Exit;
	}

	// No other thread was attempting to lock the database, so
	// set this thread up to make the attempt.  Other threads
	// coming in at this point will be required to wait and
	// be notified of the results.

	m_bBeingLocked = TRUE;
	bNotifyWaiters = TRUE;
	unlockMutex();
	bMutexLocked = FALSE;
	if (RC_BAD( rc = flmCreateLckFile( pszFilePath, &m_pLockFileHdl)))
	{
		goto Exit;
	}

Exit:

	if (bNotifyWaiters)
	{
		F_NOTIFY_LIST_ITEM *		pNotify;
		F_SEM							hSem;

		// Notify any thread waiting on the lock what its status is.

		if( !bMutexLocked)
		{
			lockMutex();
			bMutexLocked = TRUE;
		}

		pNotify = m_pLockNotifies;
		while (pNotify)
		{
			*(pNotify->pRc) = rc;
			hSem = pNotify->hSem;
			pNotify = pNotify->pNext;
			f_semSignal( hSem);
		}

		m_bBeingLocked = FALSE;
		m_pLockNotifies = NULL;
		unlockMutex();
		bMutexLocked = FALSE;
	}

	if( bMutexLocked)
	{
		unlockMutex();
	}
	
	if( hWaitSem != F_SEM_NULL)
	{
		f_semDestroy( &hWaitSem);
	}

	return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE FTKAPI F_IOBufferMgr::getBuffer(
	FLMUINT				uiBufferSize,
	IF_IOBuffer **		ppIOBuffer)
{
	RCODE					rc = NE_FLM_OK;
	F_IOBuffer *		pIOBuffer = NULL;
	FLMBOOL				bMutexLocked = FALSE;
	
	f_assert( *ppIOBuffer == NULL);
	
	if( RC_BAD( m_completionRc))
	{
		rc = m_completionRc;
		goto Exit;
	}
	
	f_mutexLock( m_hMutex);
	bMutexLocked = TRUE;
	
Retry:

	if( m_pFirstAvail)
	{
		pIOBuffer = m_pFirstAvail;
		unlinkFromList( pIOBuffer);
		pIOBuffer->resetBuffer();
		f_assert( pIOBuffer->getBufferSize() == uiBufferSize);
	}
	else if( !m_uiTotalBuffers ||
		(m_uiTotalBufferBytes + uiBufferSize <= m_uiMaxBufferBytes &&
		m_uiTotalBuffers < m_uiMaxBuffers))
	{
		if( m_uiTotalBufferBytes + uiBufferSize > m_uiMaxBufferBytes)
		{
			rc = RC_SET_AND_ASSERT( NE_FLM_MEM);
			goto Exit;
		}

		if( (pIOBuffer = f_new F_IOBuffer) == NULL)
		{
			rc = RC_SET( NE_FLM_MEM);
			goto Exit;
		}
		
		if (RC_BAD( rc = pIOBuffer->setupBuffer( uiBufferSize, this)))
		{
			goto Exit;
		}
		
		m_uiTotalBufferBytes += uiBufferSize;
		m_uiTotalBuffers++;
	}
	else if( m_pFirstPending)
	{
	#if !defined( FLM_UNIX) && !defined( FLM_NLM)
		if( RC_BAD( rc = f_notifyWait( m_hMutex, m_hAvailSem, 
			NULL, &m_pAvailNotify)))
		{
			goto Exit;
		}
	#else
		F_IOBuffer *		pPending = m_pFirstPending;
		
		pPending->AddRef();
		f_mutexUnlock( m_hMutex);
		bMutexLocked = FALSE;
	
		rc = pPending->waitToComplete();
		
		f_mutexLock( m_hMutex);
		bMutexLocked = TRUE;
		
		pPending->Release( bMutexLocked);
		
		if( RC_BAD( rc))
		{
			goto Exit;
		}
	#endif
		
		goto Retry;
	}
	else
	{
		rc = RC_SET_AND_ASSERT( NE_FLM_MEM);
		goto Exit;
	}
	
	pIOBuffer->AddRef();
	linkToList( &m_pFirstUsed, pIOBuffer);
	*ppIOBuffer = pIOBuffer;
	pIOBuffer = NULL;
	
Exit:

	if( pIOBuffer)
	{
		pIOBuffer->Release();
	}
	
	if( bMutexLocked)
	{
		f_mutexUnlock( m_hMutex);
	}
	
	return( rc);
}