rpcsx/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp

259 lines
4.8 KiB
C++
Raw Normal View History

2014-12-23 00:31:11 +01:00
#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
2014-12-24 17:09:32 +01:00
#include "Emu/IdManager.h"
2014-12-23 00:31:11 +01:00
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h"
2015-03-02 22:09:20 +01:00
#include "sleep_queue.h"
2014-12-23 00:31:11 +01:00
2014-12-24 17:09:32 +01:00
sleep_queue_t::~sleep_queue_t()
{
for (auto& tid : m_waiting)
2014-12-24 17:09:32 +01:00
{
LOG_NOTICE(HLE, "~sleep_queue_t['%s']: m_waiting[%lld]=%d", m_name.c_str(), &tid - m_waiting.data(), tid);
}
for (auto& tid : m_signaled)
{
LOG_NOTICE(HLE, "~sleep_queue_t['%s']: m_signaled[%lld]=%d", m_name.c_str(), &tid - m_signaled.data(), tid);
2014-12-24 17:09:32 +01:00
}
}
2014-12-23 00:31:11 +01:00
void sleep_queue_t::push(u32 tid, u32 protocol)
{
2014-12-24 17:09:32 +01:00
assert(tid);
2014-12-23 00:31:11 +01:00
switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK)
{
case SYS_SYNC_FIFO:
case SYS_SYNC_PRIORITY:
{
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& v : m_waiting)
{
if (v == tid)
{
LOG_ERROR(HLE, "sleep_queue_t['%s']::push() failed: thread already waiting (%d)", m_name.c_str(), tid);
Emu.Pause();
return;
}
}
for (auto& v : m_signaled)
2014-12-24 17:09:32 +01:00
{
if (v == tid)
{
LOG_ERROR(HLE, "sleep_queue_t['%s']::push() failed: thread already signaled (%d)", m_name.c_str(), tid);
Emu.Pause();
return;
2014-12-24 17:09:32 +01:00
}
}
m_waiting.push_back(tid);
2014-12-23 00:31:11 +01:00
return;
}
case SYS_SYNC_RETRY:
{
return;
}
}
LOG_ERROR(HLE, "sleep_queue_t['%s']::push() failed: unsupported protocol (0x%x)", m_name.c_str(), protocol);
Emu.Pause();
}
bool sleep_queue_t::pop(u32 tid, u32 protocol)
{
assert(tid);
switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK)
{
case SYS_SYNC_FIFO:
case SYS_SYNC_PRIORITY:
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_signaled.size() && m_signaled[0] == tid)
{
m_signaled.erase(m_signaled.begin());
return true;
}
for (auto& v : m_signaled)
{
if (v == tid)
{
return false;
}
}
for (auto& v : m_waiting)
{
if (v == tid)
{
return false;
}
}
LOG_ERROR(HLE, "sleep_queue_t['%s']::pop() failed: thread not found (%d)", m_name.c_str(), tid);
Emu.Pause();
return true; // ???
}
//case SYS_SYNC_RETRY: // ???
//{
// return true; // ???
//}
}
LOG_ERROR(HLE, "sleep_queue_t['%s']::pop() failed: unsupported protocol (0x%x)", m_name.c_str(), protocol);
2014-12-23 00:31:11 +01:00
Emu.Pause();
return false; // ???
2014-12-23 00:31:11 +01:00
}
u32 sleep_queue_t::signal(u32 protocol)
2014-12-23 00:31:11 +01:00
{
u32 res = ~0;
2014-12-23 00:31:11 +01:00
switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK)
{
case SYS_SYNC_FIFO:
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_waiting.size())
2014-12-23 00:31:11 +01:00
{
res = m_waiting[0];
if (!Emu.GetIdManager().check_id<CPUThread>(res))
2014-12-23 00:31:11 +01:00
{
LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(SYS_SYNC_FIFO) failed: invalid thread (%d)", m_name.c_str(), res);
2014-12-24 17:09:32 +01:00
Emu.Pause();
2014-12-23 00:31:11 +01:00
}
2014-12-24 17:09:32 +01:00
m_waiting.erase(m_waiting.begin());
m_signaled.push_back(res);
2014-12-24 17:09:32 +01:00
}
else
{
res = 0;
2014-12-23 00:31:11 +01:00
}
return res;
2014-12-23 00:31:11 +01:00
}
case SYS_SYNC_PRIORITY:
{
std::lock_guard<std::mutex> lock(m_mutex);
2015-07-01 00:25:52 +02:00
s32 highest_prio = INT32_MAX;
2014-12-24 17:09:32 +01:00
u64 sel = ~0ull;
for (auto& v : m_waiting)
2014-12-23 00:31:11 +01:00
{
2015-07-01 00:25:52 +02:00
if (const auto t = Emu.GetIdManager().get<PPUThread>(v))
2014-12-23 00:31:11 +01:00
{
2015-07-01 00:25:52 +02:00
const s32 prio = t->prio;
2014-12-24 17:09:32 +01:00
if (prio < highest_prio)
2014-12-23 00:31:11 +01:00
{
2014-12-24 17:09:32 +01:00
highest_prio = prio;
sel = &v - m_waiting.data();
2014-12-23 00:31:11 +01:00
}
}
2014-12-24 17:09:32 +01:00
else
{
LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(SYS_SYNC_PRIORITY) failed: invalid thread (%d)", m_name.c_str(), v);
2014-12-24 17:09:32 +01:00
Emu.Pause();
}
}
2014-12-23 00:31:11 +01:00
2014-12-24 17:09:32 +01:00
if (~sel)
{
res = m_waiting[sel];
m_waiting.erase(m_waiting.begin() + sel);
m_signaled.push_back(res);
2014-12-24 17:09:32 +01:00
return res;
2014-12-23 00:31:11 +01:00
}
2014-12-24 17:09:32 +01:00
// fallthrough
2014-12-23 00:31:11 +01:00
}
case SYS_SYNC_RETRY:
{
return 0;
}
}
LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(): unsupported protocol (0x%x)", m_name.c_str(), protocol);
Emu.Pause();
return 0;
}
bool sleep_queue_t::invalidate(u32 tid, u32 protocol)
{
assert(tid);
switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK)
{
case SYS_SYNC_FIFO:
case SYS_SYNC_PRIORITY:
{
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& v : m_waiting)
{
if (v == tid)
{
m_waiting.erase(m_waiting.begin() + (&v - m_waiting.data()));
return true;
}
}
for (auto& v : m_signaled)
{
if (v == tid)
{
2015-01-02 17:02:31 +01:00
if (&v == m_signaled.data())
{
return false; // if the thread is signaled, pop() should be used
}
m_signaled.erase(m_signaled.begin() + (&v - m_signaled.data()));
return true;
}
}
return false;
}
case SYS_SYNC_RETRY:
{
return true;
}
}
LOG_ERROR(HLE, "sleep_queue_t['%s']::invalidate(): unsupported protocol (0x%x)", m_name.c_str(), protocol);
2014-12-23 00:31:11 +01:00
Emu.Pause();
return 0;
}
bool sleep_queue_t::signal_selected(u32 tid)
2014-12-23 00:31:11 +01:00
{
2014-12-24 17:09:32 +01:00
assert(tid);
2014-12-23 00:31:11 +01:00
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& v : m_waiting)
2014-12-23 00:31:11 +01:00
{
2014-12-24 17:09:32 +01:00
if (v == tid)
2014-12-23 00:31:11 +01:00
{
m_waiting.erase(m_waiting.begin() + (&v - m_waiting.data()));
m_signaled.push_back(tid);
2014-12-23 00:31:11 +01:00
return true;
}
}
return false;
}
u32 sleep_queue_t::count()
{
std::lock_guard<std::mutex> lock(m_mutex);
return (u32)m_waiting.size() + (u32)m_signaled.size();
2014-12-23 00:31:11 +01:00
}