SDL: Use native mutexes

From 87a118b6b6cd3162de9ca9b56f927bf235b09f29 Mon Sep 17 00:00:00 2001
From: Ivan Epifanov <[EMAIL REDACTED]>
Date: Wed, 20 Jan 2021 23:33:28 +0300
Subject: [PATCH] Use native mutexes

---
 src/thread/vita/SDL_sysmutex.c | 97 +++++++++++++++++++---------------
 1 file changed, 54 insertions(+), 43 deletions(-)

diff --git a/src/thread/vita/SDL_sysmutex.c b/src/thread/vita/SDL_sysmutex.c
index 6584fb2bf..f91853776 100644
--- a/src/thread/vita/SDL_sysmutex.c
+++ b/src/thread/vita/SDL_sysmutex.c
@@ -22,17 +22,15 @@
 
 #if SDL_THREAD_VITA
 
-/* An implementation of mutexes using semaphores */
-
 #include "SDL_thread.h"
 #include "SDL_systhread_c.h"
 
+#include <psp2/kernel/threadmgr.h>
+#include <psp2/kernel/error.h>
 
 struct SDL_mutex
 {
-    int recursive;
-    SDL_threadID owner;
-    SDL_sem *sem;
+    SceUID uid;
 };
 
 /* Create a mutex */
@@ -44,13 +42,16 @@ SDL_CreateMutex(void)
     /* Allocate mutex memory */
     mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex));
     if (mutex) {
-        /* Create the mutex semaphore, with initial value 1 */
-        mutex->sem = SDL_CreateSemaphore(1);
-        mutex->recursive = 0;
-        mutex->owner = 0;
-        if (!mutex->sem) {
-            SDL_free(mutex);
-            mutex = NULL;
+
+        mutex->uid =  sceKernelCreateMutex("SDL mutex",
+            SCE_KERNEL_MUTEX_ATTR_TH_PRIO |  SCE_KERNEL_MUTEX_ATTR_RECURSIVE,
+            0,
+            NULL
+        );
+
+        if (mutex->uid <= 0) {
+            printf("Error creating mutex: %x\n", mutex->uid);
+            SDL_OutOfMemory(); // TODO: proper error
         }
     } else {
         SDL_OutOfMemory();
@@ -63,37 +64,56 @@ void
 SDL_DestroyMutex(SDL_mutex * mutex)
 {
     if (mutex) {
-        if (mutex->sem) {
-            SDL_DestroySemaphore(mutex->sem);
-        }
+        sceKernelDeleteMutex(mutex->uid);
         SDL_free(mutex);
     }
 }
 
-/* Lock the semaphore */
+/* Try to lock the mutex */
 int
-SDL_mutexP(SDL_mutex * mutex)
+SDL_TryLockMutex(SDL_mutex * mutex)
 {
 #if SDL_THREADS_DISABLED
     return 0;
 #else
-    SDL_threadID this_thread;
+    SceInt32 res = 0;
+    if (mutex == NULL) {
+        return SDL_SetError("Passed a NULL mutex");
+    }
+
+    res = sceKernelTryLockMutex(mutex->uid, 1);
+    switch (res) {
+        case SCE_KERNEL_OK:
+            return 0;
+            break;
+        case SCE_KERNEL_ERROR_MUTEX_FAILED_TO_OWN:
+            return SDL_MUTEX_TIMEDOUT;
+            break;
+        default:
+            return SDL_SetError("Error trying to lock mutex: %x", res);
+            break;
+    }
+
+    return -1;
+#endif /* SDL_THREADS_DISABLED */
+}
+
 
+/* Lock the mutex */
+int
+SDL_mutexP(SDL_mutex * mutex)
+{
+#if SDL_THREADS_DISABLED
+    return 0;
+#else
+    SceInt32 res = 0;
     if (mutex == NULL) {
         return SDL_SetError("Passed a NULL mutex");
     }
 
-    this_thread = SDL_ThreadID();
-    if (mutex->owner == this_thread) {
-        ++mutex->recursive;
-    } else {
-        /* The order of operations is important.
-           We set the locking thread id after we obtain the lock
-           so unlocks from other threads will fail.
-         */
-        SDL_SemWait(mutex->sem);
-        mutex->owner = this_thread;
-        mutex->recursive = 0;
+    res = sceKernelLockMutex(mutex->uid, 1, NULL);
+    if (res != SCE_KERNEL_OK) {
+        return SDL_SetError("Error trying to lock mutex: %x", res);
     }
 
     return 0;
@@ -107,26 +127,17 @@ SDL_mutexV(SDL_mutex * mutex)
 #if SDL_THREADS_DISABLED
     return 0;
 #else
+    SceInt32 res = 0;
+
     if (mutex == NULL) {
         return SDL_SetError("Passed a NULL mutex");
     }
 
-    /* If we don't own the mutex, we can't unlock it */
-    if (SDL_ThreadID() != mutex->owner) {
-        return SDL_SetError("mutex not owned by this thread");
+    res = sceKernelUnlockMutex(mutex->uid, 1);
+    if (res != 0) {
+        return SDL_SetError("Error trying to unlock mutex: %x", res);
     }
 
-    if (mutex->recursive) {
-        --mutex->recursive;
-    } else {
-        /* The order of operations is important.
-           First reset the owner so another thread doesn't lock
-           the mutex and set the ownership before we reset it,
-           then release the lock semaphore.
-         */
-        mutex->owner = 0;
-        SDL_SemPost(mutex->sem);
-    }
     return 0;
 #endif /* SDL_THREADS_DISABLED */
 }