core: hle: kernel: Update KSynchronizationObject.
parent
1ae883435d
commit
35c3c078e3
@ -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
|
|
Loading…
Reference in New Issue