Fix attach-related race condition in shm_mq_send_bytes.
authorRobert Haas <rhaas@postgresql.org>
Fri, 7 Aug 2015 14:04:07 +0000 (09:04 -0500)
committerRobert Haas <rhaas@postgresql.org>
Fri, 7 Aug 2015 14:04:07 +0000 (10:04 -0400)
Spotted by Antonin Houska.

src/backend/storage/ipc/shm_mq.c

index e765cea5aaa4e090d37b47b71a1df59c98cc979b..0e60dbcddc82ec14612980372af4a790b1450a73 100644 (file)
@@ -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);