mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
Finishing touches to user-mode synchronization primitives
This commit is contained in:
parent
8c786c610e
commit
beeeb057d2
@ -21,10 +21,13 @@ extern "C" {
|
||||
#include "switch/arm/counter.h"
|
||||
|
||||
#include "switch/kernel/svc.h"
|
||||
#include "switch/kernel/wait.h"
|
||||
#include "switch/kernel/tmem.h"
|
||||
#include "switch/kernel/shmem.h"
|
||||
#include "switch/kernel/mutex.h"
|
||||
#include "switch/kernel/event.h"
|
||||
#include "switch/kernel/uevent.h"
|
||||
#include "switch/kernel/utimer.h"
|
||||
#include "switch/kernel/rwlock.h"
|
||||
#include "switch/kernel/condvar.h"
|
||||
#include "switch/kernel/thread.h"
|
||||
@ -35,9 +38,6 @@ extern "C" {
|
||||
#include "switch/kernel/jit.h"
|
||||
#include "switch/kernel/ipc.h"
|
||||
#include "switch/kernel/barrier.h"
|
||||
#include "switch/kernel/uevent.h"
|
||||
#include "switch/kernel/utimer.h"
|
||||
#include "switch/kernel/wait.h"
|
||||
|
||||
#include "switch/services/sm.h"
|
||||
#include "switch/services/smm.h"
|
||||
|
@ -366,7 +366,7 @@ Result svcResetSignal(Handle handle);
|
||||
* @return Result code.
|
||||
* @note Syscall number 0x18.
|
||||
* @note \p handleCount must not be greater than \ref MAX_WAIT_OBJECTS. This is a Horizon kernel limitation.
|
||||
* @note Please use \ref waitMultiHandle instead. That function handles sporadical interrupts caused by usermode synchronization primitives.
|
||||
* @note This is the raw syscall, which can be cancelled by \ref svcCancelSynchronization or other means. \ref waitHandles or \ref waitMultiHandle should normally be used instead.
|
||||
*/
|
||||
Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout);
|
||||
|
||||
@ -374,7 +374,7 @@ Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount
|
||||
* @brief Waits on a single synchronization object, optionally with a timeout.
|
||||
* @return Result code.
|
||||
* @note Wrapper for \ref svcWaitSynchronization.
|
||||
* @note Please use \ref waitSingleHandle instead. That function handles sporadical interrupts caused by usermode synchronization primitives.
|
||||
* @note This is the raw syscall, which can be cancelled by \ref svcCancelSynchronization or other means. \ref waitSingleHandle should normally be used instead.
|
||||
*/
|
||||
static inline Result svcWaitSynchronizationSingle(Handle handle, u64 timeout) {
|
||||
s32 tmp;
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
typedef struct UEvent UEvent;
|
||||
|
||||
/// User-mode event object.
|
||||
struct UEvent {
|
||||
Waitable waitable;
|
||||
bool signal;
|
||||
|
@ -9,11 +9,13 @@
|
||||
|
||||
typedef struct UTimer UTimer;
|
||||
|
||||
/// Valid types for a user-mode timer.
|
||||
typedef enum {
|
||||
TimerType_OneShot,
|
||||
TimerType_Repeating,
|
||||
TimerType_OneShot, ///< Timers of this kind fire once and then stop automatically.
|
||||
TimerType_Repeating, ///< Timers of this kind fire periodically.
|
||||
} TimerType;
|
||||
|
||||
/// User-mode timer object.
|
||||
struct UTimer {
|
||||
Waitable waitable;
|
||||
TimerType type : 8;
|
||||
@ -35,7 +37,8 @@ static inline Waiter waiterForUTimer(UTimer* t)
|
||||
* @brief Creates a user-mode timer.
|
||||
* @param[out] t UTimer object.
|
||||
* @param[in] interval Interval (in nanoseconds).
|
||||
* @param[in] type Timer type (repeating or one-shot)
|
||||
* @param[in] type Type of timer to create (see \ref TimerType).
|
||||
* @note The timer is stopped when it is created. Use \ref utimerStart to start it.
|
||||
* @note It is safe to wait on this timer with several threads simultaneously.
|
||||
* @note If more than one thread is listening on it, at least one thread will get the signal. No other guarantees.
|
||||
* @note For a repeating timer: If the timer triggers twice before you wait on it, you will only get one signal.
|
||||
|
@ -32,7 +32,7 @@ typedef enum {
|
||||
|
||||
// User-facing API starts here.
|
||||
|
||||
/// Waiter structure.
|
||||
/// Waiter structure, representing any generic waitable synchronization object; both kernel-mode and user-mode.
|
||||
typedef struct {
|
||||
WaiterType type;
|
||||
|
||||
@ -51,49 +51,68 @@ static inline Waiter waiterForHandle(Handle h)
|
||||
return wait_obj;
|
||||
}
|
||||
|
||||
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 generic waitable synchronization objects, optionally with a timeout.
|
||||
* @param[out] idx_out Variable that will received the index of the signalled object.
|
||||
* @param[in] objects Array containing \ref Waiter structures.
|
||||
* @param[in] num_objects Number of objects in the array.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
* @return Result code.
|
||||
* @note The number of objects must not be greater than \ref MAX_WAIT_OBJECTS. This is a Horizon kernel limitation.
|
||||
*/
|
||||
Result waitObjects(s32* idx_out, const Waiter* objects, s32 num_objects, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Waits for an arbitrary number of waiters. This is a macro that uses var-args.
|
||||
* @brief Waits for an arbitrary number of kernel synchronization objects, optionally with a timeout. This function replaces \ref svcWaitSynchronization.
|
||||
* @param[out] idx_out Variable that will received the index of the signalled object.
|
||||
* @param[in] handles Array containing handles.
|
||||
* @param[in] num_handles Number of handles in the array.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
* @return Result code.
|
||||
* @note The number of objects must not be greater than \ref MAX_WAIT_OBJECTS. This is a Horizon kernel limitation.
|
||||
*/
|
||||
Result waitHandles(s32* idx_out, const Handle* handles, s32 num_handles, u64 timeout);
|
||||
|
||||
/**
|
||||
* @brief Helper macro for \ref waitObjects that accepts \ref Waiter structures as variadic arguments instead of as an array.
|
||||
* @param[out] idx_out The index of the signalled waiter.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
* @note The number of objects must not be greater than \ref MAX_WAIT_OBJECTS. This is a Horizon kernel limitation.
|
||||
*/
|
||||
#define waitMulti(idx_out, timeout, ...) ({ \
|
||||
Waiter __objects[] = { __VA_ARGS__ }; \
|
||||
waitN((idx_out), __objects, sizeof(__objects) / sizeof(Waiter), (timeout)); \
|
||||
waitObjects((idx_out), __objects, sizeof(__objects) / sizeof(Waiter), (timeout)); \
|
||||
})
|
||||
|
||||
/**
|
||||
* @brief Waits for an arbitrary number of handles. This is a macro that uses var-args.
|
||||
* @brief Helper macro for \ref waitHandles that accepts handles as variadic arguments instead of as an array.
|
||||
* @param[out] idx_out The index of the signalled handle.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
* @note The number of objects must not be greater than \ref MAX_WAIT_OBJECTS. This is a Horizon kernel limitation.
|
||||
*/
|
||||
#define waitMultiHandle(idx_out, timeout, ...) ({ \
|
||||
Handle __handles[] = { __VA_ARGS__ }; \
|
||||
waitNHandle((idx_out), __handles, sizeof(__handles) / sizeof(Handle), (timeout)); \
|
||||
waitHandles((idx_out), __handles, sizeof(__handles) / sizeof(Handle), (timeout)); \
|
||||
})
|
||||
|
||||
/**
|
||||
* @brief Waits for a single waiter.
|
||||
* @param[in] w The waiter to wait for.
|
||||
* @brief Waits on a single generic waitable synchronization object, optionally with a timeout.
|
||||
* @param[in] w \ref Waiter structure.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
*/
|
||||
static inline Result waitSingle(Waiter w, u64 timeout)
|
||||
{
|
||||
s32 idx;
|
||||
return waitMulti(&idx, timeout, w);
|
||||
return waitObjects(&idx, &w, 1, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits for a single handle.
|
||||
* @param[in] h The handle to wait for.
|
||||
* @brief Waits for a single kernel synchronization object, optionally with a timeout.
|
||||
* @param[in] h \ref Handle of the object.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
*/
|
||||
static inline Result waitSingleHandle(Handle h, u64 timeout)
|
||||
{
|
||||
s32 idx;
|
||||
return waitMultiHandle(&idx, timeout, h);
|
||||
return waitHandles(&idx, &h, 1, timeout);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ void utimerStop(UTimer* t)
|
||||
{
|
||||
mutexLock(&t->waitable.mutex);
|
||||
|
||||
if (!t->started) {
|
||||
if (t->started) {
|
||||
t->started = false;
|
||||
t->next_tick = 0;
|
||||
_waitableSignalAllListeners(&t->waitable);
|
||||
|
@ -8,9 +8,9 @@
|
||||
#include "wait.h"
|
||||
#include "../internal.h"
|
||||
|
||||
typedef Result (*WaitImplFunc)(s32* idx_out, void* objects, size_t num_objects, u64 timeout);
|
||||
typedef Result (*WaitImplFunc)(s32* idx_out, const void* objects, s32 num_objects, u64 timeout);
|
||||
|
||||
static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 timeout)
|
||||
static Result _waitObjectsImpl(s32* idx_out, const Waiter* objects, u32 num_objects, u64 timeout)
|
||||
{
|
||||
if (num_objects > MAX_WAIT_OBJECTS)
|
||||
return KERNELRESULT(OutOfRange); // same error returned by kernel
|
||||
@ -34,7 +34,7 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
||||
end_tick = armNsToTicks(timeout);
|
||||
|
||||
for (i = 0; i < num_objects; i ++) {
|
||||
Waiter* obj = &objects[i];
|
||||
const Waiter* obj = &objects[i];
|
||||
u64 next_tick;
|
||||
bool added;
|
||||
|
||||
@ -116,7 +116,7 @@ clean_up:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _waitLoop(s32* idx_out, void* objects, size_t num_objects, u64 timeout, WaitImplFunc waitfunc)
|
||||
static Result _waitLoop(s32* idx_out, const void* objects, s32 num_objects, u64 timeout, WaitImplFunc waitfunc)
|
||||
{
|
||||
Result rc;
|
||||
bool has_timeout = timeout != UINT64_MAX;
|
||||
@ -140,12 +140,12 @@ static Result _waitLoop(s32* idx_out, void* objects, size_t num_objects, u64 tim
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result waitN(s32* idx_out, Waiter* objects, size_t num_objects, u64 timeout)
|
||||
Result waitObjects(s32* idx_out, const Waiter* objects, s32 num_objects, u64 timeout)
|
||||
{
|
||||
return _waitLoop(idx_out, objects, num_objects, timeout, (WaitImplFunc)waitImpl);
|
||||
return _waitLoop(idx_out, objects, num_objects, timeout, (WaitImplFunc)_waitObjectsImpl);
|
||||
}
|
||||
|
||||
Result waitNHandle(s32* idx_out, Handle* handles, size_t num_handles, u64 timeout)
|
||||
Result waitHandles(s32* idx_out, const Handle* handles, s32 num_handles, u64 timeout)
|
||||
{
|
||||
return _waitLoop(idx_out, handles, num_handles, timeout, (WaitImplFunc)svcWaitSynchronization);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user