@@ -349,12 +349,12 @@ static volatile sig_atomic_t notifyInterruptOccurred = 0;
349349/* True if we've registered an on_shmem_exit cleanup */
350350static bool unlistenExitRegistered = false;
351351
352+ /* True if we're currently registered as a listener in asyncQueueControl */
353+ static bool amRegisteredListener = false;
354+
352355/* has this backend sent notifications in the current transaction? */
353356static bool backendHasSentNotifications = false;
354357
355- /* has this backend executed its first LISTEN in the current transaction? */
356- static bool backendHasExecutedInitialListen = false;
357-
358358/* GUC parameter */
359359bool Trace_notify = false;
360360
@@ -745,6 +745,7 @@ static void
745745Async_UnlistenOnExit (int code ,Datum arg )
746746{
747747Exec_UnlistenAllCommit ();
748+ asyncQueueUnregister ();
748749}
749750
750751/*
@@ -789,8 +790,6 @@ PreCommit_Notify(void)
789790if (Trace_notify )
790791elog (DEBUG1 ,"PreCommit_Notify" );
791792
792- Assert (backendHasExecutedInitialListen == false);
793-
794793/* Preflight for any pending listen/unlisten actions */
795794foreach (p ,pendingActions )
796795{
@@ -913,11 +912,9 @@ AtCommit_Notify(void)
913912}
914913}
915914
916- /*
917- * If we did an initial LISTEN, listenChannels now has the entry, so we no
918- * longer need or want the flag to be set.
919- */
920- backendHasExecutedInitialListen = false;
915+ /* If no longer listening to anything, get out of listener array */
916+ if (amRegisteredListener && listenChannels == NIL )
917+ asyncQueueUnregister ();
921918
922919/* And clean up */
923920ClearPendingActionsAndNotifies ();
@@ -935,19 +932,12 @@ Exec_ListenPreCommit(void)
935932 * Nothing to do if we are already listening to something, nor if we
936933 * already ran this routine in this transaction.
937934 */
938- if (listenChannels != NIL || backendHasExecutedInitialListen )
935+ if (amRegisteredListener )
939936return ;
940937
941938if (Trace_notify )
942939elog (DEBUG1 ,"Exec_ListenPreCommit(%d)" ,MyProcPid );
943940
944- /*
945- * We need this variable to detect an aborted initial LISTEN. In that case
946- * we would set up our pointer but not listen on any channel. This flag
947- * gets cleared in AtCommit_Notify or AtAbort_Notify().
948- */
949- backendHasExecutedInitialListen = true;
950-
951941/*
952942 * Before registering, make sure we will unlisten before dying. (Note:
953943 * this action does not get undone if we abort later.)
@@ -971,6 +961,9 @@ Exec_ListenPreCommit(void)
971961QUEUE_BACKEND_PID (MyBackendId )= MyProcPid ;
972962LWLockRelease (AsyncQueueLock );
973963
964+ /* Now we are listed in the global array, so remember we're listening */
965+ amRegisteredListener = true;
966+
974967/*
975968 * Try to move our pointer forward as far as possible. This will skip over
976969 * already-committed notifications. Still, we could get notifications that
@@ -1043,10 +1036,6 @@ Exec_UnlistenCommit(const char *channel)
10431036 * We do not complain about unlistening something not being listened;
10441037 * should we?
10451038 */
1046-
1047- /* If no longer listening to anything, get out of listener array */
1048- if (listenChannels == NIL )
1049- asyncQueueUnregister ();
10501039}
10511040
10521041/*
@@ -1062,8 +1051,6 @@ Exec_UnlistenAllCommit(void)
10621051
10631052list_free_deep (listenChannels );
10641053listenChannels = NIL ;
1065-
1066- asyncQueueUnregister ();
10671054}
10681055
10691056/*
@@ -1181,6 +1168,9 @@ asyncQueueUnregister(void)
11811168
11821169Assert (listenChannels == NIL );/* else caller error */
11831170
1171+ if (!amRegisteredListener )/* nothing to do */
1172+ return ;
1173+
11841174LWLockAcquire (AsyncQueueLock ,LW_SHARED );
11851175/* check if entry is valid and oldest ... */
11861176advanceTail = (MyProcPid == QUEUE_BACKEND_PID (MyBackendId ))&&
@@ -1189,6 +1179,9 @@ asyncQueueUnregister(void)
11891179QUEUE_BACKEND_PID (MyBackendId )= InvalidPid ;
11901180LWLockRelease (AsyncQueueLock );
11911181
1182+ /* mark ourselves as no longer listed in the global array */
1183+ amRegisteredListener = false;
1184+
11921185/* If we were the laziest backend, try to advance the tail pointer */
11931186if (advanceTail )
11941187asyncQueueAdvanceTail ();
@@ -1545,21 +1538,12 @@ void
15451538AtAbort_Notify (void )
15461539{
15471540/*
1548- * If we LISTEN but then roll back the transactionwe have set our pointer
1549- *but havenot made any entry in listenChannels. In that case, remove our
1550- *pointer again.
1541+ * If we LISTEN but then roll back the transactionafter PreCommit_Notify,
1542+ *we haveregistered as a listener but have not made any entry in
1543+ *listenChannels. In that case, deregister again.
15511544 */
1552- if (backendHasExecutedInitialListen )
1553- {
1554- /*
1555- * Checking listenChannels should be redundant but it can't hurt doing
1556- * it for safety reasons.
1557- */
1558- if (listenChannels == NIL )
1559- asyncQueueUnregister ();
1560-
1561- backendHasExecutedInitialListen = false;
1562- }
1545+ if (amRegisteredListener && listenChannels == NIL )
1546+ asyncQueueUnregister ();
15631547
15641548/* And clean up */
15651549ClearPendingActionsAndNotifies ();