| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- // Copyright 2014 Citra Emulator Project
- // 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"
- #include "core/hle/kernel/semaphore.h"
- #include "core/hle/kernel/thread.h"
- namespace Kernel {
- class Semaphore : public Object {
- public:
- std::string GetTypeName() const override { return "Semaphore"; }
- std::string GetName() const override { return name; }
- static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; }
- Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; }
- s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
- s32 available_count; ///< Number of free slots left in the semaphore
- std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore
- std::string name; ///< Name of semaphore (optional)
- /**
- * Tests whether a semaphore still has free slots
- * @return Whether the semaphore is available
- */
- bool IsAvailable() const {
- return available_count > 0;
- }
- ResultVal<bool> WaitSynchronization() override {
- bool wait = !IsAvailable();
- if (wait) {
- Kernel::WaitCurrentThread(WAITTYPE_SEMA, GetHandle());
- waiting_threads.push(GetCurrentThreadHandle());
- } else {
- --available_count;
- }
- return MakeResult<bool>(wait);
- }
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- ResultCode CreateSemaphore(Handle* handle, s32 initial_count,
- s32 max_count, const std::string& name) {
- if (initial_count > max_count)
- return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
- ErrorSummary::WrongArgument, ErrorLevel::Permanent);
- Semaphore* semaphore = new Semaphore;
- *handle = 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;
- return RESULT_SUCCESS;
- }
- ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
- Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle);
- if (semaphore == nullptr)
- return InvalidHandle(ErrorModule::Kernel);
- if (semaphore->max_count - semaphore->available_count < release_count)
- return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
- ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
- *count = semaphore->available_count;
- semaphore->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->waiting_threads.empty() && semaphore->IsAvailable()) {
- Kernel::ResumeThreadFromWait(semaphore->waiting_threads.front());
- semaphore->waiting_threads.pop();
- --semaphore->available_count;
- }
- return RESULT_SUCCESS;
- }
- } // namespace
|