PostgreSQL Source Code git master
Loading...
Searching...
No Matches
setup.c File Reference
#include "postgres.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgworker.h"
#include "storage/proc.h"
#include "storage/shm_toc.h"
#include "test_shm_mq.h"
#include "utils/memutils.h"
#include "utils/wait_event.h"
Include dependency graph for setup.c:

Go to the source code of this file.

Data Structures

struct  worker_state
 

Functions

static void setup_dynamic_shared_memory (int64 queue_size, int nworkers, dsm_segment **segp, test_shm_mq_header **hdrp, shm_mq **outp, shm_mq **inp)
 
static worker_statesetup_background_workers (int nworkers, dsm_segment *seg)
 
static void cleanup_background_workers (dsm_segment *seg, Datum arg)
 
static void wait_for_workers_to_become_ready (worker_state *wstate, volatile test_shm_mq_header *hdr)
 
static bool check_worker_status (worker_state *wstate)
 
void test_shm_mq_setup (int64 queue_size, int32 nworkers, dsm_segment **segp, shm_mq_handle **output, shm_mq_handle **input)
 

Variables

static uint32 we_bgworker_startup = 0
 

Function Documentation

◆ check_worker_status()

static bool check_worker_status ( worker_state wstate)
static

Definition at line 308 of file setup.c.

309{
310 int n;
311
312 /* If any workers (or the postmaster) have died, we have failed. */
313 for (n = 0; n < wstate->nworkers; ++n)
314 {
315 BgwHandleStatus status;
316 pid_t pid;
317
318 status = GetBackgroundWorkerPid(wstate->handle[n], &pid);
319 if (status == BGWH_STOPPED || status == BGWH_POSTMASTER_DIED)
320 return false;
321 }
322
323 /* Otherwise, things still look OK. */
324 return true;
325}
BgwHandleStatus GetBackgroundWorkerPid(BackgroundWorkerHandle *handle, pid_t *pidp)
Definition bgworker.c:1165
BgwHandleStatus
Definition bgworker.h:111
@ BGWH_POSTMASTER_DIED
Definition bgworker.h:115
@ BGWH_STOPPED
Definition bgworker.h:114
static int fb(int x)

References BGWH_POSTMASTER_DIED, BGWH_STOPPED, fb(), and GetBackgroundWorkerPid().

Referenced by wait_for_workers_to_become_ready().

◆ cleanup_background_workers()

static void cleanup_background_workers ( dsm_segment seg,
Datum  arg 
)
static

Definition at line 248 of file setup.c.

249{
251
252 while (wstate->nworkers > 0)
253 {
254 --wstate->nworkers;
255 TerminateBackgroundWorker(wstate->handle[wstate->nworkers]);
256 }
257}
void TerminateBackgroundWorker(BackgroundWorkerHandle *handle)
Definition bgworker.c:1304
Datum arg
Definition elog.c:1322
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
int nworkers
Definition setup.c:29

References arg, DatumGetPointer(), fb(), worker_state::nworkers, and TerminateBackgroundWorker().

Referenced by setup_background_workers(), and test_shm_mq_setup().

◆ setup_background_workers()

static worker_state * setup_background_workers ( int  nworkers,
dsm_segment seg 
)
static

Definition at line 176 of file setup.c.

