/// 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)
{
* @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);
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);
+ }
+}