summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Haas2016-06-06 18:35:30 +0000
committerRobert Haas2016-06-06 18:35:30 +0000
commit44339b892a04e94bbb472235882dc6f7023bdc65 (patch)
tree03c4772cef5d4d4f65662b992be14faf99975c94 /src
parente191a6900520a28ece9393eec2fdd69f292f12c4 (diff)
shm_mq: After a send fails with SHM_MQ_DETACHED, later ones should too.
Prior to this patch, it was occasionally possible, after shm_mq_sendv had previously returned SHM_MQ_DETACHED, for a later shm_mq_sendv operation to fail an assertion instead of just again returning SHM_MQ_ATTACHED. From the shm_mq code's point of view, it was expecting to be called again with the same arguments, since the previous operation had only partially completed. However, a caller who isn't using non-blocking mode won't be prepared to repeat the call with the same arguments, and this code shouldn't expect that they will. Repair in such a way that we'll be OK whether the next call uses the same arguments or not. Found by Andreas Seltenreich. Analysis and sketch of fix by Amit Kapila. Patch by me, reviewed by Amit Kapila.
Diffstat (limited to 'src')
-rw-r--r--src/backend/storage/ipc/shm_mq.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index 7d1c9cdbd5a..03ca79b5e36 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -366,9 +366,15 @@ shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, int iovcnt, bool nowait)
res = shm_mq_send_bytes(mqh, sizeof(Size) - mqh->mqh_partial_bytes,
((char *) &nbytes) +mqh->mqh_partial_bytes,
nowait, &bytes_written);
- mqh->mqh_partial_bytes += bytes_written;
- if (res != SHM_MQ_SUCCESS)
+
+ if (res == SHM_MQ_DETACHED)
+ {
+ /* Reset state in case caller tries to send another message. */
+ mqh->mqh_partial_bytes = 0;
+ mqh->mqh_length_word_complete = false;
return res;
+ }
+ mqh->mqh_partial_bytes += bytes_written;
if (mqh->mqh_partial_bytes >= sizeof(Size))
{
@@ -378,6 +384,9 @@ shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, int iovcnt, bool nowait)
mqh->mqh_length_word_complete = true;
}
+ if (res != SHM_MQ_SUCCESS)
+ return res;
+
/* Length word can't be split unless bigger than required alignment. */
Assert(mqh->mqh_length_word_complete || sizeof(Size) > MAXIMUM_ALIGNOF);
}
@@ -432,7 +441,17 @@ shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, int iovcnt, bool nowait)
break;
}
}
+
res = shm_mq_send_bytes(mqh, j, tmpbuf, nowait, &bytes_written);
+
+ if (res == SHM_MQ_DETACHED)
+ {
+ /* Reset state in case caller tries to send another message. */
+ mqh->mqh_partial_bytes = 0;
+ mqh->mqh_length_word_complete = false;
+ return res;
+ }
+
mqh->mqh_partial_bytes += bytes_written;
if (res != SHM_MQ_SUCCESS)
return res;
@@ -449,6 +468,15 @@ shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, int iovcnt, bool nowait)
chunksize = MAXALIGN_DOWN(chunksize);
res = shm_mq_send_bytes(mqh, chunksize, &iov[which_iov].data[offset],
nowait, &bytes_written);
+
+ if (res == SHM_MQ_DETACHED)
+ {
+ /* Reset state in case caller tries to send another message. */
+ mqh->mqh_length_word_complete = false;
+ mqh->mqh_partial_bytes = 0;
+ return res;
+ }
+
mqh->mqh_partial_bytes += bytes_written;
offset += bytes_written;
if (res != SHM_MQ_SUCCESS)