@ -60,6 +60,8 @@
# include <atomic>
# include <atomic>
# include <cstdint>
# include <cstdint>
# include <cstring>
# include <iterator>
# include <string>
# include <string>
# include "absl/base/const_init.h"
# include "absl/base/const_init.h"
@ -612,12 +614,12 @@ class ABSL_SCOPED_LOCKABLE WriterMutexLock {
// Condition
// Condition
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//
//
// As noted above, `Mutex` contains a number of member functions which take a
// `Mutex` contains a number of member functions which take a `Condition` as an
// `Condition` as an argument; clients can wait for conditions to become `true`
// argument; clients can wait for conditions to become `true` before attempting
// before attempting to acquire the mutex. These sections are known as
// to acquire the mutex. These sections are known as "condition critical"
// "condition critical" sections. To use a `Condition`, you simply need to
// sections. To use a `Condition`, you simply need to construct it, and use
// construct it, and use within an appropriate `Mutex` member function;
// within an appropriate `Mutex` member function; everything else in the
// everything else in the `Condition` class is an implementation detail.
// `Condition` class is an implementation detail.
//
//
// A `Condition` is specified as a function pointer which returns a boolean.
// A `Condition` is specified as a function pointer which returns a boolean.
// `Condition` functions should be pure functions -- their results should depend
// `Condition` functions should be pure functions -- their results should depend
@ -742,22 +744,55 @@ class Condition {
static bool GuaranteedEqual ( const Condition * a , const Condition * b ) ;
static bool GuaranteedEqual ( const Condition * a , const Condition * b ) ;
private :
private :
typedef bool ( * InternalFunctionType ) ( void * arg ) ;
// Sizing an allocation for a method pointer can be subtle. In the Itanium
typedef bool ( Condition : : * InternalMethodType ) ( ) ;
// specifications, a method pointer has a predictable, uniform size. On the
typedef bool ( * InternalMethodCallerType ) ( void * arg ,
// other hand, MSVC ABI, method pointer sizes vary based on the
InternalMethodType internal_method ) ;
// inheritance of the class. Specifically, method pointers from classes with
// multiple inheritance are bigger than those of classes with single
bool ( * eval_ ) ( const Condition * ) ; // Actual evaluator
// inheritance. Other variations also exist.
InternalFunctionType function_ ; // function taking pointer returning bool
InternalMethodType method_ ; // method returning bool
// A good way to allocate enough space for *any* pointer in these ABIs is to
void * arg_ ; // arg of function_ or object of method_
// employ a class declaration with no definition. Because the inheritance
// structure is not available for this declaration, the compiler must
Condition ( ) ; // null constructor used only to create kTrue
// assume, conservatively, that its method pointers have the largest possible
// size.
class OpaqueClass ;
using ConservativeMethodPointer = bool ( OpaqueClass : : * ) ( ) ;
static_assert ( sizeof ( bool ( OpaqueClass : : * ) ( ) ) > = sizeof ( bool ( * ) ( void * ) ) ,
" Unsupported platform. " ) ;
// Allocation for a function pointer or method pointer.
// The {0} initializer ensures that all unused bytes of this buffer are
// always zeroed out. This is necessary, because GuaranteedEqual() compares
// all of the bytes, unaware of which bytes are relevant to a given `eval_`.
char callback_ [ sizeof ( ConservativeMethodPointer ) ] = { 0 } ;
// Function with which to evaluate callbacks and/or arguments.
bool ( * eval_ ) ( const Condition * ) ;
// Either an argument for a function call or an object for a method call.
void * arg_ ;
// Various functions eval_ can point to:
// Various functions eval_ can point to:
static bool CallVoidPtrFunction ( const Condition * ) ;
static bool CallVoidPtrFunction ( const Condition * ) ;
template < typename T > static bool CastAndCallFunction ( const Condition * c ) ;
template < typename T > static bool CastAndCallFunction ( const Condition * c ) ;
template < typename T > static bool CastAndCallMethod ( const Condition * c ) ;
template < typename T > static bool CastAndCallMethod ( const Condition * c ) ;
// Helper methods for storing, validating, and reading callback arguments.
template < typename T >
inline void StoreCallback ( T callback ) {
static_assert (
sizeof ( callback ) < = sizeof ( callback_ ) ,
" An overlarge pointer was passed as a callback to Condition. " ) ;
std : : memcpy ( callback_ , & callback , sizeof ( callback ) ) ;
}
template < typename T >
inline void ReadCallback ( T * callback ) const {
std : : memcpy ( callback , callback_ , sizeof ( * callback ) ) ;
}
Condition ( ) ; // null constructor used only to create kTrue
} ;
} ;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
@ -949,44 +984,48 @@ inline CondVar::CondVar() : cv_(0) {}
// static
// static
template < typename T >
template < typename T >
bool Condition : : CastAndCallMethod ( const Condition * c ) {
bool Condition : : CastAndCallMethod ( const Condition * c ) {
typedef bool ( T : : * MemberType ) ( ) ;
T * object = static_cast < T * > ( c - > arg_ ) ;
MemberType rm = reinterpret_cast < MemberType > ( c - > method_ ) ;
bool ( T : : * method_pointer ) ( ) ;
T * x = static_cast < T * > ( c - > arg_ ) ;
c - > ReadCallback ( & method_pointer ) ;
return ( x - > * r m) ( ) ;
return ( object - > * method_pointer ) ( ) ;
}
}
// static
// static
template < typename T >
template < typename T >
bool Condition : : CastAndCallFunction ( const Condition * c ) {
bool Condition : : CastAndCallFunction ( const Condition * c ) {
typedef bool ( * FuncType ) ( T * ) ;
bool ( * function ) ( T * ) ;
FuncType fn = reinterpret_cast < FuncType > ( c - > function_ ) ;
c - > ReadCallback ( & function ) ;
T * x = static_cast < T * > ( c - > arg_ ) ;
T * argument = static_cast < T * > ( c - > arg_ ) ;
return ( * fn ) ( x ) ;
return ( * functio n ) ( argument ) ;
}
}
template < typename T >
template < typename T >
inline Condition : : Condition ( bool ( * func ) ( T * ) , T * arg )
inline Condition : : Condition ( bool ( * func ) ( T * ) , T * arg )
: eval_ ( & CastAndCallFunction < T > ) ,
: eval_ ( & CastAndCallFunction < T > ) ,
function_ ( reinterpret_cast < InternalFunctionType > ( func ) ) ,
arg_ ( const_cast < void * > ( static_cast < const void * > ( arg ) ) ) {
method_ ( nullptr ) ,
static_assert ( sizeof ( & func ) < = sizeof ( callback_ ) ,
arg_ ( const_cast < void * > ( static_cast < const void * > ( arg ) ) ) { }
" An overlarge function pointer was passed to Condition. " ) ;
StoreCallback ( func ) ;
}
template < typename T >
template < typename T >
inline Condition : : Condition ( T * object ,
inline Condition : : Condition ( T * object ,
bool ( absl : : internal : : identity < T > : : type : : * method ) ( ) )
bool ( absl : : internal : : identity < T > : : type : : * method ) ( ) )
: eval_ ( & CastAndCallMethod < T > ) ,
: eval_ ( & CastAndCallMethod < T > ) ,
function_ ( nullptr ) ,
arg_ ( object ) {
method_ ( reinterpret_cast < InternalMethodType > ( method ) ) ,
static_assert ( sizeof ( & method ) < = sizeof ( callback_ ) ,
arg_ ( object ) { }
" An overlarge method pointer was passed to Condition. " ) ;
StoreCallback ( method ) ;
}
template < typename T >
template < typename T >
inline Condition : : Condition ( const T * object ,
inline Condition : : Condition ( const T * object ,
bool ( absl : : internal : : identity < T > : : type : : * method ) ( )
bool ( absl : : internal : : identity < T > : : type : : * method ) ( )
const )
const )
: eval_ ( & CastAndCallMethod < T > ) ,
: eval_ ( & CastAndCallMethod < T > ) ,
function_ ( nullptr ) ,
arg_ ( reinterpret_cast < void * > ( const_cast < T * > ( object ) ) ) {
method_ ( reinterpret_cast < InternalMethodType > ( method ) ) ,
StoreCallback ( method ) ;
arg_ ( reinterpret_cast < void * > ( const_cast < T * > ( object ) ) ) { }
}
// Register hooks for profiling support.
// Register hooks for profiling support.
//
//