1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 03:02:53 +01:00
rpcs3/Utilities/SleepQueue.h

86 lines
1.7 KiB
C
Raw Normal View History

2014-12-23 00:31:11 +01:00
#pragma once
2016-02-01 22:55:43 +01:00
#include <deque>
2016-02-01 22:55:43 +01:00
// Tag used in sleep_entry<> constructor
static struct defer_sleep_tag {} constexpr defer_sleep{};
2015-07-19 03:56:33 +02:00
2016-02-01 22:55:43 +01:00
// Define sleep queue as std::deque with T* pointers, T - thread type
template<typename T> using sleep_queue = std::deque<T*>;
2014-12-24 17:09:32 +01:00
2016-02-01 22:55:43 +01:00
// Automatic object handling a thread pointer (T*) in the sleep queue
// Sleep is called in the constructor (if not null)
// Awake is called in the destructor (if not null)
// Sleep queue is actually std::deque with pointers, be careful about the lifetime
template<typename T, void(T::*Sleep)() = nullptr, void(T::*Awake)() = nullptr>
2016-02-01 22:55:43 +01:00
class sleep_entry final
{
sleep_queue<T>& m_queue;
T& m_thread;
2015-07-19 03:56:33 +02:00
2014-12-24 17:09:32 +01:00
public:
2016-02-01 22:55:43 +01:00
// Constructor; enter() not called
sleep_entry(sleep_queue<T>& queue, T& entry, const defer_sleep_tag&)
: m_queue(queue)
, m_thread(entry)
{
if (Sleep) (m_thread.*Sleep)();
}
2014-12-28 14:15:22 +01:00
2016-02-01 22:55:43 +01:00
// Constructor; calls enter()
sleep_entry(sleep_queue<T>& queue, T& entry)
: sleep_entry(queue, entry, defer_sleep)
{
enter();
}
2015-07-19 03:56:33 +02:00
2016-02-01 22:55:43 +01:00
// Destructor; calls leave()
~sleep_entry()
{
leave();
if (Awake) (m_thread.*Awake)();
}
2015-07-19 03:56:33 +02:00
2016-02-01 22:55:43 +01:00
// Add thread to the sleep queue
void enter()
2015-07-19 03:56:33 +02:00
{
2016-02-01 22:55:43 +01:00
for (auto t : m_queue)
{
if (t == &m_thread)
{
// Already exists, is it an error?
return;
}
}
m_queue.emplace_back(&m_thread);
2015-07-19 03:56:33 +02:00
}
2016-02-01 22:55:43 +01:00
// Remove thread from the sleep queue
void leave()
2015-07-19 03:56:33 +02:00
{
2016-05-13 16:01:48 +02:00
for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++)
2016-02-01 22:55:43 +01:00
{
2016-05-13 16:01:48 +02:00
if (*it == &m_thread)
{
m_queue.erase(it);
return;
}
2016-02-01 22:55:43 +01:00
}
2015-07-19 03:56:33 +02:00
}
2016-02-01 22:55:43 +01:00
// Check whether the thread exists in the sleep queue
explicit operator bool() const
2015-07-19 03:56:33 +02:00
{
2016-05-13 16:01:48 +02:00
for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++)
{
if (*it == &m_thread)
{
return true;
}
}
return false;
2015-07-19 03:56:33 +02:00
}
2014-12-23 00:31:11 +01:00
};