177{
178 MemoryContext oldcontext;
179 BackgroundWorker worker;
181 int i;
182
183 /*
184 * We need the worker_state object and the background worker handles to
185 * which it points to be allocated in CurTransactionContext rather than
186 * ExprContext; otherwise, they'll be destroyed before the on_dsm_detach
187 * hooks run.
188 */
190
191 /* Create worker state object. */
193 offsetof(worker_state, handle) +
194 sizeof(BackgroundWorkerHandle *) * nworkers);
195 wstate->nworkers = 0;
196
197 /*
198 * Arrange to kill all the workers if we abort before all workers are
199 * finished hooking themselves up to the dynamic shared memory segment.
200 *
201 * If we die after all the workers have finished hooking themselves up to
202 * the dynamic shared memory segment, we'll mark the two queues to which
203 * we're directly connected as detached, and the worker(s) connected to
204 * those queues will exit, marking any other queues to which they are
205 * connected as detached. This will cause any as-yet-unaware workers
206 * connected to those queues to exit in their turn, and so on, until
207 * everybody exits.
208 *
209 * But suppose the workers which are supposed to connect to the queues to
210 * which we're directly attached exit due to some error before they
211 * actually attach the queues. The remaining workers will have no way of
212 * knowing this. From their perspective, they're still waiting for those
213 * workers to start, when in fact they've already died.
214 */
217
218 /* Configure a worker. */
219 memset(&worker, 0, sizeof(worker));
223 sprintf(worker.bgw_library_name, "test_shm_mq");
224 sprintf(worker.bgw_function_name, "test_shm_mq_main");
225 snprintf(worker.bgw_type, BGW_MAXLEN, "test_shm_mq");
227 /* set bgw_notify_pid, so we can detect if the worker stops */
228 worker.bgw_notify_pid = MyProcPid;
229
230 /* Register the workers. */
231 for (i = 0; i < nworkers; ++i)
232 {
233 snprintf(worker.bgw_name, BGW_MAXLEN, "test_shm_mq worker %d", i + 1);
234 if (!RegisterDynamicBackgroundWorker(&worker, &wstate->handle[i]))
237 errmsg("could not register background process"),
238 errhint("You may need to increase \"max_worker_processes\".")));
239 ++wstate->nworkers;
240 }
241
242 /* All done. */
243 MemoryContextSwitchTo(oldcontext);
244 return wstate;
245}
bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle)
Definition bgworker.c:1053
#define BGW_NEVER_RESTART
Definition bgworker.h:92
@ BgWorkerStart_ConsistentState
Definition bgworker.h:87
#define BGWORKER_SHMEM_ACCESS
Definition bgworker.h:53
#define BGW_MAXLEN
Definition bgworker.h:93
dsm_handle dsm_segment_handle(dsm_segment *seg)
Definition dsm.c:1123
void on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition dsm.c:1132
int errcode(int sqlerrcode)
Definition elog.c:874
int errhint(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
int MyProcPid
Definition globals.c:47
int i
Definition isn.c:77
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
MemoryContext TopTransactionContext
Definition mcxt.c:171
MemoryContext CurTransactionContext
Definition mcxt.c:172
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define sprintf
Definition port.h:262
#define snprintf
Definition port.h:260
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Datum UInt32GetDatum(uint32 X)
Definition postgres.h:232
static void cleanup_background_workers(dsm_segment *seg, Datum arg)
Definition setup.c:248
char bgw_function_name[BGW_MAXLEN]
Definition bgworker.h:104
char bgw_name[BGW_MAXLEN]
Definition bgworker.h:98
char bgw_type[BGW_MAXLEN]
Definition bgworker.h:99
BgWorkerStartTime bgw_start_time
Definition bgworker.h:101
pid_t bgw_notify_pid
Definition bgworker.h:107
char bgw_library_name[MAXPGPATH]
Definition bgworker.h:103

References BackgroundWorker::bgw_flags, BackgroundWorker::bgw_function_name, BackgroundWorker::bgw_library_name, BackgroundWorker::bgw_main_arg, BGW_MAXLEN, BackgroundWorker::bgw_name, BGW_NEVER_RESTART, BackgroundWorker::bgw_notify_pid, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_start_time, BackgroundWorker::bgw_type, BGWORKER_SHMEM_ACCESS, BgWorkerStart_ConsistentState, cleanup_background_workers(), CurTransactionContext, dsm_segment_handle(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), i, MemoryContextAlloc(), MemoryContextSwitchTo(), MyProcPid, on_dsm_detach(), PointerGetDatum(), RegisterDynamicBackgroundWorker(), snprintf, sprintf, TopTransactionContext, and UInt32GetDatum().

Referenced by test_shm_mq_setup().

◆ setup_dynamic_shared_memory()

static void setup_dynamic_shared_memory ( int64  queue_size,
int  nworkers,
dsm_segment **  segp,
test_shm_mq_header **  hdrp,
shm_mq **  outp,
shm_mq **  inp 
)
static

Definition at line 93 of file setup.c.

96{
98 int i;
99 Size segsize;
100 dsm_segment *seg;
101 shm_toc *toc;
103
104 /* Ensure a valid queue size. */
105 if (queue_size < 0 || ((uint64) queue_size) < shm_mq_minimum_size)
108 errmsg("queue size must be at least %zu bytes",
110 if (queue_size != ((Size) queue_size))
113 errmsg("queue size overflows size_t")));
114
115 /*
116 * Estimate how much shared memory we need.
117 *
118 * Because the TOC machinery may choose to insert padding of oddly-sized
119 * requests, we must estimate each chunk separately.
120 *
121 * We need one key to register the location of the header, and we need
122 * nworkers + 1 keys to track the locations of the message queues.
123 */
126 for (i = 0; i <= nworkers; ++i)
127 shm_toc_estimate_chunk(&e, (Size) queue_size);
128 shm_toc_estimate_keys(&e, 2 + nworkers);
129 segsize = shm_toc_estimate(&e);
130
131 /* Create the shared memory segment and establish a table of contents. */
132 seg = dsm_create(shm_toc_estimate(&e), 0);
134 segsize);
135
136 /* Set up the header region. */
137 hdr = shm_toc_allocate(toc, sizeof(test_shm_mq_header));
138 SpinLockInit(&hdr->mutex);
139 hdr->workers_total = nworkers;
140 hdr->workers_attached = 0;
141 hdr->workers_ready = 0;
142 shm_toc_insert(toc, 0, hdr);
143
144 /* Set up one message queue per worker, plus one. */
145 for (i = 0; i <= nworkers; ++i)
146 {
147 shm_mq *mq;
148
149 mq = shm_mq_create(shm_toc_allocate(toc, (Size) queue_size),
150 (Size) queue_size);
151 shm_toc_insert(toc, i + 1, mq);
152
153 if (i == 0)
154 {
155 /* We send messages to the first queue. */
157 *outp = mq;
158 }
159 if (i == nworkers)
160 {
161 /* We receive messages from the last queue. */
163 *inp = mq;
164 }
165 }
166
167 /* Return results to caller. */
168 *segp = seg;
169 *hdrp = hdr;
170}
uint64_t uint64
Definition c.h:619
size_t Size
Definition c.h:691
void * dsm_segment_address(dsm_segment *seg)
Definition dsm.c:1095
dsm_segment * dsm_create(Size size, int flags)
Definition dsm.c:516
e
void shm_mq_set_sender(shm_mq *mq, PGPROC *proc)
Definition shm_mq.c:226
shm_mq * shm_mq_create(void *address, Size size)
Definition shm_mq.c:179
void shm_mq_set_receiver(shm_mq *mq, PGPROC *proc)
Definition shm_mq.c:208
const Size shm_mq_minimum_size
Definition shm_mq.c:170
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition shm_toc.c:88
Size shm_toc_estimate(shm_toc_estimator *e)
Definition shm_toc.c:263
shm_toc * shm_toc_create(uint64 magic, void *address, Size nbytes)
Definition shm_toc.c:40
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition shm_toc.c:171
#define shm_toc_estimate_chunk(e, sz)
Definition shm_toc.h:51
#define shm_toc_initialize_estimator(e)
Definition shm_toc.h:49
#define shm_toc_estimate_keys(e, cnt)
Definition shm_toc.h:53
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
PGPROC * MyProc
Definition proc.c:68
#define PG_TEST_SHM_MQ_MAGIC
Definition test_shm_mq.h:22

