libnx/nx/include/switch/kernel/wait.h
2018-12-17 16:06:23 +01:00

138 lines
3.5 KiB
C

// 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);
}
Result waitN(s32* idx_out, Waiter* objects, size_t num_objects, u64 timeout);
Result waitNHandle(s32* idx_out, Handle* handles, size_t num_handles, u64 timeout);
/**
* @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), (Waiter[]) { __VA_ARGS__ }, sizeof((Waiter[]) { __VA_ARGS__ }) / sizeof(Waiter), (timeout))
/**
* @brief Waits for an arbitrary number of handles. This is a macro that uses var-args.
* @param[out] idx_out The index of the signalled handle.
* @param[in] timeout Timeout (in nanoseconds).
* @note The number of handles must be less than 64. This is a Horizon kernel limitation.
*/
#define waitMultiHandle(idx_out, timeout, ...) \
waitNHandle((idx_out), (Handle[]) { __VA_ARGS__ }, sizeof((Handle[]) { __VA_ARGS__ }) / sizeof(Handle), (timeout))
/**
* @brief Waits for a single waiter.
* @param[in] w The waiter to wait for.
* @param[in] timeout Timeout (in nanoseconds).
*/
static inline Result waitSingle(Waiter w, u64 timeout) {
s32 idx;
return waitMulti(&idx, timeout, w);
}
/**
* @brief Waits for a single handle.
* @param[in] h The handle to wait for.
* @param[in] timeout Timeout (in nanoseconds).
*/
static inline Result waitSingleHandle(Handle h, u64 timeout) {
s32 idx;
return waitMultiHandle(&idx, timeout, h);
}