PostgreSQL Source Code  git master
injection_point.c File Reference
#include "postgres.h"
#include "utils/injection_point.h"
Include dependency graph for injection_point.c:

Go to the source code of this file.

Functions

Size InjectionPointShmemSize (void)
 
void InjectionPointShmemInit (void)
 
void InjectionPointAttach (const char *name, const char *library, const char *function, const void *private_data, int private_data_size)
 
bool InjectionPointDetach (const char *name)
 
void InjectionPointLoad (const char *name)
 
void InjectionPointRun (const char *name)
 
void InjectionPointCached (const char *name)
 
bool IsInjectionPointAttached (const char *name)
 

Function Documentation

◆ InjectionPointAttach()

void InjectionPointAttach ( const char *  name,
const char *  library,
const char *  function,
const void *  private_data,
int  private_data_size 
)

Definition at line 273 of file injection_point.c.

278 {
279 #ifdef USE_INJECTION_POINTS
280  InjectionPointEntry *entry;
281  uint64 generation;
282  uint32 max_inuse;
283  int free_idx;
284 
285  if (strlen(name) >= INJ_NAME_MAXLEN)
286  elog(ERROR, "injection point name %s too long (maximum of %u)",
288  if (strlen(library) >= INJ_LIB_MAXLEN)
289  elog(ERROR, "injection point library %s too long (maximum of %u)",
290  library, INJ_LIB_MAXLEN);
291  if (strlen(function) >= INJ_FUNC_MAXLEN)
292  elog(ERROR, "injection point function %s too long (maximum of %u)",
293  function, INJ_FUNC_MAXLEN);
294  if (private_data_size >= INJ_PRIVATE_MAXLEN)
295  elog(ERROR, "injection point data too long (maximum of %u)",
296  INJ_PRIVATE_MAXLEN);
297 
298  /*
299  * Allocate and register a new injection point. A new point should not
300  * exist. For testing purposes this should be fine.
301  */
302  LWLockAcquire(InjectionPointLock, LW_EXCLUSIVE);
303  max_inuse = pg_atomic_read_u32(&ActiveInjectionPoints->max_inuse);
304  free_idx = -1;
305 
306  for (int idx = 0; idx < max_inuse; idx++)
307  {
308  entry = &ActiveInjectionPoints->entries[idx];
309  generation = pg_atomic_read_u64(&entry->generation);
310  if (generation % 2 == 0)
311  {
312  /*
313  * Found a free slot where we can add the new entry, but keep
314  * going so that we will find out if the entry already exists.
315  */
316  if (free_idx == -1)
317  free_idx = idx;
318  }
319  else if (strcmp(entry->name, name) == 0)
320  elog(ERROR, "injection point \"%s\" already defined", name);
321  }
322  if (free_idx == -1)
323  {
324  if (max_inuse == MAX_INJECTION_POINTS)
325  elog(ERROR, "too many injection points");
326  free_idx = max_inuse;
327  }
328  entry = &ActiveInjectionPoints->entries[free_idx];
329  generation = pg_atomic_read_u64(&entry->generation);
330  Assert(generation % 2 == 0);
331 
332  /* Save the entry */
333  strlcpy(entry->name, name, sizeof(entry->name));
334  entry->name[INJ_NAME_MAXLEN - 1] = '\0';
335  strlcpy(entry->library, library, sizeof(entry->library));
336  entry->library[INJ_LIB_MAXLEN - 1] = '\0';
337  strlcpy(entry->function, function, sizeof(entry->function));
338  entry->function[INJ_FUNC_MAXLEN - 1] = '\0';
339  if (private_data != NULL)
340  memcpy(entry->private_data, private_data, private_data_size);
341 
343  pg_atomic_write_u64(&entry->generation, generation + 1);
344 
345  if (free_idx + 1 > max_inuse)
346  pg_atomic_write_u32(&ActiveInjectionPoints->max_inuse, free_idx + 1);
347 
348  LWLockRelease(InjectionPointLock);
349 
350 #else
351  elog(ERROR, "injection points are not supported by this build");
352 #endif
353 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:485
#define pg_write_barrier()
Definition: atomics.h:157
static void pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:276
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:239
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition: atomics.h:467
#define Assert(condition)
Definition: c.h:812
uint64_t uint64
Definition: c.h:486
uint32_t uint32
Definition: c.h:485
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define INJ_NAME_MAXLEN
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:114
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
const char * name

References Assert, elog, ERROR, idx(), INJ_NAME_MAXLEN, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), name, pg_atomic_read_u32(), pg_atomic_read_u64(), pg_atomic_write_u32(), pg_atomic_write_u64(), pg_write_barrier, and strlcpy().

Referenced by injection_points_attach().

◆ InjectionPointCached()

void InjectionPointCached ( const char *  name)

Definition at line 561 of file injection_point.c.

562 {
563 #ifdef USE_INJECTION_POINTS
564  InjectionPointCacheEntry *cache_entry;
565 
566  cache_entry = injection_point_cache_get(name);
567  if (cache_entry)
568  cache_entry->callback(name, cache_entry->private_data);
569 #else
570  elog(ERROR, "Injection points are not supported by this build");
571 #endif
572 }

References elog, ERROR, and name.

◆ InjectionPointDetach()

bool InjectionPointDetach ( const char *  name)

Definition at line 361 of file injection_point.c.

362 {
363 #ifdef USE_INJECTION_POINTS
364  bool found = false;
365  int idx;
366  int max_inuse;
367 
368  LWLockAcquire(InjectionPointLock, LW_EXCLUSIVE);
369 
370  /* Find it in the shmem array, and mark the slot as unused */
371  max_inuse = (int) pg_atomic_read_u32(&ActiveInjectionPoints->max_inuse);
372  for (idx = max_inuse - 1; idx >= 0; --idx)
373  {
374  InjectionPointEntry *entry = &ActiveInjectionPoints->entries[idx];
375  uint64 generation;
376 
377  generation = pg_atomic_read_u64(&entry->generation);
378  if (generation % 2 == 0)
379  continue; /* empty slot */
380 
381  if (strcmp(entry->name, name) == 0)
382  {
383  Assert(!found);
384  found = true;
385  pg_atomic_write_u64(&entry->generation, generation + 1);
386  break;
387  }
388  }
389 
390  /* If we just removed the highest-numbered entry, update 'max_inuse' */
391  if (found && idx == max_inuse - 1)
392  {
393  for (; idx >= 0; --idx)
394  {
395  InjectionPointEntry *entry = &ActiveInjectionPoints->entries[idx];
396  uint64 generation;
397 
398  generation = pg_atomic_read_u64(&entry->generation);
399  if (generation % 2 != 0)
400  break;
401  }
402  pg_atomic_write_u32(&ActiveInjectionPoints->max_inuse, idx + 1);
403  }
404  LWLockRelease(InjectionPointLock);
405 
406  return found;
407 #else
408  elog(ERROR, "Injection points are not supported by this build");
409  return true; /* silence compiler */
410 #endif
411 }

References Assert, elog, ERROR, idx(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), name, pg_atomic_read_u32(), pg_atomic_read_u64(), pg_atomic_write_u32(), and pg_atomic_write_u64().

Referenced by injection_points_cleanup(), and injection_points_detach().

◆ InjectionPointLoad()

void InjectionPointLoad ( const char *  name)

Definition at line 531 of file injection_point.c.

532 {
533 #ifdef USE_INJECTION_POINTS
534  InjectionPointCacheRefresh(name);
535 #else
536  elog(ERROR, "Injection points are not supported by this build");
537 #endif
538 }

References elog, ERROR, and name.

◆ InjectionPointRun()

void InjectionPointRun ( const char *  name)

Definition at line 544 of file injection_point.c.

545 {
546 #ifdef USE_INJECTION_POINTS
547  InjectionPointCacheEntry *cache_entry;
548 
549  cache_entry = InjectionPointCacheRefresh(name);
550  if (cache_entry)
551  cache_entry->callback(name, cache_entry->private_data);
552 #else
553  elog(ERROR, "Injection points are not supported by this build");
554 #endif
555 }

References elog, ERROR, and name.

◆ InjectionPointShmemInit()

void InjectionPointShmemInit ( void  )

Definition at line 249 of file injection_point.c.

250 {
251 #ifdef USE_INJECTION_POINTS
252  bool found;
253 
254  ActiveInjectionPoints = ShmemInitStruct("InjectionPoint hash",
255  sizeof(InjectionPointsCtl),
256  &found);
257  if (!IsUnderPostmaster)
258  {
259  Assert(!found);
260  pg_atomic_init_u32(&ActiveInjectionPoints->max_inuse, 0);
261  for (int i = 0; i < MAX_INJECTION_POINTS; i++)
262  pg_atomic_init_u64(&ActiveInjectionPoints->entries[i].generation, 0);
263  }
264  else
265  Assert(found);
266 #endif
267 }
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:221
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:453
bool IsUnderPostmaster
Definition: globals.c:119
int i
Definition: isn.c:72
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382

References Assert, i, IsUnderPostmaster, pg_atomic_init_u32(), pg_atomic_init_u64(), and ShmemInitStruct().

Referenced by CreateOrAttachShmemStructs().

◆ InjectionPointShmemSize()

Size InjectionPointShmemSize ( void  )

Definition at line 233 of file injection_point.c.

234 {
235 #ifdef USE_INJECTION_POINTS
236  Size sz = 0;
237 
238  sz = add_size(sz, sizeof(InjectionPointsCtl));
239  return sz;
240 #else
241  return 0;
242 #endif
243 }
size_t Size
Definition: c.h:559
Size add_size(Size s1, Size s2)
Definition: shmem.c:488

References add_size().

Referenced by CalculateShmemSize().

◆ IsInjectionPointAttached()

bool IsInjectionPointAttached ( const char *  name)

Definition at line 578 of file injection_point.c.

579 {
580 #ifdef USE_INJECTION_POINTS
581  return InjectionPointCacheRefresh(name) != NULL;
582 #else
583  elog(ERROR, "Injection points are not supported by this build");
584  return false; /* silence compiler */
585 #endif
586 }

References elog, ERROR, and name.