References dsm_create(), dsm_segment_address(), ereport, errcode(), errmsg, ERROR, fb(), i, test_shm_mq_header::mutex, MyProc, PG_TEST_SHM_MQ_MAGIC, shm_mq_create(), shm_mq_minimum_size, shm_mq_set_receiver(), shm_mq_set_sender(), shm_toc_allocate(), shm_toc_create(), shm_toc_estimate(), shm_toc_estimate_chunk, shm_toc_estimate_keys, shm_toc_initialize_estimator, shm_toc_insert(), SpinLockInit(), test_shm_mq_header::workers_attached, test_shm_mq_header::workers_ready, and test_shm_mq_header::workers_total.

Referenced by test_shm_mq_setup().

◆ test_shm_mq_setup()

void test_shm_mq_setup ( int64  queue_size,
int32  nworkers,
dsm_segment **  segp,
shm_mq_handle **  output,
shm_mq_handle **  input 
)

Definition at line 52 of file setup.c.

54{
55 dsm_segment *seg;
57 shm_mq *outq = NULL; /* placate compiler */
58 shm_mq *inq = NULL; /* placate compiler */
60
61 /* Set up a dynamic shared memory segment. */
62 setup_dynamic_shared_memory(queue_size, nworkers, &seg, &hdr, &outq, &inq);
63 *segp = seg;
64
65 /* Register background workers. */
66 wstate = setup_background_workers(nworkers, seg);
67
68 /* Attach the queues. */
69 *output = shm_mq_attach(outq, seg, wstate->handle[0]);
70 *input = shm_mq_attach(inq, seg, wstate->handle[nworkers - 1]);
71
72 /* Wait for workers to become ready. */
74
75 /*
76 * Once we reach this point, all workers are ready. We no longer need to
77 * kill them if we die; they'll die on their own as the message queues
78 * shut down.
79 */
83}
void cancel_on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
Definition dsm.c:1147
FILE * input
FILE * output
void pfree(void *pointer)
Definition mcxt.c:1616
static worker_state * setup_background_workers(int nworkers, dsm_segment *seg)
Definition setup.c:176
static void wait_for_workers_to_become_ready(worker_state *wstate, volatile test_shm_mq_header *hdr)
Definition setup.c:260
static void setup_dynamic_shared_memory(int64 queue_size, int nworkers, dsm_segment **segp, test_shm_mq_header **hdrp, shm_mq **outp, shm_mq **inp)
Definition setup.c:93
shm_mq_handle * shm_mq_attach(shm_mq *mq, dsm_segment *seg, BackgroundWorkerHandle *handle)
Definition shm_mq.c:292

