@ -44,8 +44,59 @@ namespace grpc_core {
class Arena ;
template < typename T >
struct ArenaContextType ;
namespace arena_detail {
// Tracks all registered arena context types (these should only be registered
// via ArenaContextTraits at static initialization time).
class BaseArenaContextTraits {
public :
// Count of number of contexts that have been allocated.
static uint16_t NumContexts ( ) {
return static_cast < uint16_t > ( RegisteredTraits ( ) . size ( ) ) ;
}
// Number of bytes required to store the context pointers on an arena.
static size_t ContextSize ( ) { return NumContexts ( ) * sizeof ( void * ) ; }
// Call the registered destruction function for a context.
static void Destroy ( uint16_t id , void * ptr ) {
if ( ptr = = nullptr ) return ;
RegisteredTraits ( ) [ id ] ( ptr ) ;
}
protected :
// Allocate a new context id and register the destruction function.
static uint16_t MakeId ( void ( * destroy ) ( void * ptr ) ) {
auto & traits = RegisteredTraits ( ) ;
const uint16_t id = static_cast < uint16_t > ( traits . size ( ) ) ;
traits . push_back ( destroy ) ;
return id ;
}
private :
static std : : vector < void ( * ) ( void * ) > & RegisteredTraits ( ) {
static NoDestruct < std : : vector < void ( * ) ( void * ) > > registered_traits ;
return * registered_traits ;
}
} ;
// Traits for a specific context type.
template < typename T >
class ArenaContextTraits : public BaseArenaContextTraits {
public :
static uint16_t id ( ) { return id_ ; }
private :
static const uint16_t id_ ;
} ;
template < typename T >
const uint16_t ArenaContextTraits < T > : : id_ = BaseArenaContextTraits : : MakeId (
[ ] ( void * ptr ) { ArenaContextType < T > : : Destroy ( static_cast < T * > ( ptr ) ) ; } ) ;
template < typename T , typename A , typename B >
struct IfArray {
using Result = A ;
@ -215,6 +266,21 @@ class Arena final : public RefCounted<Arena, NonPolymorphicRefCount,
delete p ;
}
template < typename T >
T * GetContext ( ) {
return static_cast < T * > (
contexts ( ) [ arena_detail : : ArenaContextTraits < T > : : id ( ) ] ) ;
}
template < typename T >
void SetContext ( T * context ) {
void * & slot = contexts ( ) [ arena_detail : : ArenaContextTraits < T > : : id ( ) ] ;
if ( slot ! = nullptr ) {
ArenaContextType < T > : : Destroy ( static_cast < T * > ( slot ) ) ;
}
slot = context ;
}
private :
friend struct arena_detail : : UnrefDestroy ;
@ -247,19 +313,20 @@ class Arena final : public RefCounted<Arena, NonPolymorphicRefCount,
// quick optimization (avoiding an atomic fetch-add) for the common case
// where we wish to create an arena and then perform an immediate
// allocation.
explicit Arena ( size_t initial_size , size_t initial_alloc ,
explicit Arena ( size_t initial_size ,
RefCountedPtr < ArenaFactory > arena_factory ) ;
~ Arena ( ) ;
void * AllocZone ( size_t size ) ;
void Destroy ( ) const ;
void * * contexts ( ) { return reinterpret_cast < void * * > ( this + 1 ) ; }
// Keep track of the total used size. We use this in our call sizing
// hysteresis.
std : : atomic < size_t > total_used_ { 0 } ;
std : : atomic < size_t > total_allocated_ { 0 } ;
const size_t initial_zone_size_ ;
std : : atomic < size_t > total_used_ ;
std : : atomic < size_t > total_allocated_ { initial_zone_size_ } ;
// If the initial arena allocation wasn't enough, we allocate additional zones
// in a reverse linked list. Each additional zone consists of (1) a pointer to
// the zone added before this zone (null if this is the first additional zone)
@ -280,6 +347,17 @@ inline void UnrefDestroy::operator()(const Arena* arena) const {
}
} // namespace arena_detail
namespace promise_detail {
template < typename T >
class Context < T , absl : : void_t < decltype ( ArenaContextType < T > : : Destroy ) > > {
public :
static T * get ( ) { return GetContext < Arena > ( ) - > GetContext < T > ( ) ; }
static void set ( T * value ) { GetContext < Arena > ( ) - > SetContext ( value ) ; }
} ;
} // namespace promise_detail
} // namespace grpc_core
# endif // GRPC_SRC_CORE_LIB_RESOURCE_QUOTA_ARENA_H