// Copyright 2018 plutoo #pragma once #include "../kernel/mutex.h" #include "../kernel/event.h" #include "../kernel/thread.h" // Implementation details. typedef struct UsermodeEvent UsermodeEvent; typedef struct UsermodeTimer UsermodeTimer; typedef enum { WaiterNodeType_Event, WaiterNodeType_Timer } WaiterNodeType; typedef struct Waitable Waitable; typedef struct WaitableNode WaitableNode; struct WaitableNode { WaitableNode* prev; WaitableNode* next; }; typedef struct { WaitableNode node; WaiterNodeType type; Handle thread; union { Waitable* parent; UsermodeEvent* parent_event; UsermodeTimer* parent_timer; }; size_t idx; size_t* idx_out; } WaiterNode; struct Waitable { WaitableNode list; Mutex mutex; }; // User-facing API starts here. typedef enum { WaiterType_Handle, WaiterType_UsermodeTimer, WaiterType_UsermodeEvent, } WaiterType; typedef struct { WaiterType type; union { Handle handle; UsermodeTimer* timer; UsermodeEvent* event; }; } Waiter; /// Creates a waiter for a kernelmode handle. static inline Waiter waiterForHandle(Handle h) { Waiter wait_obj; wait_obj.type = WaiterType_Handle; wait_obj.handle = h; return wait_obj; } /// Creates a waiter for a usermode timer. static inline Waiter waiterForUtimer(UsermodeTimer* t) { Waiter wait_obj; wait_obj.type = WaiterType_UsermodeTimer; wait_obj.timer = t; return wait_obj; } /// Creates a waiter for a usermode event. static inline Waiter waiterForUevent(UsermodeEvent* e) { Waiter wait_obj; wait_obj.type = WaiterType_UsermodeEvent; wait_obj.event = e; return wait_obj; } /// Creates a waiter for a kernelmode event. static inline Waiter waiterForEvent(Event* e) { return waiterForHandle(e->revent); } /// Creates a waiter for a thread exit. static inline Waiter waiterForThreadExit(Thread* t) { return waiterForHandle(t->handle); } /** * @brief Waits for an arbitrary number of waiters. This is a macro that uses var-args. * @param[out] idx_out The index of the signalled waiter. * @param[in] timeout Timeout (in nanoseconds). * @note The number of waiters must be less than 64. This is a Horizon kernel limitation. */ #define waitMulti(idx_out, timeout, ...) \ waitN((idx_out), (timeout), (Waiter[]) { __VA_ARGS__ }, sizeof((Waiter[]) { __VA_ARGS__ }) / sizeof(Waiter)) Result waitN(s32* idx_out, u64 timeout, Waiter* objects, size_t num_objects);