rpcsx/rpcs3/Emu/SysCalls/Modules/cellSync.cpp

171 lines
3.7 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
//void cellSync_init();
//Module cellSync("cellSync", cellSync_init);
Module *cellSync = nullptr;
// Return Codes
enum
{
2014-04-04 15:25:38 +02:00
CELL_SYNC_ERROR_AGAIN = 0x80410101,
CELL_SYNC_ERROR_INVAL = 0x80410102,
CELL_SYNC_ERROR_NOMEM = 0x80410104,
CELL_SYNC_ERROR_DEADLK = 0x80410108,
CELL_SYNC_ERROR_PERM = 0x80410109,
CELL_SYNC_ERROR_BUSY = 0x8041010A,
CELL_SYNC_ERROR_STAT = 0x8041010F,
CELL_SYNC_ERROR_ALIGN = 0x80410110,
CELL_SYNC_ERROR_NULL_POINTER = 0x80410111,
CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD = 0x80410112,
CELL_SYNC_ERROR_NO_NOTIFIER = 0x80410113,
CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114,
};
2014-04-04 16:43:43 +02:00
struct CellSyncMutex
{
be_t<u16> m_freed;
be_t<u16> m_order;
volatile u32& m_data()
{
return *reinterpret_cast<u32*>(this);
};
/*
(???) Initialize: set zeros
(???) Lock: increase m_order and wait until m_freed == old m_order
(???) Unlock: increase m_freed
(???) TryLock: ?????
*/
};
2014-04-04 16:43:43 +02:00
static_assert(sizeof(CellSyncMutex) == 4, "CellSyncMutex: wrong sizeof");
int cellSyncMutexInitialize(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync->Log("cellSyncMutexInitialize(mutex=0x%x)", mutex.GetAddr());
if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
mutex->m_data() = 0;
return CELL_OK;
}
int cellSyncMutexLock(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync->Log("cellSyncMutexLock(mutex=0x%x)", mutex.GetAddr());
if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
be_t<u16> old_order;
while (true)
{
const u32 old_data = mutex->m_data();
CellSyncMutex new_mutex;
new_mutex.m_data() = old_data;
old_order = new_mutex.m_order;
new_mutex.m_order++;
if (InterlockedCompareExchange(&mutex->m_data(), new_mutex.m_data(), old_data) == old_data) break;
}
while (old_order != mutex->m_freed)
{
2014-07-12 09:02:39 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2014-02-15 22:16:35 +01:00
if (Emu.IsStopped())
{
LOG_WARNING(HLE, "cellSyncMutexLock(mutex=0x%x) aborted", mutex.GetAddr());
2014-02-15 22:16:35 +01:00
break;
}
}
_mm_mfence();
return CELL_OK;
}
int cellSyncMutexTryLock(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync->Log("cellSyncMutexTryLock(mutex=0x%x)", mutex.GetAddr());
if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
int res;
while (true)
{
const u32 old_data = mutex->m_data();
CellSyncMutex new_mutex;
new_mutex.m_data() = old_data;
if (new_mutex.m_order != new_mutex.m_freed)
{
res = CELL_SYNC_ERROR_BUSY;
}
else
{
new_mutex.m_order++;
res = CELL_OK;
}
if (InterlockedCompareExchange(&mutex->m_data(), new_mutex.m_data(), old_data) == old_data) break;
}
return res;
}
int cellSyncMutexUnlock(mem_ptr_t<CellSyncMutex> mutex)
{
cellSync->Log("cellSyncMutexUnlock(mutex=0x%x)", mutex.GetAddr());
if (!mutex.IsGood())
{
return CELL_SYNC_ERROR_NULL_POINTER;
}
if (mutex.GetAddr() % 4)
{
return CELL_SYNC_ERROR_ALIGN;
}
while (true)
{
const u32 old_data = mutex->m_data();
CellSyncMutex new_mutex;
new_mutex.m_data() = old_data;
new_mutex.m_freed++;
if (InterlockedCompareExchange(&mutex->m_data(), new_mutex.m_data(), old_data) == old_data) break;
}
return CELL_OK;
}
void cellSync_init()
{
cellSync->AddFunc(0xa9072dee, cellSyncMutexInitialize);
cellSync->AddFunc(0x1bb675c2, cellSyncMutexLock);
cellSync->AddFunc(0xd06918c4, cellSyncMutexTryLock);
cellSync->AddFunc(0x91f2b7b0, cellSyncMutexUnlock);
}