]> Chaos Git - corbenik/ctrulib.git/commitdiff
Add light events
authorfincs <fincs.alt1@gmail.com>
Fri, 1 Jul 2016 16:28:00 +0000 (18:28 +0200)
committerfincs <fincs.alt1@gmail.com>
Fri, 1 Jul 2016 16:28:00 +0000 (18:28 +0200)
libctru/include/3ds/synchronization.h
libctru/source/synchronization.c

index 030774525ef1f9ebed44a68f5b549bea47cbee0d..f23594b83fbeec703438af891d7826e90a37494d 100644 (file)
@@ -11,6 +11,13 @@ typedef _LOCK_T LightLock;
 /// A recursive lock.
 typedef _LOCK_RECURSIVE_T RecursiveLock;
 
+/// A light event.
+typedef struct
+{
+       s32 state;      ///< State of the event: -2=cleared sticky, -1=cleared oneshot, 0=signaled oneshot, 1=signaled sticky
+       LightLock lock; ///< Lock used for sticky timer operation
+} LightEvent;
+
 /// Performs a Data Synchronization Barrier operation.
 static inline void __dsb(void)
 {
@@ -114,3 +121,41 @@ int RecursiveLock_TryLock(RecursiveLock* lock);
  * @param lock Pointer to the lock.
  */
 void RecursiveLock_Unlock(RecursiveLock* lock);
+
+/**
+ * @brief Initializes a light event.
+ * @param event Pointer to the event.
+ * @param reset_type Type of reset the event uses (RESET_ONESHOT/RESET_STICKY).
+ */
+void LightEvent_Init(LightEvent* event, ResetType reset_type);
+
+/**
+ * @brief Clears a light event.
+ * @param event Pointer to the event.
+ */
+void LightEvent_Clear(LightEvent* event);
+
+/**
+ * @brief Wakes up threads waiting on a sticky light event without signaling it. If the event had been signaled before, it is cleared instead.
+ * @param event Pointer to the event.
+ */
+void LightEvent_Pulse(LightEvent* event);
+
+/**
+ * @brief Signals a light event, waking up threads waiting on it.
+ * @param event Pointer to the event.
+ */
+void LightEvent_Signal(LightEvent* event);
+
+/**
+ * @brief Attempts to wait on a light event.
+ * @param event Pointer to the event.
+ * @return Non-zero if the event was signaled, zero otherwise.
+ */
+int LightEvent_TryWait(LightEvent* event);
+
+/**
+ * @brief Waits on a light event.
+ * @param event Pointer to the event.
+ */
+void LightEvent_Wait(LightEvent* event);
index ecbae16249951cd30d259fd2e6354262dcd8a86b..15bc35c83d2369f949e2dedec5848a3ec2df66ac 100644 (file)
@@ -127,3 +127,92 @@ void RecursiveLock_Unlock(RecursiveLock* lock)
                LightLock_Unlock(&lock->lock);
        }
 }
+
+static inline void LightEvent_SetState(LightEvent* event, int state)
+{
+       do
+               __ldrex(&event->state);
+       while (__strex(&event->state, state));
+}
+
+static inline int LightEvent_TryReset(LightEvent* event)
+{
+       do
+       {
+               if (__ldrex(&event->state))
+               {
+                       __clrex();
+                       return 0;
+               }
+       } while (__strex(&event->state, -1));
+       return 1;
+}
+
+void LightEvent_Init(LightEvent* event, ResetType reset_type)
+{
+       LightLock_Init(&event->lock);
+       LightEvent_SetState(event, reset_type == RESET_STICKY ? -2 : -1);
+}
+
+void LightEvent_Clear(LightEvent* event)
+{
+       if (event->state == 1)
+       {
+               LightLock_Lock(&event->lock);
+               LightEvent_SetState(event, -2);
+               LightLock_Unlock(&event->lock);
+       } else if (event->state == 0)
+               LightEvent_SetState(event, -1);
+}
+
+void LightEvent_Pulse(LightEvent* event)
+{
+       if (event->state == -2)
+               svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
+       else if (event->state == -1)
+               svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
+       else
+               LightEvent_Clear(event);
+}
+
+void LightEvent_Signal(LightEvent* event)
+{
+       if (event->state == -1)
+       {
+               LightEvent_SetState(event, 0);
+               svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
+       } else if (event->state == -2)
+       {
+               LightLock_Lock(&event->lock);
+               LightEvent_SetState(event, 1);
+               svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
+               LightLock_Unlock(&event->lock);
+       }
+}
+
+int LightEvent_TryWait(LightEvent* event)
+{
+       if (event->state == 1)
+               return 1;
+       return LightEvent_TryReset(event);
+}
+
+void LightEvent_Wait(LightEvent* event)
+{
+       for (;;)
+       {
+               if (event->state == -2)
+               {
+                       svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
+                       return;
+               }
+               if (event->state != -1)
+               {
+                       if (event->state == 1)
+                               return;
+                       if (event->state == 0 && LightEvent_TryReset(event))
+                               return;
+               }
+               svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
+       }
+}