diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c index 0639689..1acda3c 100644 --- a/src/backend/storage/lmgr/condition_variable.c +++ b/src/backend/storage/lmgr/condition_variable.c @@ -61,7 +61,8 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv) /* Add myself to the wait queue. */ SpinLockAcquire(&cv->mutex); - proclist_push_head(&cv->wakeup, pgprocno, cvWaitLink); + if (!proclist_contains(&cv->wakeup, pgprocno, cvWaitLink)) + proclist_push_head(&cv->wakeup, pgprocno, cvWaitLink); SpinLockRelease(&cv->mutex); } @@ -100,7 +101,8 @@ ConditionVariableCancelSleep(void) return; SpinLockAcquire(&cv->mutex); - proclist_delete(&cv->wakeup, MyProc->pgprocno, cvWaitLink); + if (proclist_contains(&cv->wakeup, MyProc->pgprocno, cvWaitLink)) + proclist_delete(&cv->wakeup, MyProc->pgprocno, cvWaitLink); SpinLockRelease(&cv->mutex); MyProc->cvSleeping = false; @@ -126,6 +128,7 @@ ConditionVariableSignal(ConditionVariable *cv) /* If we found someone sleeping, set their latch to wake them up. */ if (proc != NULL) { + proc->cvSleeping = false; SetLatch(&proc->procLatch); return true; } diff --git a/src/include/storage/proclist.h b/src/include/storage/proclist.h index 0d7935c..b14e8f8 100644 --- a/src/include/storage/proclist.h +++ b/src/include/storage/proclist.h @@ -69,6 +69,8 @@ proclist_push_head_offset(proclist_head *list, int procno, size_t node_offset) else { Assert(list->tail != INVALID_PGPROCNO); + Assert(list->head != procno); + Assert(list->tail != procno); node->next = list->head; proclist_node_get(node->next, node_offset)->prev = procno; node->prev = INVALID_PGPROCNO; @@ -77,7 +79,7 @@ proclist_push_head_offset(proclist_head *list, int procno, size_t node_offset) } /* - * Insert a node a the end of a list. + * Insert a node at the end of a list. */ static inline void proclist_push_tail_offset(proclist_head *list, int procno, size_t node_offset) @@ -93,6 +95,8 @@ proclist_push_tail_offset(proclist_head *list, int procno, size_t node_offset) else { Assert(list->head != INVALID_PGPROCNO); + Assert(list->head != procno); + Assert(list->tail != procno); node->prev = list->tail; proclist_node_get(node->prev, node_offset)->next = procno; node->next = INVALID_PGPROCNO; @@ -117,6 +121,38 @@ proclist_delete_offset(proclist_head *list, int procno, size_t node_offset) list->tail = node->prev; else proclist_node_get(node->next, node_offset)->prev = node->prev; + + node->next = node->prev = INVALID_PGPROCNO; +} + +/* + * Check if a node is currently in a list. It must be known that the node is + * not in any _other_ proclist that uses the same proclist_node, so that the + * only possibilities are that it is in this list or none. + */ +static inline bool +proclist_contains_offset(proclist_head *list, int procno, + size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + /* + * If this node has never been a member of a cv list, then it will contain + * zero before and after us in the list. Circular lists are not allowed + * so this condition is not confusable with a real pgprocno 0. + */ + if (node->prev == 0 && node->next == 0) + return false; + + /* If there is a previous node, then this node must be in the list. */ + if (node->prev != INVALID_PGPROCNO) + return true; + + /* + * There is no previous node, so the only way this node can be in the list + * is if it's the head node. + */ + return list->head == procno; } /* @@ -145,6 +181,8 @@ proclist_pop_head_node_offset(proclist_head *list, size_t node_offset) proclist_push_tail_offset((list), (procno), offsetof(PGPROC, link_member)) #define proclist_pop_head_node(list, link_member) \ proclist_pop_head_node_offset((list), offsetof(PGPROC, link_member)) +#define proclist_contains(list, procno, link_member) \ + proclist_contains_offset((list), (procno), offsetof(PGPROC, link_member)) /* * Iterate through the list pointed at by 'lhead', storing the current