]> Chaos Git - corbenik/ctrulib.git/commitdiff
Revise algorithm used by LightLock_Lock/Unlock to fix potential issues
authorfincs <fincs.alt1@gmail.com>
Sat, 21 Nov 2015 17:57:16 +0000 (18:57 +0100)
committerfincs <fincs.alt1@gmail.com>
Sat, 21 Nov 2015 17:57:16 +0000 (18:57 +0100)
libctru/source/synchronization.c

index d2a550c2d3b616967229f2d8acc55548ce2c2360..0dca7247a1f0478431a7f1780c1c748f6bef6ca2 100644 (file)
@@ -32,9 +32,26 @@ _begin:
                val = __ldrex(lock);
                if (val < 0)
                {
-                       __clrex();
-                       svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN, 0, 0);
-                       goto _begin; // Try locking again
+                       // Add ourselves to the list of threads blocked on this lock
+                       if (__strex(lock, val-1))
+                               goto _begin; // strex failed, try to lock again
+
+               _wait:
+                       // Wait for a thread to wake us up
+                       svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
+
+                       // Try to lock again
+                       do
+                       {
+                               val = __ldrex(lock);
+                               if (val < 0)
+                               {
+                                       // Lock is still locked - keep waiting
+                                       __clrex();
+                                       goto _wait;
+                               }
+                       } while (__strex(lock, -(val-1)));
+                       return;
                }
        } while (__strex(lock, -val));
 }
@@ -60,14 +77,10 @@ void LightLock_Unlock(LightLock* lock)
        do
                val = -__ldrex(lock);
        while (__strex(lock, val));
+
        if (val > 1)
-       {
                // Wake up exactly one thread
-               do
-                       val = __ldrex(lock);
-               while (__strex(lock, val >= 0 ? (val-1) : (val+1)));
                svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0);
-       }
 }
 
 void RecursiveLock_Init(RecursiveLock* lock)