mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
138 lines
3.5 KiB
C
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);
|
|
}
|