@@ -117,9 +117,9 @@ inline static void
117117PRINT_LWDEBUG (const char * where , const LWLock * lock )
118118{
119119 if (Trace_lwlocks )
120- elog (LOG , "%s(%s %d): excl %d shared %d head %p rOK %d" ,
120+ elog (LOG , "%s(%s %d): excl %d shared %d rOK %d" ,
121121 where , T_NAME (lock ), T_ID (lock ),
122- (int ) lock -> exclusive , lock -> shared , lock -> head ,
122+ (int ) lock -> exclusive , lock -> shared ,
123123 (int ) lock -> releaseOK );
124124}
125125
@@ -479,8 +479,7 @@ LWLockInitialize(LWLock *lock, int tranche_id)
479479 lock -> exclusive = 0 ;
480480 lock -> shared = 0 ;
481481 lock -> tranche = tranche_id ;
482- lock -> head = NULL ;
483- lock -> tail = NULL ;
482+ dlist_init (& lock -> waiters );
484483}
485484
486485
@@ -619,12 +618,7 @@ LWLockAcquireCommon(LWLock *lock, LWLockMode mode, uint64 *valptr, uint64 val)
619618
620619 proc -> lwWaiting = true;
621620 proc -> lwWaitMode = mode ;
622- proc -> lwWaitLink = NULL ;
623- if (lock -> head == NULL )
624- lock -> head = proc ;
625- else
626- lock -> tail -> lwWaitLink = proc ;
627- lock -> tail = proc ;
621+ dlist_push_head (& lock -> waiters , & proc -> lwWaitLink );
628622
629623 /* Can release the mutex now */
630624 SpinLockRelease (& lock -> mutex );
@@ -840,12 +834,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
840834
841835 proc -> lwWaiting = true;
842836 proc -> lwWaitMode = LW_WAIT_UNTIL_FREE ;
843- proc -> lwWaitLink = NULL ;
844- if (lock -> head == NULL )
845- lock -> head = proc ;
846- else
847- lock -> tail -> lwWaitLink = proc ;
848- lock -> tail = proc ;
837+ dlist_push_head (& lock -> waiters , & proc -> lwWaitLink );
849838
850839 /* Can release the mutex now */
851840 SpinLockRelease (& lock -> mutex );
@@ -1002,10 +991,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
1002991 proc -> lwWaiting = true;
1003992 proc -> lwWaitMode = LW_WAIT_UNTIL_FREE ;
1004993 /* waiters are added to the front of the queue */
1005- proc -> lwWaitLink = lock -> head ;
1006- if (lock -> head == NULL )
1007- lock -> tail = proc ;
1008- lock -> head = proc ;
994+ dlist_push_head (& lock -> waiters , & proc -> lwWaitLink );
1009995
1010996 /*
1011997 * Set releaseOK, to make sure we get woken up as soon as the lock is
@@ -1087,9 +1073,10 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
10871073void
10881074LWLockUpdateVar (LWLock * lock , uint64 * valptr , uint64 val )
10891075{
1090- PGPROC * head ;
1091- PGPROC * proc ;
1092- PGPROC * next ;
1076+ dlist_head wakeup ;
1077+ dlist_mutable_iter iter ;
1078+
1079+ dlist_init (& wakeup );
10931080
10941081 /* Acquire mutex. Time spent holding mutex should be short! */
10951082 SpinLockAcquire (& lock -> mutex );
@@ -1104,40 +1091,31 @@ LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val)
11041091 * See if there are any LW_WAIT_UNTIL_FREE waiters that need to be woken
11051092 * up. They are always in the front of the queue.
11061093 */
1107- head = lock -> head ;
1108-
1109- if (head != NULL && head -> lwWaitMode == LW_WAIT_UNTIL_FREE )
1094+ dlist_foreach_modify (iter , & lock -> waiters )
11101095 {
1111- proc = head ;
1112- next = proc -> lwWaitLink ;
1113- while (next && next -> lwWaitMode == LW_WAIT_UNTIL_FREE )
1114- {
1115- proc = next ;
1116- next = next -> lwWaitLink ;
1117- }
1096+ PGPROC * waiter = dlist_container (PGPROC , lwWaitLink , iter .cur );
1097+
1098+ if (waiter -> lwWaitMode != LW_WAIT_UNTIL_FREE )
1099+ break ;
11181100
1119- /* proc is now the last PGPROC to be released */
1120- lock -> head = next ;
1121- proc -> lwWaitLink = NULL ;
1101+ dlist_delete (& waiter -> lwWaitLink );
1102+ dlist_push_tail (& wakeup , & waiter -> lwWaitLink );
11221103 }
1123- else
1124- head = NULL ;
11251104
11261105 /* We are done updating shared state of the lock itself. */
11271106 SpinLockRelease (& lock -> mutex );
11281107
11291108 /*
11301109 * Awaken any waiters I removed from the queue.
11311110 */
1132- while ( head != NULL )
1111+ dlist_foreach_modify ( iter , & wakeup )
11331112 {
1134- proc = head ;
1135- head = proc -> lwWaitLink ;
1136- proc -> lwWaitLink = NULL ;
1113+ PGPROC * waiter = dlist_container (PGPROC , lwWaitLink , iter .cur );
1114+ dlist_delete (& waiter -> lwWaitLink );
11371115 /* check comment in LWLockRelease() about this barrier */
11381116 pg_write_barrier ();
1139- proc -> lwWaiting = false;
1140- PGSemaphoreUnlock (& proc -> sem );
1117+ waiter -> lwWaiting = false;
1118+ PGSemaphoreUnlock (& waiter -> sem );
11411119 }
11421120}
11431121
@@ -1148,10 +1126,12 @@ LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val)
11481126void
11491127LWLockRelease (LWLock * lock )
11501128{
1151- PGPROC * head ;
1152- PGPROC * proc ;
1129+ dlist_head wakeup ;
1130+ dlist_mutable_iter iter ;
11531131 int i ;
11541132
1133+ dlist_init (& wakeup );
1134+
11551135 PRINT_LWDEBUG ("LWLockRelease" , lock );
11561136
11571137 /*
@@ -1187,58 +1167,39 @@ LWLockRelease(LWLock *lock)
11871167 * if someone has already awakened waiters that haven't yet acquired the
11881168 * lock.
11891169 */
1190- head = lock -> head ;
1191- if (head != NULL )
1170+ if (lock -> exclusive == 0 && lock -> shared == 0 && lock -> releaseOK )
11921171 {
1193- if (lock -> exclusive == 0 && lock -> shared == 0 && lock -> releaseOK )
1172+ /*
1173+ * Remove the to-be-awakened PGPROCs from the queue.
1174+ */
1175+ bool releaseOK = true;
1176+ bool wokeup_somebody = false;
1177+
1178+ dlist_foreach_modify (iter , & lock -> waiters )
11941179 {
1195- /*
1196- * Remove the to-be-awakened PGPROCs from the queue.
1197- */
1198- bool releaseOK = true;
1180+ PGPROC * waiter = dlist_container (PGPROC , lwWaitLink , iter .cur );
11991181
1200- proc = head ;
1182+ if (wokeup_somebody && waiter -> lwWaitMode == LW_EXCLUSIVE )
1183+ continue ;
12011184
1202- /*
1203- * First wake up any backends that want to be woken up without
1204- * acquiring the lock.
1205- */
1206- while (proc -> lwWaitMode == LW_WAIT_UNTIL_FREE && proc -> lwWaitLink )
1207- proc = proc -> lwWaitLink ;
1185+ dlist_delete (& waiter -> lwWaitLink );
1186+ dlist_push_tail (& wakeup , & waiter -> lwWaitLink );
12081187
12091188 /*
1210- * If the front waiter wants exclusive lock, awaken him only.
1211- * Otherwise awaken as many waiters as want shared access.
1189+ * Prevent additional wakeups until retryer gets to
1190+ * run. Backends that are just waiting for the lock to become
1191+ * free don't retry automatically.
12121192 */
1213- if (proc -> lwWaitMode != LW_EXCLUSIVE )
1193+ if (waiter -> lwWaitMode != LW_WAIT_UNTIL_FREE )
12141194 {
1215- while (proc -> lwWaitLink != NULL &&
1216- proc -> lwWaitLink -> lwWaitMode != LW_EXCLUSIVE )
1217- {
1218- if (proc -> lwWaitMode != LW_WAIT_UNTIL_FREE )
1219- releaseOK = false;
1220- proc = proc -> lwWaitLink ;
1221- }
1222- }
1223- /* proc is now the last PGPROC to be released */
1224- lock -> head = proc -> lwWaitLink ;
1225- proc -> lwWaitLink = NULL ;
1226-
1227- /*
1228- * Prevent additional wakeups until retryer gets to run. Backends
1229- * that are just waiting for the lock to become free don't retry
1230- * automatically.
1231- */
1232- if (proc -> lwWaitMode != LW_WAIT_UNTIL_FREE )
12331195 releaseOK = false;
1196+ wokeup_somebody = true;
1197+ }
12341198
1235- lock -> releaseOK = releaseOK ;
1236- }
1237- else
1238- {
1239- /* lock is still held, can't awaken anything */
1240- head = NULL ;
1199+ if (waiter -> lwWaitMode == LW_EXCLUSIVE )
1200+ break ;
12411201 }
1202+ lock -> releaseOK = releaseOK ;
12421203 }
12431204
12441205 /* We are done updating shared state of the lock itself. */
@@ -1249,13 +1210,12 @@ LWLockRelease(LWLock *lock)
12491210 /*
12501211 * Awaken any waiters I removed from the queue.
12511212 */
1252- while ( head != NULL )
1213+ dlist_foreach_modify ( iter , & wakeup )
12531214 {
1215+ PGPROC * waiter = dlist_container (PGPROC , lwWaitLink , iter .cur );
12541216 LOG_LWDEBUG ("LWLockRelease" , T_NAME (lock ), T_ID (lock ),
12551217 "release waiter" );
1256- proc = head ;
1257- head = proc -> lwWaitLink ;
1258- proc -> lwWaitLink = NULL ;
1218+ dlist_delete (& waiter -> lwWaitLink );
12591219 /*
12601220 * Guarantee that lwWaiting being unset only becomes visible once the
12611221 * unlink from the link has completed. Otherwise the target backend
@@ -1267,8 +1227,8 @@ LWLockRelease(LWLock *lock)
12671227 * another lock.
12681228 */
12691229 pg_write_barrier ();
1270- proc -> lwWaiting = false;
1271- PGSemaphoreUnlock (& proc -> sem );
1230+ waiter -> lwWaiting = false;
1231+ PGSemaphoreUnlock (& waiter -> sem );
12721232 }
12731233
12741234 /*
0 commit comments