2013-12-31 12:10:24 +01:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "Emu/SysCalls/SysCalls.h"
|
|
|
|
|
#include "Emu/SysCalls/SC_FUNC.h"
|
2014-01-12 11:27:59 +01:00
|
|
|
#include <mutex>
|
2013-12-31 12:10:24 +01:00
|
|
|
|
|
|
|
|
void cellSync_init();
|
2014-02-06 23:55:48 +01:00
|
|
|
Module cellSync("cellSync", cellSync_init);
|
2013-12-31 12:10:24 +01:00
|
|
|
|
|
|
|
|
// Return Codes
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
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-01-14 20:03:48 +01:00
|
|
|
#pragma pack(push, 1)
|
2014-02-24 00:40:03 +01:00
|
|
|
struct CellSyncMutex {
|
2014-04-03 13:01:14 +02:00
|
|
|
be_t<u16> m_freed;
|
|
|
|
|
be_t<u16> m_order;
|
|
|
|
|
|
|
|
|
|
volatile u32& m_data()
|
|
|
|
|
{
|
|
|
|
|
return *reinterpret_cast<u32*>(this);
|
|
|
|
|
};
|
2014-01-10 02:30:59 +01:00
|
|
|
/*
|
2014-01-12 11:27:59 +01:00
|
|
|
(???) Initialize: set zeros
|
2014-01-10 02:30:59 +01:00
|
|
|
(???) Lock: increase m_order and wait until m_freed == old m_order
|
|
|
|
|
(???) Unlock: increase m_freed
|
|
|
|
|
(???) TryLock: ?????
|
|
|
|
|
*/
|
|
|
|
|
};
|
2014-01-14 20:03:48 +01:00
|
|
|
#pragma pack(pop)
|
2014-01-10 02:30:59 +01:00
|
|
|
|
|
|
|
|
int cellSyncMutexInitialize(mem_ptr_t<CellSyncMutex> mutex)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
2014-01-07 21:27:34 +01:00
|
|
|
cellSync.Log("cellSyncMutexInitialize(mutex=0x%x)", mutex.GetAddr());
|
2014-01-10 02:30:59 +01:00
|
|
|
|
|
|
|
|
if (!mutex.IsGood())
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_NULL_POINTER;
|
|
|
|
|
}
|
2014-01-10 02:30:59 +01:00
|
|
|
if (mutex.GetAddr() % 4)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_ALIGN;
|
|
|
|
|
}
|
2014-01-12 11:27:59 +01:00
|
|
|
|
2014-04-03 13:01:14 +02:00
|
|
|
mutex->m_data() = 0;
|
|
|
|
|
return CELL_OK;
|
2013-12-31 12:10:24 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-10 02:30:59 +01:00
|
|
|
int cellSyncMutexLock(mem_ptr_t<CellSyncMutex> mutex)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
2014-01-12 11:27:59 +01:00
|
|
|
cellSync.Log("cellSyncMutexLock(mutex=0x%x)", mutex.GetAddr());
|
|
|
|
|
|
2014-01-10 02:30:59 +01:00
|
|
|
if (!mutex.IsGood())
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_NULL_POINTER;
|
|
|
|
|
}
|
2014-01-10 02:30:59 +01:00
|
|
|
if (mutex.GetAddr() % 4)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_ALIGN;
|
|
|
|
|
}
|
2014-01-10 02:30:59 +01:00
|
|
|
|
|
|
|
|
be_t<u16> old_order;
|
2014-04-03 13:01:14 +02:00
|
|
|
while (true)
|
2014-02-06 23:55:48 +01:00
|
|
|
{
|
2014-04-03 13:01:14 +02:00
|
|
|
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;
|
2014-01-10 02:30:59 +01:00
|
|
|
}
|
2014-01-12 11:27:59 +01:00
|
|
|
|
2014-04-03 13:01:14 +02:00
|
|
|
while (old_order != mutex->m_freed)
|
2014-01-12 11:27:59 +01:00
|
|
|
{
|
|
|
|
|
Sleep(1);
|
2014-02-15 22:16:35 +01:00
|
|
|
if (Emu.IsStopped())
|
2014-01-12 11:27:59 +01:00
|
|
|
{
|
2014-02-15 22:16:35 +01:00
|
|
|
ConLog.Warning("cellSyncMutexLock(mutex=0x%x) aborted", mutex.GetAddr());
|
|
|
|
|
break;
|
2014-01-12 11:27:59 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-14 20:03:48 +01:00
|
|
|
_mm_mfence();
|
2013-12-31 12:10:24 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-10 02:30:59 +01:00
|
|
|
int cellSyncMutexTryLock(mem_ptr_t<CellSyncMutex> mutex)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
2014-01-12 11:27:59 +01:00
|
|
|
cellSync.Log("cellSyncMutexTryLock(mutex=0x%x)", mutex.GetAddr());
|
|
|
|
|
|
2014-01-10 02:30:59 +01:00
|
|
|
if (!mutex.IsGood())
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_NULL_POINTER;
|
|
|
|
|
}
|
2014-01-10 02:30:59 +01:00
|
|
|
if (mutex.GetAddr() % 4)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_ALIGN;
|
|
|
|
|
}
|
2014-04-03 13:01:14 +02:00
|
|
|
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
while (true)
|
2014-02-06 23:55:48 +01:00
|
|
|
{
|
2014-04-03 13:01:14 +02:00
|
|
|
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)
|
2014-02-06 23:55:48 +01:00
|
|
|
{
|
2014-04-03 13:01:14 +02:00
|
|
|
res = CELL_SYNC_ERROR_BUSY;
|
2014-02-06 23:55:48 +01:00
|
|
|
}
|
2014-04-03 13:01:14 +02:00
|
|
|
else
|
2014-01-12 11:27:59 +01:00
|
|
|
{
|
2014-04-03 13:01:14 +02:00
|
|
|
new_mutex.m_order++;
|
|
|
|
|
res = CELL_OK;
|
2014-01-12 11:27:59 +01:00
|
|
|
}
|
2014-04-03 13:01:14 +02:00
|
|
|
if (InterlockedCompareExchange(&mutex->m_data(), new_mutex.m_data(), old_data) == old_data) break;
|
2013-12-31 12:10:24 +01:00
|
|
|
}
|
2014-04-03 13:01:14 +02:00
|
|
|
|
|
|
|
|
return res;
|
2013-12-31 12:10:24 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-10 02:30:59 +01:00
|
|
|
int cellSyncMutexUnlock(mem_ptr_t<CellSyncMutex> mutex)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
2014-01-12 11:27:59 +01:00
|
|
|
cellSync.Log("cellSyncMutexUnlock(mutex=0x%x)", mutex.GetAddr());
|
|
|
|
|
|
2014-01-10 02:30:59 +01:00
|
|
|
if (!mutex.IsGood())
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_NULL_POINTER;
|
|
|
|
|
}
|
2014-01-10 02:30:59 +01:00
|
|
|
if (mutex.GetAddr() % 4)
|
2013-12-31 12:10:24 +01:00
|
|
|
{
|
|
|
|
|
return CELL_SYNC_ERROR_ALIGN;
|
|
|
|
|
}
|
2014-01-10 02:30:59 +01:00
|
|
|
|
2014-04-03 13:01:14 +02:00
|
|
|
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;
|
2014-01-12 11:27:59 +01:00
|
|
|
}
|
2014-04-03 13:01:14 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
2013-12-31 12:10:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cellSync_init()
|
|
|
|
|
{
|
|
|
|
|
cellSync.AddFunc(0xa9072dee, cellSyncMutexInitialize);
|
|
|
|
|
cellSync.AddFunc(0x1bb675c2, cellSyncMutexLock);
|
|
|
|
|
cellSync.AddFunc(0xd06918c4, cellSyncMutexTryLock);
|
|
|
|
|
cellSync.AddFunc(0x91f2b7b0, cellSyncMutexUnlock);
|
2014-02-23 17:52:52 +01:00
|
|
|
}
|