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 *arg)
 
void InjectionPointCached (const char *name, void *arg)
 
bool IsInjectionPointAttached (const char *name)
 
ListInjectionPointList (void)
 

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 characters)",
287 name, INJ_NAME_MAXLEN - 1);
288 if (strlen(library) >= INJ_LIB_MAXLEN)
289 elog(ERROR, "injection point library %s too long (maximum of %u characters)",
290 library, INJ_LIB_MAXLEN - 1);
291 if (strlen(function) >= INJ_FUNC_MAXLEN)
292 elog(ERROR, "injection point function %s too long (maximum of %u characters)",
293 function, INJ_FUNC_MAXLEN - 1);
294 if (private_data_size > INJ_PRIVATE_MAXLEN)
295 elog(ERROR, "injection point data too long (maximum of %u bytes)",
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 strlcpy(entry->library, library, sizeof(entry->library));
335 strlcpy(entry->function, function, sizeof(entry->function));
336 if (private_data != NULL)
337 memcpy(entry->private_data, private_data, private_data_size);
338
340 pg_atomic_write_u64(&entry->generation, generation + 1);
341
342 if (free_idx + 1 > max_inuse)
343 pg_atomic_write_u32(&ActiveInjectionPoints->max_inuse, free_idx + 1);
344
345 LWLockRelease(InjectionPointLock);
346
347#else
348 elog(ERROR, "injection points are not supported by this build");
349#endif
350}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:262
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:485
#define pg_write_barrier()
Definition: atomics.h:155
static void pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:274
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:237
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition: atomics.h:467
uint64_t uint64
Definition: c.h:553
uint32_t uint32
Definition: c.h:552
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
Assert(PointerIsAligned(start, uint64))
#define INJ_NAME_MAXLEN
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1178
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1898
@ LW_EXCLUSIVE
Definition: lwlock.h:112
on_exit_nicely_callback function
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
const char * name

References Assert(), elog, ERROR, function, 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(), injection_points_attach_func(), and test_aio_shmem_startup().

◆ InjectionPointCached()

void InjectionPointCached ( const char *  name,
void *  arg 
)

Definition at line 558 of file injection_point.c.

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

References arg, elog, ERROR, and name.

◆ InjectionPointDetach()

bool InjectionPointDetach ( const char *  name)

Definition at line 358 of file injection_point.c.

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

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().

◆ InjectionPointList()

List * InjectionPointList ( void  )

Definition at line 591 of file injection_point.c.

592{
593#ifdef USE_INJECTION_POINTS
594 List *inj_points = NIL;
595 uint32 max_inuse;
596
597 LWLockAcquire(InjectionPointLock, LW_SHARED);
598
599 max_inuse = pg_atomic_read_u32(&ActiveInjectionPoints->max_inuse);
600
601 for (uint32 idx = 0; idx < max_inuse; idx++)
602 {
603 InjectionPointEntry *entry;
604 InjectionPointData *inj_point;
605 uint64 generation;
606
607 entry = &ActiveInjectionPoints->entries[idx];
608 generation = pg_atomic_read_u64(&entry->generation);
609
610 /* skip free slots */
611 if (generation % 2 == 0)
612 continue;
613
615 inj_point->name = pstrdup(entry->name);
616 inj_point->library = pstrdup(entry->library);
617 inj_point->function = pstrdup(entry->function);
618 inj_points = lappend(inj_points, inj_point);
619 }
620
621 LWLockRelease(InjectionPointLock);
622
623 return inj_points;
624
625#else
626 elog(ERROR, "Injection points are not supported by this build");
627 return NIL; /* keep compiler quiet */
628#endif
629}
#define palloc0_object(type)
Definition: fe_memutils.h:75
List * lappend(List *list, void *datum)
Definition: list.c:339
@ LW_SHARED
Definition: lwlock.h:113
char * pstrdup(const char *in)
Definition: mcxt.c:1781
#define NIL
Definition: pg_list.h:68
const char * library
const char * function
Definition: pg_list.h:54

References elog, ERROR, InjectionPointData::function, idx(), lappend(), InjectionPointData::library, LW_SHARED, LWLockAcquire(), LWLockRelease(), InjectionPointData::name, NIL, palloc0_object, pg_atomic_read_u32(), pg_atomic_read_u64(), and pstrdup().

Referenced by injection_points_list().

◆ InjectionPointLoad()

void InjectionPointLoad ( const char *  name)

Definition at line 528 of file injection_point.c.

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

References elog, ERROR, and name.

Referenced by test_aio_shmem_startup().

◆ InjectionPointRun()

void InjectionPointRun ( const char *  name,
void *  arg 
)

Definition at line 541 of file injection_point.c.

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

References arg, 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);
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:219
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:453
bool IsUnderPostmaster
Definition: globals.c:120
int i
Definition: isn.c:77
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:389

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:625
Size add_size(Size s1, Size s2)
Definition: shmem.c:495

References add_size().

Referenced by CalculateShmemSize().

◆ IsInjectionPointAttached()

bool IsInjectionPointAttached ( const char *  name)

Definition at line 575 of file injection_point.c.

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

References elog, ERROR, and name.