2014-12-22 23:31:11 +00:00
|
|
|
#pragma once
|
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
#include <deque>
|
2015-07-07 22:33:24 +00:00
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
// Tag used in sleep_entry<> constructor
|
|
|
|
static struct defer_sleep_tag {} constexpr defer_sleep{};
|
2015-07-19 01:56:33 +00:00
|
|
|
|
2016-02-01 21:55:43 +00: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 16:09:32 +00:00
|
|
|
|
2016-02-01 21:55:43 +00: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)() = &T::sleep, void(T::*Awake)() = &T::awake>
|
|
|
|
class sleep_entry final
|
|
|
|
{
|
|
|
|
sleep_queue<T>& m_queue;
|
|
|
|
T& m_thread;
|
2015-07-19 01:56:33 +00:00
|
|
|
|
2014-12-24 16:09:32 +00:00
|
|
|
public:
|
2016-02-01 21:55:43 +00: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 13:15:22 +00:00
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
// Constructor; calls enter()
|
|
|
|
sleep_entry(sleep_queue<T>& queue, T& entry)
|
|
|
|
: sleep_entry(queue, entry, defer_sleep)
|
|
|
|
{
|
|
|
|
enter();
|
|
|
|
}
|
2015-07-19 01:56:33 +00:00
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
// Destructor; calls leave()
|
|
|
|
~sleep_entry()
|
|
|
|
{
|
|
|
|
leave();
|
|
|
|
if (Awake) (m_thread.*Awake)();
|
|
|
|
}
|
2015-07-19 01:56:33 +00:00
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
// Add thread to the sleep queue
|
2015-09-26 20:46:04 +00:00
|
|
|
void enter()
|
2015-07-19 01:56:33 +00:00
|
|
|
{
|
2016-02-01 21:55:43 +00: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 01:56:33 +00:00
|
|
|
}
|
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
// Remove thread from the sleep queue
|
2015-09-26 20:46:04 +00:00
|
|
|
void leave()
|
2015-07-19 01:56:33 +00:00
|
|
|
{
|
2016-05-13 14:01:48 +00:00
|
|
|
for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++)
|
2016-02-01 21:55:43 +00:00
|
|
|
{
|
2016-05-13 14:01:48 +00:00
|
|
|
if (*it == &m_thread)
|
|
|
|
{
|
|
|
|
m_queue.erase(it);
|
|
|
|
return;
|
|
|
|
}
|
2016-02-01 21:55:43 +00:00
|
|
|
}
|
2015-07-19 01:56:33 +00:00
|
|
|
}
|
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
// Check whether the thread exists in the sleep queue
|
2015-09-26 20:46:04 +00:00
|
|
|
explicit operator bool() const
|
2015-07-19 01:56:33 +00:00
|
|
|
{
|
2016-05-13 14:01:48 +00: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 01:56:33 +00:00
|
|
|
}
|
2014-12-22 23:31:11 +00:00
|
|
|
};
|