/* * Attach to shared memory message queues. * * We use our worker number to determine to which queue we should attach. * The queues are registered at keys 1..<number-of-workers>. The user backend * writes to queue #1 and reads from queue #<number-of-workers>; each worker * reads from the queue whose number is equal to its worker number and writes * to the next higher-numbered queue. */ static void attach_to_queues(dsm_segment *seg, shm_toc *toc, int myworkernumber, shm_mq_handle **inqhp, shm_mq_handle **outqhp) { shm_mq *inq; shm_mq *outq; inq = shm_toc_lookup(toc, myworkernumber); shm_mq_set_receiver(inq, MyProc); *inqhp = shm_mq_attach(inq, seg, NULL); outq = shm_toc_lookup(toc, myworkernumber + 1); shm_mq_set_sender(outq, MyProc); *outqhp = shm_mq_attach(outq, seg, NULL); }
/* * Set up a dynamic shared memory segment. * * We set up a small control region that contains only a test_shm_mq_header, * plus one region per message queue. There are as many message queues as * the number of workers, plus one. */ 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) { shm_toc_estimator e; int i; Size segsize; dsm_segment *seg; shm_toc *toc; test_shm_mq_header *hdr; /* Ensure a valid queue size. */ if (queue_size < 0 || ((uint64) queue_size) < shm_mq_minimum_size) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("queue size must be at least %zu bytes", shm_mq_minimum_size))); if (queue_size != ((Size) queue_size)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("queue size overflows size_t"))); /* * Estimate how much shared memory we need. * * Because the TOC machinery may choose to insert padding of oddly-sized * requests, we must estimate each chunk separately. * * We need one key to register the location of the header, and we need * nworkers + 1 keys to track the locations of the message queues. */ shm_toc_initialize_estimator(&e); shm_toc_estimate_chunk(&e, sizeof(test_shm_mq_header)); for (i = 0; i <= nworkers; ++i) shm_toc_estimate_chunk(&e, (Size) queue_size); shm_toc_estimate_keys(&e, 2 + nworkers); segsize = shm_toc_estimate(&e); /* Create the shared memory segment and establish a table of contents. */ seg = dsm_create(shm_toc_estimate(&e), 0); toc = shm_toc_create(PG_TEST_SHM_MQ_MAGIC, dsm_segment_address(seg), segsize); /* Set up the header region. */ hdr = shm_toc_allocate(toc, sizeof(test_shm_mq_header)); SpinLockInit(&hdr->mutex); hdr->workers_total = nworkers; hdr->workers_attached = 0; hdr->workers_ready = 0; shm_toc_insert(toc, 0, hdr); /* Set up one message queue per worker, plus one. */ for (i = 0; i <= nworkers; ++i) { shm_mq *mq; mq = shm_mq_create(shm_toc_allocate(toc, (Size) queue_size), (Size) queue_size); shm_toc_insert(toc, i + 1, mq); if (i == 0) { /* We send messages to the first queue. */ shm_mq_set_sender(mq, MyProc); *outp = mq; } if (i == nworkers) { /* We receive messages from the last queue. */ shm_mq_set_receiver(mq, MyProc); *inp = mq; } } /* Return results to caller. */ *segp = seg; *hdrp = hdr; }