33 changed files with 397 additions and 621 deletions
-
6src/core/CMakeLists.txt
-
10src/core/hle/kernel/address_arbiter.cpp
-
3src/core/hle/kernel/client_port.cpp
-
11src/core/hle/kernel/client_session.cpp
-
8src/core/hle/kernel/client_session.h
-
3src/core/hle/kernel/errors.h
-
5src/core/hle/kernel/k_scheduler.cpp
-
171src/core/hle/kernel/k_synchronization_object.cpp
-
58src/core/hle/kernel/k_synchronization_object.h
-
15src/core/hle/kernel/kernel.cpp
-
6src/core/hle/kernel/kernel.h
-
4src/core/hle/kernel/mutex.cpp
-
21src/core/hle/kernel/process.cpp
-
14src/core/hle/kernel/process.h
-
18src/core/hle/kernel/readable_event.cpp
-
12src/core/hle/kernel/readable_event.h
-
14src/core/hle/kernel/server_port.cpp
-
7src/core/hle/kernel/server_port.h
-
23src/core/hle/kernel/server_session.cpp
-
12src/core/hle/kernel/server_session.h
-
11src/core/hle/kernel/session.cpp
-
8src/core/hle/kernel/session.h
-
47src/core/hle/kernel/svc.cpp
-
9src/core/hle/kernel/svc_wrap.h
-
116src/core/hle/kernel/synchronization.cpp
-
44src/core/hle/kernel/synchronization.h
-
49src/core/hle/kernel/synchronization_object.cpp
-
77src/core/hle/kernel/synchronization_object.h
-
66src/core/hle/kernel/thread.cpp
-
131src/core/hle/kernel/thread.h
-
3src/core/hle/service/sm/sm.cpp
-
19src/yuzu/debugger/wait_tree.cpp
-
17src/yuzu/debugger/wait_tree.h
@ -0,0 +1,171 @@ |
|||||
|
// Copyright 2021 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "common/common_types.h"
|
||||
|
#include "core/hle/kernel/k_scheduler.h"
|
||||
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
|
#include "core/hle/kernel/kernel.h"
|
||||
|
#include "core/hle/kernel/svc_results.h"
|
||||
|
#include "core/hle/kernel/thread.h"
|
||||
|
|
||||
|
namespace Kernel { |
||||
|
|
||||
|
ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, |
||||
|
KSynchronizationObject** objects, const s32 num_objects, |
||||
|
s64 timeout) { |
||||
|
// Allocate space on stack for thread nodes.
|
||||
|
std::vector<ThreadListNode> thread_nodes(num_objects); |
||||
|
|
||||
|
// Prepare for wait.
|
||||
|
Thread* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
||||
|
Handle timer = InvalidHandle; |
||||
|
|
||||
|
{ |
||||
|
// Setup the scheduling lock and sleep.
|
||||
|
KScopedSchedulerLockAndSleep slp(kernel, timer, thread, timeout); |
||||
|
|
||||
|
// Check if any of the objects are already signaled.
|
||||
|
for (auto i = 0; i < num_objects; ++i) { |
||||
|
ASSERT(objects[i] != nullptr); |
||||
|
|
||||
|
if (objects[i]->IsSignaled()) { |
||||
|
*out_index = i; |
||||
|
slp.CancelSleep(); |
||||
|
return RESULT_SUCCESS; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Check if the timeout is zero.
|
||||
|
if (timeout == 0) { |
||||
|
slp.CancelSleep(); |
||||
|
return Svc::ResultTimedOut; |
||||
|
} |
||||
|
|
||||
|
// Check if the thread should terminate.
|
||||
|
if (thread->IsTerminationRequested()) { |
||||
|
slp.CancelSleep(); |
||||
|
return Svc::ResultTerminationRequested; |
||||
|
} |
||||
|
|
||||
|
// Check if waiting was canceled.
|
||||
|
if (thread->IsWaitCancelled()) { |
||||
|
slp.CancelSleep(); |
||||
|
thread->ClearWaitCancelled(); |
||||
|
return Svc::ResultCancelled; |
||||
|
} |
||||
|
|
||||
|
// Add the waiters.
|
||||
|
for (auto i = 0; i < num_objects; ++i) { |
||||
|
thread_nodes[i].thread = thread; |
||||
|
thread_nodes[i].next = nullptr; |
||||
|
|
||||
|
if (objects[i]->thread_list_tail == nullptr) { |
||||
|
objects[i]->thread_list_head = std::addressof(thread_nodes[i]); |
||||
|
} else { |
||||
|
objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]); |
||||
|
} |
||||
|
|
||||
|
objects[i]->thread_list_tail = std::addressof(thread_nodes[i]); |
||||
|
} |
||||
|
|
||||
|
// For debugging only
|
||||
|
thread->SetWaitObjectsForDebugging(objects, num_objects); |
||||
|
|
||||
|
// Mark the thread as waiting.
|
||||
|
thread->SetCancellable(); |
||||
|
thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); |
||||
|
thread->SetState(ThreadState::WaitSynch); |
||||
|
} |
||||
|
|
||||
|
// The lock/sleep is done, so we should be able to get our result.
|
||||
|
|
||||
|
// Thread is no longer cancellable.
|
||||
|
thread->ClearCancellable(); |
||||
|
|
||||
|
// For debugging only
|
||||
|
thread->SetWaitObjectsForDebugging(nullptr, 0); |
||||
|
|
||||
|
// Cancel the timer as needed.
|
||||
|
if (timer != InvalidHandle) { |
||||
|
auto& time_manager = kernel.TimeManager(); |
||||
|
time_manager.UnscheduleTimeEvent(timer); |
||||
|
} |
||||
|
|
||||
|
// Get the wait result.
|
||||
|
ResultCode wait_result{RESULT_SUCCESS}; |
||||
|
s32 sync_index = -1; |
||||
|
{ |
||||
|
KScopedSchedulerLock lock(kernel); |
||||
|
KSynchronizationObject* synced_obj; |
||||
|
wait_result = thread->GetWaitResult(std::addressof(synced_obj)); |
||||
|
|
||||
|
for (auto i = 0; i < num_objects; ++i) { |
||||
|
// Unlink the object from the list.
|
||||
|
ThreadListNode* prev_ptr = |
||||
|
reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head)); |
||||
|
ThreadListNode* prev_val = nullptr; |
||||
|
ThreadListNode *prev, *tail_prev; |
||||
|
|
||||
|
do { |
||||
|
prev = prev_ptr; |
||||
|
prev_ptr = prev_ptr->next; |
||||
|
tail_prev = prev_val; |
||||
|
prev_val = prev_ptr; |
||||
|
} while (prev_ptr != std::addressof(thread_nodes[i])); |
||||
|
|
||||
|
if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) { |
||||
|
objects[i]->thread_list_tail = tail_prev; |
||||
|
} |
||||
|
|
||||
|
prev->next = thread_nodes[i].next; |
||||
|
|
||||
|
if (objects[i] == synced_obj) { |
||||
|
sync_index = i; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Set output.
|
||||
|
*out_index = sync_index; |
||||
|
return wait_result; |
||||
|
} |
||||
|
|
||||
|
KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} |
||||
|
|
||||
|
KSynchronizationObject ::~KSynchronizationObject() = default; |
||||
|
|
||||
|
void KSynchronizationObject::NotifyAvailable(ResultCode result) { |
||||
|
KScopedSchedulerLock lock(kernel); |
||||
|
|
||||
|
// If we're not signaled, we've nothing to notify.
|
||||
|
if (!this->IsSignaled()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Iterate over each thread.
|
||||
|
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { |
||||
|
Thread* thread = cur_node->thread; |
||||
|
if (thread->GetState() == ThreadSchedStatus::Paused) { |
||||
|
thread->SetSyncedObject(this, result); |
||||
|
thread->SetState(ThreadStatus::Ready); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::vector<Thread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const { |
||||
|
std::vector<Thread*> threads; |
||||
|
|
||||
|
// If debugging, dump the list of waiters.
|
||||
|
{ |
||||
|
KScopedSchedulerLock lock(kernel); |
||||
|
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { |
||||
|
threads.emplace_back(cur_node->thread); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return threads; |
||||
|
} |
||||
|
} // namespace Kernel
|
||||
@ -0,0 +1,58 @@ |
|||||
|
// Copyright 2021 yuzu Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <vector> |
||||
|
|
||||
|
#include "core/hle/kernel/object.h" |
||||
|
#include "core/hle/result.h" |
||||
|
|
||||
|
namespace Kernel { |
||||
|
|
||||
|
class KernelCore; |
||||
|
class Synchronization; |
||||
|
class Thread; |
||||
|
|
||||
|
/// Class that represents a Kernel object that a thread can be waiting on |
||||
|
class KSynchronizationObject : public Object { |
||||
|
public: |
||||
|
struct ThreadListNode { |
||||
|
ThreadListNode* next{}; |
||||
|
Thread* thread{}; |
||||
|
}; |
||||
|
|
||||
|
[[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index, |
||||
|
KSynchronizationObject** objects, const s32 num_objects, |
||||
|
s64 timeout); |
||||
|
|
||||
|
[[nodiscard]] virtual bool IsSignaled() const = 0; |
||||
|
|
||||
|
[[nodiscard]] std::vector<Thread*> GetWaitingThreadsForDebugging() const; |
||||
|
|
||||
|
protected: |
||||
|
explicit KSynchronizationObject(KernelCore& kernel); |
||||
|
virtual ~KSynchronizationObject(); |
||||
|
|
||||
|
void NotifyAvailable(ResultCode result); |
||||
|
void NotifyAvailable() { |
||||
|
return this->NotifyAvailable(RESULT_SUCCESS); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
ThreadListNode* thread_list_head{}; |
||||
|
ThreadListNode* thread_list_tail{}; |
||||
|
}; |
||||
|
|
||||
|
// Specialization of DynamicObjectCast for KSynchronizationObjects |
||||
|
template <> |
||||
|
inline std::shared_ptr<KSynchronizationObject> DynamicObjectCast<KSynchronizationObject>( |
||||
|
std::shared_ptr<Object> object) { |
||||
|
if (object != nullptr && object->IsWaitable()) { |
||||
|
return std::static_pointer_cast<KSynchronizationObject>(object); |
||||
|
} |
||||
|
return nullptr; |
||||
|
} |
||||
|
|
||||
|
} // namespace Kernel |
||||
@ -1,116 +0,0 @@ |
|||||
// Copyright 2020 yuzu Emulator Project
|
|
||||
// Licensed under GPLv2 or any later version
|
|
||||
// Refer to the license.txt file included.
|
|
||||
|
|
||||
#include "core/core.h"
|
|
||||
#include "core/hle/kernel/errors.h"
|
|
||||
#include "core/hle/kernel/handle_table.h"
|
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
|
||||
#include "core/hle/kernel/kernel.h"
|
|
||||
#include "core/hle/kernel/synchronization.h"
|
|
||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||
#include "core/hle/kernel/thread.h"
|
|
||||
#include "core/hle/kernel/time_manager.h"
|
|
||||
|
|
||||
namespace Kernel { |
|
||||
|
|
||||
Synchronization::Synchronization(Core::System& system) : system{system} {} |
|
||||
|
|
||||
void Synchronization::SignalObject(SynchronizationObject& obj) const { |
|
||||
auto& kernel = system.Kernel(); |
|
||||
KScopedSchedulerLock lock(kernel); |
|
||||
if (obj.IsSignaled()) { |
|
||||
for (auto thread : obj.GetWaitingThreads()) { |
|
||||
if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { |
|
||||
if (thread->GetStatus() != ThreadStatus::WaitHLEEvent) { |
|
||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); |
|
||||
ASSERT(thread->IsWaitingSync()); |
|
||||
} |
|
||||
thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); |
|
||||
thread->ResumeFromWait(); |
|
||||
} |
|
||||
} |
|
||||
obj.ClearWaitingThreads(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
std::pair<ResultCode, Handle> Synchronization::WaitFor( |
|
||||
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { |
|
||||
auto& kernel = system.Kernel(); |
|
||||
auto* const thread = kernel.CurrentScheduler()->GetCurrentThread(); |
|
||||
Handle event_handle = InvalidHandle; |
|
||||
{ |
|
||||
KScopedSchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds); |
|
||||
const auto itr = |
|
||||
std::find_if(sync_objects.begin(), sync_objects.end(), |
|
||||
[thread](const std::shared_ptr<SynchronizationObject>& object) { |
|
||||
return object->IsSignaled(); |
|
||||
}); |
|
||||
|
|
||||
if (itr != sync_objects.end()) { |
|
||||
// We found a ready object, acquire it and set the result value
|
|
||||
SynchronizationObject* object = itr->get(); |
|
||||
object->Acquire(thread); |
|
||||
const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); |
|
||||
lock.CancelSleep(); |
|
||||
return {RESULT_SUCCESS, index}; |
|
||||
} |
|
||||
|
|
||||
if (nano_seconds == 0) { |
|
||||
lock.CancelSleep(); |
|
||||
return {RESULT_TIMEOUT, InvalidHandle}; |
|
||||
} |
|
||||
|
|
||||
if (thread->IsPendingTermination()) { |
|
||||
lock.CancelSleep(); |
|
||||
return {ERR_THREAD_TERMINATING, InvalidHandle}; |
|
||||
} |
|
||||
|
|
||||
if (thread->IsSyncCancelled()) { |
|
||||
thread->SetSyncCancelled(false); |
|
||||
lock.CancelSleep(); |
|
||||
return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; |
|
||||
} |
|
||||
|
|
||||
for (auto& object : sync_objects) { |
|
||||
object->AddWaitingThread(SharedFrom(thread)); |
|
||||
} |
|
||||
|
|
||||
thread->SetSynchronizationObjects(&sync_objects); |
|
||||
thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); |
|
||||
thread->SetStatus(ThreadStatus::WaitSynch); |
|
||||
thread->SetWaitingSync(true); |
|
||||
} |
|
||||
thread->SetWaitingSync(false); |
|
||||
|
|
||||
if (event_handle != InvalidHandle) { |
|
||||
auto& time_manager = kernel.TimeManager(); |
|
||||
time_manager.UnscheduleTimeEvent(event_handle); |
|
||||
} |
|
||||
|
|
||||
{ |
|
||||
KScopedSchedulerLock lock(kernel); |
|
||||
ResultCode signaling_result = thread->GetSignalingResult(); |
|
||||
SynchronizationObject* signaling_object = thread->GetSignalingObject(); |
|
||||
thread->SetSynchronizationObjects(nullptr); |
|
||||
auto shared_thread = SharedFrom(thread); |
|
||||
for (auto& obj : sync_objects) { |
|
||||
obj->RemoveWaitingThread(shared_thread); |
|
||||
} |
|
||||
if (signaling_object != nullptr) { |
|
||||
const auto itr = std::find_if( |
|
||||
sync_objects.begin(), sync_objects.end(), |
|
||||
[signaling_object](const std::shared_ptr<SynchronizationObject>& object) { |
|
||||
return object.get() == signaling_object; |
|
||||
}); |
|
||||
ASSERT(itr != sync_objects.end()); |
|
||||
signaling_object->Acquire(thread); |
|
||||
const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); |
|
||||
return {signaling_result, index}; |
|
||||
} |
|
||||
return {signaling_result, -1}; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} // namespace Kernel
|
|
||||
@ -1,44 +0,0 @@ |
|||||
// Copyright 2020 yuzu Emulator Project |
|
||||
// Licensed under GPLv2 or any later version |
|
||||
// Refer to the license.txt file included. |
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
#include <memory> |
|
||||
#include <utility> |
|
||||
#include <vector> |
|
||||
|
|
||||
#include "core/hle/kernel/object.h" |
|
||||
#include "core/hle/result.h" |
|
||||
|
|
||||
namespace Core { |
|
||||
class System; |
|
||||
} // namespace Core |
|
||||
|
|
||||
namespace Kernel { |
|
||||
|
|
||||
class SynchronizationObject; |
|
||||
|
|
||||
/** |
|
||||
* The 'Synchronization' class is an interface for handling synchronization methods |
|
||||
* used by Synchronization objects and synchronization SVCs. This centralizes processing of |
|
||||
* such |
|
||||
*/ |
|
||||
class Synchronization { |
|
||||
public: |
|
||||
explicit Synchronization(Core::System& system); |
|
||||
|
|
||||
/// Signals a synchronization object, waking up all its waiting threads |
|
||||
void SignalObject(SynchronizationObject& obj) const; |
|
||||
|
|
||||
/// Tries to see if waiting for any of the sync_objects is necessary, if not |
|
||||
/// it returns Success and the handle index of the signaled sync object. In |
|
||||
/// case not, the current thread will be locked and wait for nano_seconds or |
|
||||
/// for a synchronization object to signal. |
|
||||
std::pair<ResultCode, Handle> WaitFor( |
|
||||
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds); |
|
||||
|
|
||||
private: |
|
||||
Core::System& system; |
|
||||
}; |
|
||||
} // namespace Kernel |
|
||||
@ -1,49 +0,0 @@ |
|||||
// Copyright 2014 Citra Emulator Project
|
|
||||
// Licensed under GPLv2 or any later version
|
|
||||
// Refer to the license.txt file included.
|
|
||||
|
|
||||
#include <algorithm>
|
|
||||
#include "common/assert.h"
|
|
||||
#include "common/common_types.h"
|
|
||||
#include "common/logging/log.h"
|
|
||||
#include "core/core.h"
|
|
||||
#include "core/hle/kernel/kernel.h"
|
|
||||
#include "core/hle/kernel/object.h"
|
|
||||
#include "core/hle/kernel/process.h"
|
|
||||
#include "core/hle/kernel/synchronization.h"
|
|
||||
#include "core/hle/kernel/synchronization_object.h"
|
|
||||
#include "core/hle/kernel/thread.h"
|
|
||||
|
|
||||
namespace Kernel { |
|
||||
|
|
||||
SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {} |
|
||||
SynchronizationObject::~SynchronizationObject() = default; |
|
||||
|
|
||||
void SynchronizationObject::Signal() { |
|
||||
kernel.Synchronization().SignalObject(*this); |
|
||||
} |
|
||||
|
|
||||
void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) { |
|
||||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); |
|
||||
if (itr == waiting_threads.end()) |
|
||||
waiting_threads.push_back(std::move(thread)); |
|
||||
} |
|
||||
|
|
||||
void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) { |
|
||||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); |
|
||||
// If a thread passed multiple handles to the same object,
|
|
||||
// the kernel might attempt to remove the thread from the object's
|
|
||||
// waiting threads list multiple times.
|
|
||||
if (itr != waiting_threads.end()) |
|
||||
waiting_threads.erase(itr); |
|
||||
} |
|
||||
|
|
||||
void SynchronizationObject::ClearWaitingThreads() { |
|
||||
waiting_threads.clear(); |
|
||||
} |
|
||||
|
|
||||
const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const { |
|
||||
return waiting_threads; |
|
||||
} |
|
||||
|
|
||||
} // namespace Kernel
|
|
||||
@ -1,77 +0,0 @@ |
|||||
// Copyright 2014 Citra Emulator Project |
|
||||
// Licensed under GPLv2 or any later version |
|
||||
// Refer to the license.txt file included. |
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
#include <atomic> |
|
||||
#include <memory> |
|
||||
#include <vector> |
|
||||
|
|
||||
#include "core/hle/kernel/object.h" |
|
||||
|
|
||||
namespace Kernel { |
|
||||
|
|
||||
class KernelCore; |
|
||||
class Synchronization; |
|
||||
class Thread; |
|
||||
|
|
||||
/// Class that represents a Kernel object that a thread can be waiting on |
|
||||
class SynchronizationObject : public Object { |
|
||||
public: |
|
||||
explicit SynchronizationObject(KernelCore& kernel); |
|
||||
~SynchronizationObject() override; |
|
||||
|
|
||||
/** |
|
||||
* Check if the specified thread should wait until the object is available |
|
||||
* @param thread The thread about which we're deciding. |
|
||||
* @return True if the current thread should wait due to this object being unavailable |
|
||||
*/ |
|
||||
virtual bool ShouldWait(const Thread* thread) const = 0; |
|
||||
|
|
||||
/// Acquire/lock the object for the specified thread if it is available |
|
||||
virtual void Acquire(Thread* thread) = 0; |
|
||||
|
|
||||
/// Signal this object |
|
||||
virtual void Signal(); |
|
||||
|
|
||||
virtual bool IsSignaled() const { |
|
||||
return is_signaled; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Add a thread to wait on this object |
|
||||
* @param thread Pointer to thread to add |
|
||||
*/ |
|
||||
void AddWaitingThread(std::shared_ptr<Thread> thread); |
|
||||
|
|
||||
/** |
|
||||
* Removes a thread from waiting on this object (e.g. if it was resumed already) |
|
||||
* @param thread Pointer to thread to remove |
|
||||
*/ |
|
||||
void RemoveWaitingThread(std::shared_ptr<Thread> thread); |
|
||||
|
|
||||
/// Get a const reference to the waiting threads list for debug use |
|
||||
const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; |
|
||||
|
|
||||
void ClearWaitingThreads(); |
|
||||
|
|
||||
protected: |
|
||||
std::atomic_bool is_signaled{}; // Tells if this sync object is signaled |
|
||||
|
|
||||
private: |
|
||||
/// Threads waiting for this object to become available |
|
||||
std::vector<std::shared_ptr<Thread>> waiting_threads; |
|
||||
}; |
|
||||
|
|
||||
// Specialization of DynamicObjectCast for SynchronizationObjects |
|
||||
template <> |
|
||||
inline std::shared_ptr<SynchronizationObject> DynamicObjectCast<SynchronizationObject>( |
|
||||
std::shared_ptr<Object> object) { |
|
||||
if (object != nullptr && object->IsWaitable()) { |
|
||||
return std::static_pointer_cast<SynchronizationObject>(object); |
|
||||
} |
|
||||
return nullptr; |
|
||||
} |
|
||||
|
|
||||
} // namespace Kernel |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue