@ -144,8 +144,20 @@ typedef struct LWLockHandle
static int num_held_lwlocks = 0 ;
static LWLockHandle held_lwlocks [ MAX_SIMUL_LWLOCKS ] ;
static int lock_addin_request = 0 ;
static bool lock_addin_request_allowed = true ;
/* struct representing the LWLock tranche request for named tranche */
typedef struct NamedLWLockTrancheRequest
{
char tranche_name [ NAMEDATALEN ] ;
int num_lwlocks ;
} NamedLWLockTrancheRequest ;
NamedLWLockTrancheRequest * NamedLWLockTrancheRequestArray = NULL ;
static int NamedLWLockTrancheRequestsAllocated = 0 ;
int NamedLWLockTrancheRequests = 0 ;
NamedLWLockTranche * NamedLWLockTrancheArray = NULL ;
static bool lock_named_request_allowed = true ;
# ifdef LWLOCK_STATS
typedef struct lwlock_stats_key
@ -335,6 +347,22 @@ get_lwlock_stats_entry(LWLock *lock)
# endif /* LWLOCK_STATS */
/*
* Compute number of LWLocks required by named tranches . These will be
* allocated in the main array .
*/
static int
NumLWLocksByNamedTranches ( void )
{
int numLocks = 0 ;
int i ;
for ( i = 0 ; i < NamedLWLockTrancheRequests ; i + + )
numLocks + = NamedLWLockTrancheRequestArray [ i ] . num_lwlocks ;
return numLocks ;
}
/*
* Compute number of LWLocks to allocate in the main array .
*/
@ -353,64 +381,49 @@ NumLWLocks(void)
/* Predefined LWLocks */
numLocks = NUM_FIXED_LWLOCKS ;
/*
* Add any requested by loadable modules ; for backwards - compatibility
* reasons , allocate at least NUM_USER_DEFINED_LWLOCKS of them even if
* there are no explicit requests .
*/
lock_addin_request_allowed = false ;
numLocks + = Max ( lock_addin_request , NUM_USER_DEFINED_LWLOCKS ) ;
/* Disallow named LWLocks' requests after startup */
lock_named_request_allowed = false ;
return numLocks ;
}
/*
* RequestAddinLWLocks
* Request that extra LWLocks be allocated for use by
* a loadable module .
*
* This is only useful if called from the _PG_init hook of a library that
* is loaded into the postmaster via shared_preload_libraries . Once
* shared memory has been allocated , calls will be ignored . ( We could
* raise an error , but it seems better to make it a no - op , so that
* libraries containing such calls can be reloaded if needed . )
*/
void
RequestAddinLWLocks ( int n )
{
if ( IsUnderPostmaster | | ! lock_addin_request_allowed )
return ; /* too late */
lock_addin_request + = n ;
}
/*
* Compute shmem space needed for LWLocks .
* Compute shmem space needed for LWLocks and named tranches .
*/
Size
LWLockShmemSize ( void )
{
Size size ;
int i ;
int numLocks = NumLWLocks ( ) ;
numLocks + = NumLWLocksByNamedTranches ( ) ;
/* Space for the LWLock array. */
size = mul_size ( numLocks , sizeof ( LWLockPadded ) ) ;
/* Space for dynamic allocation counter, plus room for alignment. */
size = add_size ( size , 3 * sizeof ( int ) + LWLOCK_PADDED_SIZE ) ;
/* space for named tranches. */
size = add_size ( size , mul_size ( NamedLWLockTrancheRequests , sizeof ( NamedLWLockTranche ) ) ) ;
/* space for name of each tranche. */
for ( i = 0 ; i < NamedLWLockTrancheRequests ; i + + )
size = add_size ( size , strlen ( NamedLWLockTrancheRequestArray [ i ] . tranche_name ) + 1 ) ;
return size ;
}
/*
* Allocate shmem space for the main LWLock array and initialize it . We also
* register the main tranch here .
* Allocate shmem space for the main LWLock array and named tranches and
* initialize it . We also register the main and named tranche here .
*/
void
CreateLWLocks ( void )
{
int i ;
StaticAssertExpr ( LW_VAL_EXCLUSIVE > ( uint32 ) MAX_BACKENDS ,
" MAX_BACKENDS too big for lwlock.c " ) ;
@ -421,11 +434,13 @@ CreateLWLocks(void)
if ( ! IsUnderPostmaster )
{
int numLocks = NumLWLocks ( ) ;
int numNamedLocks = NumLWLocksByNamedTranches ( ) ;
Size spaceLocks = LWLockShmemSize ( ) ;
LWLockPadded * lock ;
int * LWLockCounter ;
char * ptr ;
int id ;
int j ;
/* Allocate space */
ptr = ( char * ) ShmemAlloc ( spaceLocks ) ;
@ -438,7 +453,7 @@ CreateLWLocks(void)
MainLWLockArray = ( LWLockPadded * ) ptr ;
/* Initialize all LWLocks in main array */
/* Initialize all fixed LWLocks in main array */
for ( id = 0 , lock = MainLWLockArray ; id < numLocks ; id + + , lock + + )
LWLockInitialize ( & lock - > lock , LWTRANCHE_MAIN ) ;
@ -453,6 +468,40 @@ CreateLWLocks(void)
LWLockCounter [ 0 ] = NUM_FIXED_LWLOCKS ;
LWLockCounter [ 1 ] = numLocks ;
LWLockCounter [ 2 ] = LWTRANCHE_FIRST_USER_DEFINED ;
/* Initialize named tranches. */
if ( NamedLWLockTrancheRequests > 0 )
{
char * trancheNames ;
NamedLWLockTrancheArray = ( NamedLWLockTranche * )
& MainLWLockArray [ numLocks + numNamedLocks ] ;
trancheNames = ( char * ) NamedLWLockTrancheArray +
( NamedLWLockTrancheRequests * sizeof ( NamedLWLockTranche ) ) ;
lock = & MainLWLockArray [ numLocks ] ;
for ( i = 0 ; i < NamedLWLockTrancheRequests ; i + + )
{
NamedLWLockTrancheRequest * request ;
NamedLWLockTranche * tranche ;
char * name ;
request = & NamedLWLockTrancheRequestArray [ i ] ;
tranche = & NamedLWLockTrancheArray [ i ] ;
name = trancheNames ;
trancheNames + = strlen ( request - > tranche_name ) + 1 ;
strcpy ( name , request - > tranche_name ) ;
tranche - > lwLockTranche . name = name ;
tranche - > trancheId = LWLockNewTrancheId ( ) ;
tranche - > lwLockTranche . array_base = lock ;
tranche - > lwLockTranche . array_stride = sizeof ( LWLockPadded ) ;
for ( j = 0 ; j < request - > num_lwlocks ; j + + , lock + + )
LWLockInitialize ( & lock - > lock , tranche - > trancheId ) ;
}
}
}
if ( LWLockTrancheArray = = NULL )
@ -468,6 +517,11 @@ CreateLWLocks(void)
MainLWLockTranche . array_base = MainLWLockArray ;
MainLWLockTranche . array_stride = sizeof ( LWLockPadded ) ;
LWLockRegisterTranche ( LWTRANCHE_MAIN , & MainLWLockTranche ) ;
/* Register named tranches. */
for ( i = 0 ; i < NamedLWLockTrancheRequests ; i + + )
LWLockRegisterTranche ( NamedLWLockTrancheArray [ i ] . trancheId ,
& NamedLWLockTrancheArray [ i ] . lwLockTranche ) ;
}
/*
@ -507,6 +561,45 @@ LWLockAssign(void)
return result ;
}
/*
* GetNamedLWLockTranche - returns the base address of LWLock from the
* specified tranche .
*
* Caller needs to retrieve the requested number of LWLocks starting from
* the base lock address returned by this API . This can be used for
* tranches that are requested by using RequestNamedLWLockTranche ( ) API .
*/
LWLockPadded *
GetNamedLWLockTranche ( const char * tranche_name )
{
int lock_pos ;
int i ;
int * LWLockCounter ;
LWLockCounter = ( int * ) ( ( char * ) MainLWLockArray - 3 * sizeof ( int ) ) ;
/*
* Obtain the position of base address of LWLock belonging to requested
* tranche_name in MainLWLockArray . LWLocks for named tranches are placed
* in MainLWLockArray after LWLocks specified by LWLockCounter [ 1 ] .
*/
lock_pos = LWLockCounter [ 1 ] ;
for ( i = 0 ; i < NamedLWLockTrancheRequests ; i + + )
{
if ( strcmp ( NamedLWLockTrancheRequestArray [ i ] . tranche_name ,
tranche_name ) = = 0 )
return & MainLWLockArray [ lock_pos ] ;
lock_pos + = NamedLWLockTrancheRequestArray [ i ] . num_lwlocks ;
}
if ( i > = NamedLWLockTrancheRequests )
elog ( ERROR , " requested tranche is not registered " ) ;
/* just to keep compiler quiet */
return NULL ;
}
/*
* Allocate a new tranche ID .
*/
@ -551,6 +644,55 @@ LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche)
LWLockTrancheArray [ tranche_id ] = tranche ;
}
/*
* RequestNamedLWLockTranche
* Request that extra LWLocks be allocated during postmaster
* startup .
*
* This is only useful for extensions if called from the _PG_init hook
* of a library that is loaded into the postmaster via
* shared_preload_libraries . Once shared memory has been allocated , calls
* will be ignored . ( We could raise an error , but it seems better to make
* it a no - op , so that libraries containing such calls can be reloaded if
* needed . )
*/
void
RequestNamedLWLockTranche ( const char * tranche_name , int num_lwlocks )
{
NamedLWLockTrancheRequest * request ;
if ( IsUnderPostmaster | | ! lock_named_request_allowed )
return ; /* too late */
if ( NamedLWLockTrancheRequestArray = = NULL )
{
NamedLWLockTrancheRequestsAllocated = 16 ;
NamedLWLockTrancheRequestArray = ( NamedLWLockTrancheRequest * )
MemoryContextAlloc ( TopMemoryContext ,
NamedLWLockTrancheRequestsAllocated
* sizeof ( NamedLWLockTrancheRequest ) ) ;
}
if ( NamedLWLockTrancheRequests > = NamedLWLockTrancheRequestsAllocated )
{
int i = NamedLWLockTrancheRequestsAllocated ;
while ( i < = NamedLWLockTrancheRequests )
i * = 2 ;
NamedLWLockTrancheRequestArray = ( NamedLWLockTrancheRequest * )
repalloc ( NamedLWLockTrancheRequestArray ,
i * sizeof ( NamedLWLockTrancheRequest ) ) ;
NamedLWLockTrancheRequestsAllocated = i ;
}
request = & NamedLWLockTrancheRequestArray [ NamedLWLockTrancheRequests ] ;
Assert ( strlen ( tranche_name ) + 1 < NAMEDATALEN ) ;
StrNCpy ( request - > tranche_name , tranche_name , NAMEDATALEN ) ;
request - > num_lwlocks = num_lwlocks ;
NamedLWLockTrancheRequests + + ;
}
/*
* LWLockInitialize - initialize a new lwlock ; it ' s initially unlocked
*/