| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * dsa.h |
| 4 | * Dynamic shared memory areas. |
| 5 | * |
| 6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 7 | * Portions Copyright (c) 1994, Regents of the University of California |
| 8 | * |
| 9 | * IDENTIFICATION |
| 10 | * src/include/utils/dsa.h |
| 11 | * |
| 12 | *------------------------------------------------------------------------- |
| 13 | */ |
| 14 | #ifndef DSA_H |
| 15 | #define DSA_H |
| 16 | |
| 17 | #include "port/atomics.h" |
| 18 | #include "storage/dsm.h" |
| 19 | |
| 20 | /* The opaque type used for an area. */ |
| 21 | struct dsa_area; |
| 22 | typedef struct dsa_area dsa_area; |
| 23 | |
| 24 | /* |
| 25 | * If this system only uses a 32-bit value for size_t, then use the 32-bit |
| 26 | * implementation of DSA. This limits the amount of DSA that can be created |
| 27 | * to something significantly less than the entire 4GB address space because |
| 28 | * the DSA pointer must encode both a segment identifier and an offset, but |
| 29 | * that shouldn't be a significant limitation in practice. |
| 30 | * |
| 31 | * If this system doesn't support atomic operations on 64-bit values, then |
| 32 | * we fall back to 32-bit dsa_pointer for lack of other options. |
| 33 | * |
| 34 | * For testing purposes, USE_SMALL_DSA_POINTER can be defined to force the use |
| 35 | * of 32-bit dsa_pointer even on systems capable of supporting a 64-bit |
| 36 | * dsa_pointer. |
| 37 | */ |
| 38 | #if SIZEOF_SIZE_T == 4 || !defined(PG_HAVE_ATOMIC_U64_SUPPORT) || \ |
| 39 | defined(USE_SMALL_DSA_POINTER) |
| 40 | #define SIZEOF_DSA_POINTER 4 |
| 41 | #else |
| 42 | #define SIZEOF_DSA_POINTER 8 |
| 43 | #endif |
| 44 | |
| 45 | /* |
| 46 | * The type of 'relative pointers' to memory allocated by a dynamic shared |
| 47 | * area. dsa_pointer values can be shared with other processes, but must be |
| 48 | * converted to backend-local pointers before they can be dereferenced. See |
| 49 | * dsa_get_address. Also, an atomic version and appropriately sized atomic |
| 50 | * operations. |
| 51 | */ |
| 52 | #if SIZEOF_DSA_POINTER == 4 |
| 53 | typedef uint32 dsa_pointer; |
| 54 | typedef pg_atomic_uint32 dsa_pointer_atomic; |
| 55 | #define dsa_pointer_atomic_init pg_atomic_init_u32 |
| 56 | #define dsa_pointer_atomic_read pg_atomic_read_u32 |
| 57 | #define dsa_pointer_atomic_write pg_atomic_write_u32 |
| 58 | #define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u32 |
| 59 | #define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u32 |
| 60 | #define DSA_POINTER_FORMAT "%08x" |
| 61 | #else |
| 62 | typedef uint64 dsa_pointer; |
| 63 | typedef pg_atomic_uint64 dsa_pointer_atomic; |
| 64 | #define dsa_pointer_atomic_init pg_atomic_init_u64 |
| 65 | #define dsa_pointer_atomic_read pg_atomic_read_u64 |
| 66 | #define dsa_pointer_atomic_write pg_atomic_write_u64 |
| 67 | #define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u64 |
| 68 | #define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u64 |
| 69 | #define DSA_POINTER_FORMAT "%016" INT64_MODIFIER "x" |
| 70 | #endif |
| 71 | |
| 72 | /* Flags for dsa_allocate_extended. */ |
| 73 | #define DSA_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) */ |
| 74 | #define DSA_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */ |
| 75 | #define DSA_ALLOC_ZERO 0x04 /* zero allocated memory */ |
| 76 | |
| 77 | /* A sentinel value for dsa_pointer used to indicate failure to allocate. */ |
| 78 | #define InvalidDsaPointer ((dsa_pointer) 0) |
| 79 | |
| 80 | /* Check if a dsa_pointer value is valid. */ |
| 81 | #define DsaPointerIsValid(x) ((x) != InvalidDsaPointer) |
| 82 | |
| 83 | /* Allocate uninitialized memory with error on out-of-memory. */ |
| 84 | #define dsa_allocate(area, size) \ |
| 85 | dsa_allocate_extended(area, size, 0) |
| 86 | |
| 87 | /* Allocate zero-initialized memory with error on out-of-memory. */ |
| 88 | #define dsa_allocate0(area, size) \ |
| 89 | dsa_allocate_extended(area, size, DSA_ALLOC_ZERO) |
| 90 | |
| 91 | /* |
| 92 | * The type used for dsa_area handles. dsa_handle values can be shared with |
| 93 | * other processes, so that they can attach to them. This provides a way to |
| 94 | * share allocated storage with other processes. |
| 95 | * |
| 96 | * The handle for a dsa_area is currently implemented as the dsm_handle |
| 97 | * for the first DSM segment backing this dynamic storage area, but client |
| 98 | * code shouldn't assume that is true. |
| 99 | */ |
| 100 | typedef dsm_handle dsa_handle; |
| 101 | |
| 102 | extern void dsa_startup(void); |
| 103 | |
| 104 | extern dsa_area *dsa_create(int tranche_id); |
| 105 | extern dsa_area *dsa_create_in_place(void *place, size_t size, |
| 106 | int tranche_id, dsm_segment *segment); |
| 107 | extern dsa_area *dsa_attach(dsa_handle handle); |
| 108 | extern dsa_area *dsa_attach_in_place(void *place, dsm_segment *segment); |
| 109 | extern void dsa_release_in_place(void *place); |
| 110 | extern void dsa_on_dsm_detach_release_in_place(dsm_segment *, Datum); |
| 111 | extern void dsa_on_shmem_exit_release_in_place(int, Datum); |
| 112 | extern void dsa_pin_mapping(dsa_area *area); |
| 113 | extern void dsa_detach(dsa_area *area); |
| 114 | extern void dsa_pin(dsa_area *area); |
| 115 | extern void dsa_unpin(dsa_area *area); |
| 116 | extern void dsa_set_size_limit(dsa_area *area, size_t limit); |
| 117 | extern size_t dsa_minimum_size(void); |
| 118 | extern dsa_handle dsa_get_handle(dsa_area *area); |
| 119 | extern dsa_pointer dsa_allocate_extended(dsa_area *area, size_t size, int flags); |
| 120 | extern void dsa_free(dsa_area *area, dsa_pointer dp); |
| 121 | extern void *dsa_get_address(dsa_area *area, dsa_pointer dp); |
| 122 | extern void dsa_trim(dsa_area *area); |
| 123 | extern void dsa_dump(dsa_area *area); |
| 124 | |
| 125 | #endif /* DSA_H */ |
| 126 | |