diff --git a/nx/include/switch.h b/nx/include/switch.h
index 56cad927..eed6c5c5 100644
--- a/nx/include/switch.h
+++ b/nx/include/switch.h
@@ -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"
diff --git a/nx/include/switch/kernel/svc.h b/nx/include/switch/kernel/svc.h
index f3b0823f..f38d277c 100644
--- a/nx/include/switch/kernel/svc.h
+++ b/nx/include/switch/kernel/svc.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;
diff --git a/nx/include/switch/kernel/uevent.h b/nx/include/switch/kernel/uevent.h
index cd2a9d66..3ef76fc6 100644
--- a/nx/include/switch/kernel/uevent.h
+++ b/nx/include/switch/kernel/uevent.h
@@ -9,6 +9,7 @@
 
 typedef struct UEvent UEvent;
 
+/// User-mode event object.
 struct UEvent {
     Waitable waitable;
     bool signal;
diff --git a/nx/include/switch/kernel/utimer.h b/nx/include/switch/kernel/utimer.h
index f3cbefc1..f9d3e77a 100644
--- a/nx/include/switch/kernel/utimer.h
+++ b/nx/include/switch/kernel/utimer.h
@@ -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.
diff --git a/nx/include/switch/kernel/wait.h b/nx/include/switch/kernel/wait.h
index 01c75dd2..a864f5a4 100644
--- a/nx/include/switch/kernel/wait.h
+++ b/nx/include/switch/kernel/wait.h
@@ -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);
 }
diff --git a/nx/source/kernel/utimer.c b/nx/source/kernel/utimer.c
index a57f884d..2a1f1f6e 100644
--- a/nx/source/kernel/utimer.c
+++ b/nx/source/kernel/utimer.c
@@ -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);
diff --git a/nx/source/kernel/wait.c b/nx/source/kernel/wait.c
index 46210d40..aade1f2c 100644
--- a/nx/source/kernel/wait.c
+++ b/nx/source/kernel/wait.c
@@ -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);
 }