diff --git a/ftk/src/ftk.h b/ftk/src/ftk.h index 9f009f2..3d67496 100644 --- a/ftk/src/ftk.h +++ b/ftk/src/ftk.h @@ -481,7 +481,7 @@ #define NE_FLM_COULD_NOT_CREATE_SEMAPHORE 0xC500 ///< 0xC500 - Could not create a semaphore. #define NE_FLM_BAD_UTF8 0xC501 ///< 0xC501 - An invalid byte sequence was found in a UTF-8 string - #define NE_FLM_ERROR_WAITING_ON_SEMPAHORE 0xC502 ///< 0xC502 - Error occurred while waiting on a sempahore. + #define NE_FLM_ERROR_WAITING_ON_SEMAPHORE 0xC502 ///< 0xC502 - Error occurred while waiting on a sempahore. #define NE_FLM_BAD_SEN 0xC503 ///< 0xC503 - Invalid simple encoded number. #define NE_FLM_COULD_NOT_START_THREAD 0xC504 ///< 0xC504 - Problem starting a new thread. #define NE_FLM_BAD_BASE64_ENCODING 0xC505 ///< 0xC505 - Invalid base64 sequence encountered. @@ -492,6 +492,7 @@ #define NE_FLM_COULD_NOT_CREATE_MUTEX 0xC50A ///< 0xC50A - Error occurred while creating or initializing a mutex. #define NE_FLM_BAD_PLATFORM_FORMAT 0xC50B ///< 0xC50B - In-memory alignment of disk structures is incorrect #define NE_FLM_LOCK_REQ_TIMEOUT 0xC50C ///< 0xC50C - Timeout while waiting for a lock object + #define NE_FLM_WAIT_TIMEOUT 0xC50D ///< 0xC50D - Timeout while waiting on a semaphore, condition variable, or reader/writer lock // Network Errors - Must be the same as they were for FLAIM @@ -1629,6 +1630,8 @@ virtual RCODE FLMAPI close( void) = 0; virtual FLMBOOL FLMAPI canDoAsync( void) = 0; + + virtual FLMBOOL FLMAPI canDoDirectIO( void) = 0; virtual void FLMAPI setExtendSize( FLMUINT uiExtendSize) = 0; @@ -1824,6 +1827,8 @@ } FLMBOOL FLMAPI canDoAsync( void); + + FLMBOOL FLMAPI canDoDirectIO( void); private: @@ -2203,6 +2208,58 @@ void FLMAPI f_semSignal( F_SEM hSem); + /**************************************************************************** + Desc: Notify Lists + ****************************************************************************/ + + typedef struct F_NOTIFY + { + F_NOTIFY * pNext; ///< Pointer to next F_NOTIFY structure in list. + FLMUINT uiThreadId; ///< ID of thread requesting the notify + RCODE * pRc; ///< Pointer to a return code variable that is to + ///< be filled in when the operation is completed. + ///< The thread requesting notification supplies + ///< the return code variable to be filled in. + void * pvData; ///< Data that is passed through to a custom + ///< notify routine + F_SEM hSem; ///< Semaphore that will be signaled when the + ///< operation is complete. + } F_NOTIFY; + + RCODE FLMAPI f_notifyWait( + F_MUTEX hMutex, + F_SEM hSem, + void * pvData, + F_NOTIFY ** ppNotifyList); + + void FLMAPI f_notifySignal( + F_NOTIFY * pNotifyList, + RCODE notifyRc); + + /**************************************************************************** + Desc: Reader / Writer Locks + ****************************************************************************/ + typedef void * F_RWLOCK; + #define F_RWLOCK_NULL NULL + + RCODE FLMAPI f_rwlockCreate( + F_RWLOCK * phReadWriteLock); + + void FLMAPI f_rwlockDestroy( + F_RWLOCK * phReadWriteLock); + + RCODE FLMAPI f_rwlockAcquire( + F_RWLOCK hReadWriteLock, + F_SEM hSem, + FLMBOOL bWriter); + + RCODE FLMAPI f_rwlockPromote( + F_RWLOCK hReadWriteLock, + F_SEM hSem); + + RCODE FLMAPI f_rwlockRelease( + F_RWLOCK hReadWriteLock); + /**************************************************************************** Desc: Thread manager ****************************************************************************/ @@ -4824,8 +4881,6 @@ ) = 0; }; - #define FLM_NO_TIMEOUT 0xFF - /************************************************************************** /// Structure used in gathering statistics to hold an operation count and an elapsed time. **************************************************************************/ @@ -4834,7 +4889,6 @@ FLMUINT64 ui64Count; ///< Number of times operation was performed FLMUINT64 ui64ElapMilli; ///< Total elapsed time (milliseconds) for the operations. } F_COUNT_TIME_STAT; - /************************************************************************** /// Structure for returning lock statistics. diff --git a/ftk/src/ftklock.cpp b/ftk/src/ftklock.cpp index 02f8e27..240d7ed 100644 --- a/ftk/src/ftklock.cpp +++ b/ftk/src/ftklock.cpp @@ -597,7 +597,7 @@ RCODE FLMAPI F_LockObject::lock( LockWait.pLockStats = pLockStats; } - if (uiMaxWaitSecs == FLM_NO_TIMEOUT) + if (uiMaxWaitSecs >= 0xFF) { LockWait.uiWaitTime = 0; } diff --git a/ftk/src/ftksem.cpp b/ftk/src/ftksem.cpp index 0f9bab1..af414ee 100644 --- a/ftk/src/ftksem.cpp +++ b/ftk/src/ftksem.cpp @@ -25,6 +25,17 @@ #include "ftksys.h" +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct +{ + F_MUTEX hMutex; + F_NOTIFY * pNotifyList; + FLMUINT uiWriteThread; + FLMINT iRefCnt; +} F_RWLOCK_IMP; + /**************************************************************************** Desc: ****************************************************************************/ @@ -670,7 +681,7 @@ RCODE f_semWait( { if( _sema_timedwait( (sema_t *)hSem, (unsigned int)uiTimeout)) { - rc = RC_SET( NE_FLM_ERROR_WAITING_ON_SEMPAHORE); + rc = RC_SET( NE_FLM_WAIT_TIMEOUT); } } @@ -745,7 +756,7 @@ RCODE FLMAPI f_semWait( { if( kSemaphoreTimedWait( (SEMAPHORE)hSem, (UINT)uiTimeout) != 0) { - rc = RC_SET( NE_FLM_ERROR_WAITING_ON_SEMPAHORE); + rc = RC_SET( NE_FLM_WAIT_TIMEOUT); } } @@ -854,12 +865,12 @@ RCODE FLMAPI f_semWait( F_SEM hSem, FLMUINT uiTimeout) { - if( WaitForSingleObject( hSem, uiTimeout ) == WAIT_OBJECT_0) + if( WaitForSingleObject( hSem, uiTimeout) == WAIT_OBJECT_0) { return( NE_FLM_OK); } - return( RC_SET( NE_FLM_ERROR_WAITING_ON_SEMPAHORE)); + return( RC_SET( NE_FLM_WAIT_TIMEOUT)); } #endif @@ -873,3 +884,357 @@ void FLMAPI f_semSignal( (void)ReleaseSemaphore( hSem, 1, NULL); } #endif + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC void f_rwlockNotify( + F_RWLOCK_IMP * pReadWriteLock) +{ + F_NOTIFY * pNotify = pReadWriteLock->pNotifyList; + FLMBOOL bFoundWriter = FALSE; + + f_assertMutexLocked( pReadWriteLock->hMutex); + + while( pNotify && !bFoundWriter) + { + F_SEM hSem; + + *(pNotify->pRc) = NE_FLM_OK; + hSem = pNotify->hSem; + bFoundWriter = (FLMBOOL)pNotify->pvData; + pNotify = pNotify->pNext; + f_semSignal( hSem); + } + + pReadWriteLock->pNotifyList = pNotify; +} + +/**************************************************************************** +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: +****************************************************************************/ +void FLMAPI f_rwlockDestroy( + F_RWLOCK * phReadWriteLock) +{ + F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)*phReadWriteLock; + + if( pReadWriteLock) + { + f_assert( !pReadWriteLock->pNotifyList); + + if( pReadWriteLock->hMutex != F_MUTEX_NULL) + { + f_mutexDestroy( &pReadWriteLock->hMutex); + } + + f_free( &pReadWriteLock); + } +} + +/**************************************************************************** +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 *)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 *)bWriter, + &pReadWriteLock->pNotifyList); + } + + if( RC_OK( rc)) + { + pReadWriteLock->iRefCnt++; + } + } + + f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt); + + if( bMutexLocked) + { + f_mutexUnlock( pReadWriteLock->hMutex); + } + + 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); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE FLMAPI f_rwlockTryAcquire( + F_RWLOCK hReadWriteLock, + FLMBOOL bWriter) +{ + RCODE rc = NE_FLM_OK; + F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock; + + f_mutexLock( pReadWriteLock->hMutex); + + if( bWriter) + { + if( pReadWriteLock->iRefCnt != 0) + { + rc = RC_SET( NE_FLM_WAIT_TIMEOUT); + } + else + { + pReadWriteLock->iRefCnt = -1; + pReadWriteLock->uiWriteThread = f_threadId(); + } + } + else + { + if( pReadWriteLock->iRefCnt < 0 || pReadWriteLock->pNotifyList) + { + rc = RC_SET( NE_FLM_WAIT_TIMEOUT); + } + else + { + pReadWriteLock->iRefCnt++; + } + } + + f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt); + f_mutexUnlock( pReadWriteLock->hMutex); + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE FLMAPI f_rwlockRelease( + F_RWLOCK hReadWriteLock) +{ + 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) + { + pReadWriteLock->iRefCnt--; + } + else if( pReadWriteLock->iRefCnt == -1) + { + f_assert( pReadWriteLock->uiWriteThread == f_threadId()); + pReadWriteLock->iRefCnt = 0; + } + else + { + rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); + goto Exit; + } + + if( !pReadWriteLock->iRefCnt && pReadWriteLock->pNotifyList) + { + f_rwlockNotify( pReadWriteLock); + } + +Exit: + + f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt >= 0); + + if( bMutexLocked) + { + f_mutexUnlock( pReadWriteLock->hMutex); + } + + return( rc); +} + +/**************************************************************************** +Desc: This routine links a request into a notification list and + then waits to be notified that the event has occurred. The mutex + is assumed to protect the notify list. +****************************************************************************/ +RCODE FLMAPI f_notifyWait( + F_MUTEX hMutex, + F_SEM hSem, + void * pvData, + F_NOTIFY ** ppNotifyList) +{ + RCODE rc = NE_FLM_OK; + RCODE tmpRc; + F_NOTIFY stackNotify; + F_NOTIFY * pNotify = &stackNotify; + + f_assertMutexLocked( hMutex); + f_memset( &stackNotify, 0, sizeof( F_NOTIFY)); + + pNotify->uiThreadId = f_threadId(); + pNotify->hSem = F_SEM_NULL; + + if( hSem == F_SEM_NULL) + { + if( RC_BAD( rc = f_semCreate( &pNotify->hSem))) + { + goto Exit; + } + } + else + { + pNotify->hSem = hSem; + } + + pNotify->pRc = &rc; + pNotify->pvData = pvData; + + pNotify->pNext = *ppNotifyList; + *ppNotifyList = pNotify; + + // Unlock the mutex and wait on the semaphore + + f_mutexUnlock( hMutex); + + if( RC_BAD( tmpRc = f_semWait( pNotify->hSem, F_SEM_WAITFOREVER))) + { + rc = tmpRc; + } + + // Free the semaphore + + if( hSem != pNotify->hSem) + { + f_semDestroy( &pNotify->hSem); + } + + // Relock the mutex + + f_mutexLock( hMutex); + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: This routine notifies threads waiting for a pending read or write + to complete. This routine assumes that the notify list mutex + is already locked. +****************************************************************************/ +void FLMAPI f_notifySignal( + F_NOTIFY * pNotifyList, + RCODE notifyRc) +{ + while( pNotifyList) + { + F_SEM hSem; + + *(pNotifyList->pRc) = notifyRc; + hSem = pNotifyList->hSem; + pNotifyList = pNotifyList->pNext; + + f_semSignal( hSem); + } +} diff --git a/ftk/src/ftksupr.cpp b/ftk/src/ftksupr.cpp index 5c33fcf..5523c5f 100644 --- a/ftk/src/ftksupr.cpp +++ b/ftk/src/ftksupr.cpp @@ -536,6 +536,31 @@ FLMBOOL FLMAPI F_SuperFileHdl::canDoAsync( void) return( bCanDoAsync); } +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBOOL FLMAPI F_SuperFileHdl::canDoDirectIO( void) +{ + FLMBOOL bCanDoDirectIO = FALSE; + + if( m_pCFileHdl) + { + bCanDoDirectIO = m_pCFileHdl->canDoDirectIO(); + } + else + { + IF_FileHdl * pFileHdl = NULL; + + if( RC_OK( getFileHdl( 0, FALSE, &pFileHdl))) + { + bCanDoDirectIO = pFileHdl->canDoDirectIO(); + pFileHdl->Release(); + } + } + + return( bCanDoDirectIO); +} + /**************************************************************************** Desc: ****************************************************************************/ diff --git a/ftk/src/ftksys.h b/ftk/src/ftksys.h index c0bbbdb..f4505f3 100644 --- a/ftk/src/ftksys.h +++ b/ftk/src/ftksys.h @@ -612,6 +612,11 @@ { return( m_bOpenedInAsyncMode); } + + FINLINE FLMBOOL FLMAPI canDoDirectIO( void) + { + return( m_bDoDirectIO); + } FINLINE void FLMAPI setExtendSize( FLMUINT uiExtendSize)