rpcs3/Utilities/SQueue.h

140 lines
2.0 KiB
C
Raw Normal View History

2014-02-24 00:00:42 +00:00
#pragma once
template<typename T, u32 SQSize = 666>
class SQueue
{
std::mutex m_mutex;
2014-06-20 19:57:28 +00:00
NamedThreadBase* push_waiter;
NamedThreadBase* pop_waiter;
2014-02-24 00:00:42 +00:00
u32 m_pos;
u32 m_count;
T m_data[SQSize];
public:
SQueue()
: m_pos(0)
, m_count(0)
2014-06-20 19:57:28 +00:00
, push_waiter(nullptr)
, pop_waiter(nullptr)
2014-02-24 00:00:42 +00:00
{
}
const u32 GetSize() const
{
return SQSize;
}
2014-03-06 11:50:45 +00:00
bool Push(const T& data)
2014-02-24 00:00:42 +00:00
{
2014-06-20 19:57:28 +00:00
NamedThreadBase* t = GetCurrentNamedThread();
push_waiter = t;
2014-02-24 00:00:42 +00:00
while (true)
{
if (m_count >= SQSize)
{
2014-03-02 23:02:42 +00:00
if (Emu.IsStopped())
{
return false;
}
2014-06-20 19:57:28 +00:00
SM_Sleep();
2014-02-24 00:00:42 +00:00
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
2014-02-24 00:00:42 +00:00
if (m_count >= SQSize) continue;
2014-06-20 19:57:28 +00:00
if (pop_waiter && !m_count) pop_waiter->Notify();
2014-02-24 00:00:42 +00:00
m_data[(m_pos + m_count++) % SQSize] = data;
2014-06-20 19:57:28 +00:00
push_waiter = nullptr;
2014-02-24 00:00:42 +00:00
return true;
}
}
}
bool Pop(T& data)
{
2014-06-20 19:57:28 +00:00
NamedThreadBase* t = GetCurrentNamedThread();
pop_waiter = t;
2014-02-24 00:00:42 +00:00
while (true)
{
if (!m_count)
{
2014-03-02 23:02:42 +00:00
if (Emu.IsStopped())
{
return false;
}
2014-06-20 19:57:28 +00:00
SM_Sleep();
2014-02-24 00:00:42 +00:00
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
2014-02-24 00:00:42 +00:00
if (!m_count) continue;
2014-06-20 19:57:28 +00:00
if (push_waiter && m_count >= SQSize) push_waiter->Notify();
2014-02-24 00:00:42 +00:00
data = m_data[m_pos];
m_pos = (m_pos + 1) % SQSize;
m_count--;
2014-06-20 19:57:28 +00:00
pop_waiter = nullptr;
2014-02-24 00:00:42 +00:00
return true;
}
}
}
2014-06-20 19:57:28 +00:00
volatile u32 GetCount() // may be thread unsafe
2014-02-24 00:00:42 +00:00
{
return m_count;
}
2014-06-20 19:57:28 +00:00
volatile bool IsEmpty() // may be thread unsafe
2014-02-24 00:00:42 +00:00
{
return !m_count;
}
void Clear()
{
std::lock_guard<std::mutex> lock(m_mutex);
2014-06-20 19:57:28 +00:00
if (push_waiter && m_count >= SQSize) push_waiter->Notify();
2014-02-24 00:00:42 +00:00
m_count = 0;
}
2014-03-02 23:02:42 +00:00
T& Peek(u32 pos = 0)
{
2014-06-20 19:57:28 +00:00
NamedThreadBase* t = GetCurrentNamedThread();
pop_waiter = t;
2014-03-22 01:08:25 +00:00
while (true)
{
if (!m_count)
{
if (Emu.IsStopped())
{
break;
}
2014-06-20 19:57:28 +00:00
SM_Sleep();
2014-03-22 01:08:25 +00:00
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
2014-06-20 19:57:28 +00:00
if (m_count)
{
pop_waiter = nullptr;
break;
}
2014-03-22 01:08:25 +00:00
}
}
2014-03-02 23:02:42 +00:00
return m_data[(m_pos + pos) % SQSize];
}
2014-03-06 11:50:45 +00:00
};