From d9b19be1d9c1baa5e8b92c1960c14e435e6b532f Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 11 Jan 2015 13:53:11 -0200
Subject: [PATCH] Kernel: Convert Semaphore to not use Handles

---
 src/core/hle/kernel/semaphore.cpp | 65 +++++++++++--------------------
 src/core/hle/kernel/semaphore.h   | 55 ++++++++++++++++++--------
 src/core/hle/svc.cpp              | 33 +++++++++++++---
 3 files changed, 87 insertions(+), 66 deletions(-)

diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index 135d8fb2a..a9e406ef4 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -2,8 +2,6 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include <queue>
-
 #include "common/common.h"
 
 #include "core/hle/kernel/kernel.h"
@@ -12,69 +10,50 @@
 
 namespace Kernel {
 
-class Semaphore : public WaitObject {
-public:
-    std::string GetTypeName() const override { return "Semaphore"; }
-    std::string GetName() const override { return name; }
-
-    static const HandleType HANDLE_TYPE = HandleType::Semaphore;
-    HandleType GetHandleType() const override { return HANDLE_TYPE; }
-
-    s32 max_count;                              ///< Maximum number of simultaneous holders the semaphore can have
-    s32 available_count;                        ///< Number of free slots left in the semaphore
-    std::string name;                           ///< Name of semaphore (optional)
-
-    bool ShouldWait() override {
-        return available_count <= 0;
-    }
-
-    void Acquire() override {
-        _assert_msg_(Kernel, !ShouldWait(), "object unavailable!");
-        --available_count;
-    }
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-ResultCode CreateSemaphore(Handle* handle, s32 initial_count, 
-    s32 max_count, const std::string& name) {
+ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count,
+        std::string name) {
 
     if (initial_count > max_count)
         return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
                           ErrorSummary::WrongArgument, ErrorLevel::Permanent);
 
-    Semaphore* semaphore = new Semaphore;
-    // TOOD(yuriks): Fix error reporting
-    *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE);
+    SharedPtr<Semaphore> semaphore(new Semaphore);
+    // TOOD(yuriks): Don't create Handle (see Thread::Create())
+    CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore));
 
     // When the semaphore is created, some slots are reserved for other threads,
     // and the rest is reserved for the caller thread
     semaphore->max_count = max_count;
     semaphore->available_count = initial_count;
-    semaphore->name = name;
+    semaphore->name = std::move(name);
 
-    return RESULT_SUCCESS;
+    return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore));
 }
 
-ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
-    Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get();
-    if (semaphore == nullptr)
-        return InvalidHandle(ErrorModule::Kernel);
+bool Semaphore::ShouldWait() {
+    return available_count <= 0;
+}
 
-    if (semaphore->max_count - semaphore->available_count < release_count)
+void Semaphore::Acquire() {
+    _assert_msg_(Kernel, !ShouldWait(), "object unavailable!");
+    --available_count;
+}
+
+ResultVal<s32> Semaphore::Release(s32 release_count) {
+    if (max_count - available_count < release_count)
         return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, 
                           ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
 
-    *count = semaphore->available_count;
-    semaphore->available_count += release_count;
+    s32 previous_count = available_count;
+    available_count += release_count;
 
     // Notify some of the threads that the semaphore has been released
     // stop once the semaphore is full again or there are no more waiting threads
-    while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) {
-        semaphore->Acquire();
+    while (!ShouldWait() && WakeupNextThread() != nullptr) {
+        Acquire();
     }
 
-    return RESULT_SUCCESS;
+    return MakeResult<s32>(previous_count);
 }
 
 } // namespace
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index 8644ecf0c..b7f22b86e 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -4,29 +4,50 @@
 
 #pragma once
 
+#include <queue>
+#include <string>
+
 #include "common/common_types.h"
 
 #include "core/hle/kernel/kernel.h"
 
 namespace Kernel {
 
-/**
- * Creates a semaphore.
- * @param handle Pointer to the handle of the newly created object
- * @param initial_count Number of slots reserved for other threads
- * @param max_count Maximum number of slots the semaphore can have
- * @param name Optional name of semaphore
- * @return ResultCode of the error
- */
-ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown");
+class Semaphore : public WaitObject {
+public:
+    /**
+     * Creates a semaphore.
+     * @param handle Pointer to the handle of the newly created object
+     * @param initial_count Number of slots reserved for other threads
+     * @param max_count Maximum number of slots the semaphore can have
+     * @param name Optional name of semaphore
+     * @return The created semaphore
+     */
+    static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count,
+            std::string name = "Unknown");
 
-/**
- * Releases a certain number of slots from a semaphore.
- * @param count The number of free slots the semaphore had before this call
- * @param handle The handle of the semaphore to release
- * @param release_count The number of slots to release
- * @return ResultCode of the error
- */
-ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count);
+    std::string GetTypeName() const override { return "Semaphore"; }
+    std::string GetName() const override { return name; }
+
+    static const HandleType HANDLE_TYPE = HandleType::Semaphore;
+    HandleType GetHandleType() const override { return HANDLE_TYPE; }
+
+    s32 max_count;                              ///< Maximum number of simultaneous holders the semaphore can have
+    s32 available_count;                        ///< Number of free slots left in the semaphore
+    std::string name;                           ///< Name of semaphore (optional)
+
+    bool ShouldWait() override;
+    void Acquire() override;
+
+    /**
+     * Releases a certain number of slots from a semaphore.
+     * @param release_count The number of slots to release
+     * @return The number of free slots the semaphore had before this call
+     */
+    ResultVal<s32> Release(s32 release_count);
+
+private:
+    Semaphore() = default;
+};
 
 } // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 165da0402..6cbe38bc3 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -374,17 +374,38 @@ static Result GetThreadId(u32* thread_id, Handle handle) {
 
 /// Creates a semaphore
 static Result CreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count) {
-    ResultCode res = Kernel::CreateSemaphore(semaphore, initial_count, max_count);
+    using Kernel::Semaphore;
+
+    ResultVal<SharedPtr<Semaphore>> semaphore_res = Semaphore::Create(initial_count, max_count);
+    if (semaphore_res.Failed())
+        return semaphore_res.Code().raw;
+
+    ResultVal<Handle> handle_res = Kernel::g_handle_table.Create(*semaphore_res);
+    if (handle_res.Failed())
+        return handle_res.Code().raw;
+
+    *semaphore = *handle_res;
     LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X",
         initial_count, max_count, *semaphore);
-    return res.raw;
+    return RESULT_SUCCESS.raw;
 }
 
 /// Releases a certain number of slots in a semaphore
-static Result ReleaseSemaphore(s32* count, Handle semaphore, s32 release_count) {
-    LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, semaphore);
-    ResultCode res = Kernel::ReleaseSemaphore(count, semaphore, release_count);
-    return res.raw;
+static Result ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
+    using Kernel::Semaphore;
+
+    LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle);
+
+    SharedPtr<Semaphore> semaphore = Kernel::g_handle_table.Get<Semaphore>(handle);
+    if (semaphore == nullptr)
+        return InvalidHandle(ErrorModule::Kernel).raw;
+
+    ResultVal<s32> release_res = semaphore->Release(release_count);
+    if (release_res.Failed())
+        return release_res.Code().raw;
+
+    *count = *release_res;
+    return RESULT_SUCCESS.raw;
 }
 
 /// Query memory