/* * Write a message into a shared message queue. */ shm_mq_result shm_mq_send(shm_mq_handle *mqh, Size nbytes, const void *data, bool nowait) { shm_mq_iovec iov; iov.data = data; iov.len = nbytes; return shm_mq_sendv(mqh, &iov, 1, nowait); }
/* * Transmit a libpq protocol message to the shared memory message queue * selected via pq_mq_handle. We don't include a length word, because the * receiver will know the length of the message from shm_mq_receive(). */ static int mq_putmessage(char msgtype, const char *s, size_t len) { shm_mq_iovec iov[2]; shm_mq_result result; /* * If we're sending a message, and we have to wait because the queue is * full, and then we get interrupted, and that interrupt results in trying * to send another message, we respond by detaching the queue. There's no * way to return to the original context, but even if there were, just * queueing the message would amount to indefinitely postponing the * response to the interrupt. So we do this instead. */ if (pq_mq_busy) { if (pq_mq != NULL) shm_mq_detach(pq_mq); pq_mq = NULL; pq_mq_handle = NULL; return EOF; } /* * If the message queue is already gone, just ignore the message. This * doesn't necessarily indicate a problem; for example, DEBUG messages * can be generated late in the shutdown sequence, after all DSMs have * already been detached. */ if (pq_mq == NULL) return 0; pq_mq_busy = true; iov[0].data = &msgtype; iov[0].len = 1; iov[1].data = s; iov[1].len = len; Assert(pq_mq_handle != NULL); for (;;) { result = shm_mq_sendv(pq_mq_handle, iov, 2, true); if (pq_mq_parallel_master_pid != 0) SendProcSignal(pq_mq_parallel_master_pid, PROCSIG_PARALLEL_MESSAGE, pq_mq_parallel_master_backend_id); if (result != SHM_MQ_WOULD_BLOCK) break; WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); CHECK_FOR_INTERRUPTS(); ResetLatch(&MyProc->procLatch); } pq_mq_busy = false; Assert(result == SHM_MQ_SUCCESS || result == SHM_MQ_DETACHED); if (result != SHM_MQ_SUCCESS) return EOF; return 0; }