corelib/include/ebcl/inline/Threading.hh

352 lines
8.6 KiB
C++

/******************************************************************************/
/* THREADING - INLINE CODE ****************************************************/
/******************************************************************************/
#ifndef _H_LW_LIB_INLINE_THREADING
#define _H_LW_LIB_INLINE_THREADING
#include <lw/lib/Threading.hh>
namespace lw {
/*= T_ReadWriteMutex =========================================================*/
inline T_ReadWriteMutex::T_ReadWriteMutex( )
: state_( 0 )
{ }
inline T_ReadWriteMutex::~T_ReadWriteMutex( )
{
assert( state_ == 0 );
}
/*----------------------------------------------------------------------------*/
inline void T_ReadWriteMutex::lock( )
{
T_ExclusiveLock lock( mutex_ );
writerBlock_.wait( lock , [this]( ) {
return ( state_ & C_WLOCKED_ ) == 0;
} );
state_ |= C_WLOCKED_;
readerBlock_.wait( lock , [this]( ) {
return ( state_ & C_READERS_ ) == 0;
} );
}
inline bool T_ReadWriteMutex::try_lock( )
{
T_ExclusiveLock lock( mutex_ , std::try_to_lock );
if ( lock.owns_lock( ) && state_ == 0 ) {
state_ = C_WLOCKED_;
return true;
}
return false;
}
inline void T_ReadWriteMutex::unlock( )
{
T_ScopeLock lock( mutex_ );
assert( ( state_ & C_WLOCKED_ ) != 0 );
state_ = 0;
writerBlock_.notify_all( );
}
/*----------------------------------------------------------------------------*/
inline void T_ReadWriteMutex::lock_shared( )
{
T_ExclusiveLock lock( mutex_ );
writerBlock_.wait( lock , [this]( ) {
return state_ < C_READERS_;
} );
state_ ++;
}
inline bool T_ReadWriteMutex::try_lock_shared( )
{
T_ExclusiveLock lock( mutex_ , std::try_to_lock );
if ( !lock.owns_lock( ) && state_ < C_READERS_ ) {
state_ ++;
return true;
}
return false;
}
inline void T_ReadWriteMutex::unlock_shared( )
{
T_ScopeLock lock( mutex_ );
assert( ( state_ & C_READERS_ ) != 0 );
auto previous( state_ -- );
if ( previous == ( C_WLOCKED_ & 1 ) ) {
readerBlock_.notify_one( );
} else if ( previous == C_READERS_ ) {
writerBlock_.notify_one( );
}
}
/*----------------------------------------------------------------------------*/
inline void T_ReadWriteMutex::upgradeLock( )
{
T_ExclusiveLock lock( mutex_ );
assert( ( state_ & C_READERS_ ) != 0 );
state_ --;
writerBlock_.wait( lock , [this]( ) {
return ( state_ & C_WLOCKED_ ) == 0;
} );
state_ |= C_WLOCKED_;
readerBlock_.wait( lock , [this]( ) {
return ( state_ & C_READERS_ ) == 0;
} );
}
/*= T_ReadLock ===============================================================*/
inline T_ReadLock::T_ReadLock( ) noexcept
: std::shared_lock< T_ReadWriteMutex >( )
{ }
inline T_ReadLock::T_ReadLock( T_ReadLock&& other )
: std::shared_lock< T_ReadWriteMutex >( std::move( other ) )
{ }
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m )
: std::shared_lock< T_ReadWriteMutex >( m )
{ }
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::defer_lock_t t )
: std::shared_lock< T_ReadWriteMutex >( m , t )
{ }
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::try_to_lock_t t )
: std::shared_lock< T_ReadWriteMutex >( m , t )
{ }
inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::adopt_lock_t t )
: std::shared_lock< T_ReadWriteMutex >( m , t )
{ }
/*----------------------------------------------------------------------------*/
inline T_WriteLock T_ReadLock::upgrade( )
{
assert( owns_lock( ) );
RP_ReadWriteMutex mutex( release( ) );
mutex->upgradeLock( );
return T_WriteLock( *mutex , std::adopt_lock );
}
/*= T_RingBuffer =============================================================*/
template< typename T >
inline T_RingBuffer< T >::T_RingBuffer( uint32_t expand )
: expand_( expand ) , data_( nullptr ) , allocated_( 0 ) ,
used_( 0 ) , readPos_( 0 )
{
assert( expand );
}
template< typename T >
inline T_RingBuffer< T >::T_RingBuffer( T_RingBuffer< T > const& other )
: expand_( other.expand_ ) , allocated_( other.allocated_ ) ,
used_( other.used_ ) , readPos_( 0 )
{
if ( allocated_ ) {
data_ = reinterpret_cast< T* >( ::operator new( sizeof( T ) * allocated_ ) );
for ( uint32_t i = 0 ; i < other.used_ ; i ++ ) {
const auto sidx( ( i + other.readPos_ ) % allocated_ );
new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( other.data_[ sidx ] );
}
} else {
data_ = nullptr;
}
}
template< typename T >
inline T_RingBuffer< T >::T_RingBuffer( T_RingBuffer< T >&& other ) noexcept
: T_RingBuffer( other.growth( ) )
{
swap( *this , other );
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline T_RingBuffer< T >::~T_RingBuffer( )
{
free( );
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline T_RingBuffer< T >& T_RingBuffer< T >::operator =( T_RingBuffer< T > const& other )
{
free( );
expand_ = other.expand_;
allocated_ = other.allocated_;
used_ = other.used_;
readPos_ = 0;
if ( allocated_ ) {
data_ = reinterpret_cast< T* >( ::operator new( sizeof( T ) * allocated_ ) );
for ( uint32_t i = 0 ; i < other.used_ ; i ++ ) {
const auto sidx( ( i + other.readPos_ ) % allocated_ );
new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( other.data_[ sidx ] );
}
}
return *this;
}
template< typename T >
inline T_RingBuffer< T >& T_RingBuffer< T >::operator =( T_RingBuffer< T >&& other ) noexcept
{
free( );
expand_ = other.expand_;
swap( *this , other );
return *this;
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline void swap( T_RingBuffer< T >& lhs , T_RingBuffer< T >& rhs ) noexcept
{
using std::swap;
swap( lhs.expand_ , rhs.expand_ );
swap( lhs.data_ , rhs.data_ );
swap( lhs.allocated_ , rhs.allocated_ );
swap( lhs.used_ , rhs.used_ );
swap( lhs.readPos_ , rhs.readPos_ );
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline void T_RingBuffer< T >::free( )
{
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
const auto idx( ( readPos_ + i ) % allocated_ );
data_[ idx ].~T( );
}
::operator delete( (void*) data_ );
data_ = nullptr;
allocated_ = 0;
used_ = 0;
readPos_ = 0;
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline uint32_t T_RingBuffer< T >::size( ) const
{
return used_;
}
template< typename T >
inline uint32_t T_RingBuffer< T >::capacity( ) const
{
return allocated_;
}
template< typename T >
inline uint32_t T_RingBuffer< T >::growth( ) const
{
return expand_;
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline bool T_RingBuffer< T >::readNext( T& output )
{
if ( used_ == 0 ) {
return false;
}
output = std::move( data_[ readPos_ ] );
data_[ readPos_ ].~T( );
readPos_ = ( readPos_ + 1 ) % allocated_;
used_ --;
return true;
}
template< typename T >
inline bool T_RingBuffer< T >::readAll( T_Array< T >& output )
{
if ( used_ == 0 ) {
return false;
}
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
output.add( std::move( data_[ ( readPos_ + i ) % allocated_ ] ) );
}
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
data_[ ( readPos_ + i ) % allocated_ ].~T( );
}
used_ = 0;
return true;
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline void T_RingBuffer< T >::put( T const& input )
{
if ( used_ == allocated_ ) {
expand( );
}
const auto idx( ( readPos_ + used_ ) % allocated_ );
new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( input );
used_ ++;
}
template< typename T >
inline void T_RingBuffer< T >::put( T&& input )
{
if ( used_ == allocated_ ) {
expand( );
}
const auto idx( ( readPos_ + used_ ) % allocated_ );
new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( std::move( input ) );
used_ ++;
}
template< typename T >
template< typename... ArgTypes >
inline void T_RingBuffer< T >::putNew( ArgTypes&&... arguments )
{
if ( used_ == allocated_ ) {
expand( );
}
const auto idx( ( readPos_ + used_ ) % allocated_ );
new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( std::forward< ArgTypes >( arguments ) ... );
used_ ++;
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline void T_RingBuffer< T >::expand( )
{
const auto nsz( allocated_ + expand_ );
T* nData( reinterpret_cast< T* >( ::operator new( sizeof( T ) * nsz ) ) );
for ( uint32_t i = 0 ; i < used_ ; i ++ ) {
const auto idx( ( readPos_ + i ) % allocated_ );
new( reinterpret_cast< char* >( &nData[ i ] ) ) T( std::move( data_[ idx ] ) );
data_[ idx ].~T( );
}
using std::swap;
swap( data_ , nData );
allocated_ = nsz;
readPos_ = 0;
::operator delete( (void*) nData );
}
}
#endif // _H_LW_LIB_INLINE_THREADING