aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2015-08-07 09:04:07 -0500
committerRobert Haas <rhaas@postgresql.org>2015-08-07 10:06:22 -0400
commitcaf89b31aa79b472a451a5b13657db0da43decee (patch)
treeca68779b6cf205e426c9929a4c2373565408b88d
parent37163e22bddb30a235c9748f49ad54d5e99db142 (diff)
downloadpostgresql-caf89b31aa79b472a451a5b13657db0da43decee.tar.gz
postgresql-caf89b31aa79b472a451a5b13657db0da43decee.zip
Fix attach-related race condition in shm_mq_send_bytes.
Spotted by Antonin Houska.
-rw-r--r--src/backend/storage/ipc/shm_mq.c38
1 files changed, 21 insertions, 17 deletions
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index e765cea5aaa..0e60dbcddc8 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -777,33 +777,37 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
return SHM_MQ_DETACHED;
}
- if (available == 0)
+ if (available == 0 && !mqh->mqh_counterparty_attached)
{
- shm_mq_result res;
-
/*
* The queue is full, so if the receiver isn't yet known to be
* attached, we must wait for that to happen.
*/
- if (!mqh->mqh_counterparty_attached)
+ if (nowait)
{
- if (nowait)
+ if (shm_mq_get_receiver(mq) == NULL)
{
- if (shm_mq_get_receiver(mq) == NULL)
- {
- *bytes_written = sent;
- return SHM_MQ_WOULD_BLOCK;
- }
- }
- else if (!shm_mq_wait_internal(mq, &mq->mq_receiver,
- mqh->mqh_handle))
- {
- mq->mq_detached = true;
*bytes_written = sent;
- return SHM_MQ_DETACHED;
+ return SHM_MQ_WOULD_BLOCK;
}
- mqh->mqh_counterparty_attached = true;
}
+ else if (!shm_mq_wait_internal(mq, &mq->mq_receiver,
+ mqh->mqh_handle))
+ {
+ mq->mq_detached = true;
+ *bytes_written = sent;
+ return SHM_MQ_DETACHED;
+ }
+ mqh->mqh_counterparty_attached = true;
+
+ /*
+ * The receiver may have read some data after attaching, so we
+ * must not wait without rechecking the queue state.
+ */
+ }
+ else if (available == 0)
+ {
+ shm_mq_result res;
/* Let the receiver know that we need them to read some data. */
res = shm_mq_notify_receiver(mq);