References cancel_on_dsm_detach(), cleanup_background_workers(), fb(), dsm_segment::handle, input, output, pfree(), PointerGetDatum(), setup_background_workers(), setup_dynamic_shared_memory(), shm_mq_attach(), and wait_for_workers_to_become_ready().

Referenced by test_shm_mq(), and test_shm_mq_pipelined().

◆ wait_for_workers_to_become_ready()

static void wait_for_workers_to_become_ready ( worker_state wstate,
volatile test_shm_mq_header hdr 
)
static

Definition at line 260 of file setup.c.

262{
263 bool result = false;
264
265 for (;;)
266 {
267 int workers_ready;
268
269 /* If all the workers are ready, we have succeeded. */
270 SpinLockAcquire(&hdr->mutex);
271 workers_ready = hdr->workers_ready;
272 SpinLockRelease(&hdr->mutex);
273 if (workers_ready >= wstate->nworkers)
274 {
275 result = true;
276 break;
277 }
278
279 /* If any workers (or the postmaster) have died, we have failed. */
281 {
282 result = false;
283 break;
284 }
285
286 /* first time, allocate or get the custom wait event */
287 if (we_bgworker_startup == 0)
288 we_bgworker_startup = WaitEventExtensionNew("TestShmMqBgWorkerStartup");
289
290 /* Wait to be signaled. */
293
294 /* Reset the latch so we don't spin. */
296
297 /* An interrupt may have occurred while we were waiting. */
299 }
300
301 if (!result)
304 errmsg("one or more background workers failed to start")));
305}
struct Latch * MyLatch
Definition globals.c:63
void ResetLatch(Latch *latch)
Definition latch.c:374
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition latch.c:172
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
static uint32 we_bgworker_startup
Definition setup.c:45
static bool check_worker_status(worker_state *wstate)
Definition setup.c:308
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
uint32 WaitEventExtensionNew(const char *wait_event_name)
Definition wait_event.c:163
#define WL_EXIT_ON_PM_DEATH
#define WL_LATCH_SET

References CHECK_FOR_INTERRUPTS, check_worker_status(), ereport, errcode(), errmsg, ERROR, fb(), test_shm_mq_header::mutex, MyLatch, ResetLatch(), SpinLockAcquire(), SpinLockRelease(), WaitEventExtensionNew(), WaitLatch(), we_bgworker_startup, WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and test_shm_mq_header::workers_ready.

Referenced by test_shm_mq_setup().

Variable Documentation

◆ we_bgworker_startup

uint32 we_bgworker_startup = 0
static

Definition at line 45 of file setup.c.

Referenced by wait_for_workers_to_become_ready().