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()
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
for (auto& tid : m_waiting)
|
2014-12-24 17:09:32 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +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);
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
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)
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
m_waiting.push_back(tid);
|
2014-12-23 00:31:11 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case SYS_SYNC_RETRY:
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
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();
|
2015-01-02 00:41:29 +01:00
|
|
|
return false; // ???
|
2014-12-23 00:31:11 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
u32 sleep_queue_t::signal(u32 protocol)
|
2014-12-23 00:31:11 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +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);
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
if (m_waiting.size())
|
2014-12-23 00:31:11 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
res = m_waiting[0];
|
2015-05-27 05:11:59 +02:00
|
|
|
if (!Emu.GetIdManager().check_id<CPUThread>(res))
|
2014-12-23 00:31:11 +01:00
|
|
|
{
|
2015-01-02 00:41:29 +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
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
m_waiting.erase(m_waiting.begin());
|
|
|
|
|
m_signaled.push_back(res);
|
2014-12-24 17:09:32 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
res = 0;
|
2014-12-23 00:31:11 +01:00
|
|
|
}
|
2015-01-02 00:41:29 +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;
|
2015-01-02 00:41:29 +01:00
|
|
|
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;
|
2015-01-02 00:41:29 +01:00
|
|
|
sel = &v - m_waiting.data();
|
2014-12-23 00:31:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-12-24 17:09:32 +01:00
|
|
|
else
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
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)
|
|
|
|
|
{
|
2015-01-02 00:41:29 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
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
|
|
|
|
|
}
|
2015-01-02 00:41:29 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
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);
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
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
|
|
|
{
|
2015-01-02 00:41:29 +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);
|
|
|
|
|
|
2015-01-02 00:41:29 +01:00
|
|
|
return (u32)m_waiting.size() + (u32)m_signaled.size();
|
2014-12-23 00:31:11 +01:00
|
|
|
}
|