1 /*-------------------------------------------------------------------------
2  *
3  * dsa.h
4  *	  Dynamic shared memory areas.
5  *
6  * Portions Copyright (c) 1996-2018, 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. */
__clzti2(ti_int a)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