mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-05 15:40:10 +00:00
commit
31c0687fc0
@ -1209,9 +1209,9 @@ private:
|
||||
}
|
||||
void VPERM(u32 vd, u32 va, u32 vb, u32 vc)
|
||||
{
|
||||
u8 tmpSRC[32];
|
||||
memcpy(tmpSRC, CPU.VPR[vb]._u8, 16);
|
||||
memcpy(tmpSRC + 16, CPU.VPR[va]._u8, 16);
|
||||
u8 tmpSRC[32];
|
||||
memcpy(tmpSRC, CPU.VPR[vb]._u8, 16);
|
||||
memcpy(tmpSRC + 16, CPU.VPR[va]._u8, 16);
|
||||
|
||||
for (uint b = 0; b < 16; b++)
|
||||
{
|
||||
@ -1556,23 +1556,14 @@ private:
|
||||
}
|
||||
void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh)
|
||||
{
|
||||
u8 tmpSRC[32];
|
||||
memcpy(tmpSRC, CPU.VPR[vb]._u8, 16);
|
||||
memcpy(tmpSRC + 16, CPU.VPR[va]._u8, 16);
|
||||
u8 tmpSRC[32];
|
||||
memcpy(tmpSRC, CPU.VPR[vb]._u8, 16);
|
||||
memcpy(tmpSRC + 16, CPU.VPR[va]._u8, 16);
|
||||
|
||||
for(uint b=0; b<16; b++)
|
||||
{
|
||||
CPU.VPR[vd]._u8[15 - b] = tmpSRC[31 - (b + sh)];
|
||||
}
|
||||
|
||||
/*for (uint b = 0; b < 16 - sh; b++)
|
||||
for(uint b=0; b<16; b++)
|
||||
{
|
||||
CPU.VPR[vd]._u8[15 - b] = CPU.VPR[va]._u8[15 - (b + sh)];
|
||||
CPU.VPR[vd]._u8[15 - b] = tmpSRC[31 - (b + sh)];
|
||||
}
|
||||
for (uint b = 16 - sh; b < 16; b++)
|
||||
{
|
||||
CPU.VPR[vd]._u8[15 - b] = CPU.VPR[vb]._u8[15 - (b - (16 - sh))];
|
||||
}*/
|
||||
}
|
||||
void VSLH(u32 vd, u32 va, u32 vb)
|
||||
{
|
||||
|
@ -1,11 +1,13 @@
|
||||
#include "stdafx.h"
|
||||
#include "SysCalls.h"
|
||||
#include "SC_FUNC.h"
|
||||
#include <mutex>
|
||||
|
||||
Module* g_modules[3][0xff] = {0};
|
||||
uint g_max_module_id = 0;
|
||||
uint g_module_2_count = 0;
|
||||
ArrayF<ModuleFunc> g_modules_funcs_list;
|
||||
std::mutex g_funcs_lock;
|
||||
|
||||
struct ModuleInfo
|
||||
{
|
||||
@ -142,20 +144,31 @@ bool IsLoadedFunc(u32 id)
|
||||
|
||||
bool CallFunc(u32 num)
|
||||
{
|
||||
for(u32 i=0; i<g_modules_funcs_list.GetCount(); ++i)
|
||||
func_caller* func = nullptr;
|
||||
{
|
||||
if(g_modules_funcs_list[i].id == num)
|
||||
std::lock_guard<std::mutex> lock(g_funcs_lock);
|
||||
|
||||
for(u32 i=0; i<g_modules_funcs_list.GetCount(); ++i)
|
||||
{
|
||||
(*g_modules_funcs_list[i].func)();
|
||||
return true;
|
||||
if(g_modules_funcs_list[i].id == num)
|
||||
{
|
||||
func = g_modules_funcs_list[i].func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (func)
|
||||
{
|
||||
(*func)();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnloadFunc(u32 id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_funcs_lock);
|
||||
|
||||
for(u32 i=0; i<g_modules_funcs_list.GetCount(); ++i)
|
||||
{
|
||||
if(g_modules_funcs_list[i].id == id)
|
||||
@ -187,6 +200,7 @@ void UnloadModules()
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_funcs_lock);
|
||||
g_modules_funcs_list.Clear();
|
||||
}
|
||||
|
||||
@ -318,8 +332,10 @@ void Module::Load()
|
||||
|
||||
for(u32 i=0; i<m_funcs_list.GetCount(); ++i)
|
||||
{
|
||||
if(IsLoadedFunc(m_funcs_list[i].id)) continue;
|
||||
std::lock_guard<std::mutex> lock(g_funcs_lock);
|
||||
|
||||
if(IsLoadedFunc(m_funcs_list[i].id)) continue;
|
||||
|
||||
g_modules_funcs_list.Add(m_funcs_list[i]);
|
||||
}
|
||||
|
||||
@ -343,6 +359,8 @@ void Module::UnLoad()
|
||||
|
||||
bool Module::Load(u32 id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_funcs_lock);
|
||||
|
||||
if(IsLoadedFunc(id)) return false;
|
||||
|
||||
for(u32 i=0; i<m_funcs_list.GetCount(); ++i)
|
||||
|
@ -365,6 +365,8 @@ int cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, mem_ptr_t<CellCodecEsFilterId
|
||||
|
||||
int cellPamfReaderGetStreamIndex(mem_ptr_t<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf.Log("cellPamfReaderGetStreamIndex(pSelf=0x%x)", pSelf.GetAddr());
|
||||
|
||||
return pSelf->stream;
|
||||
}
|
||||
|
||||
@ -506,7 +508,7 @@ int cellPamfReaderGetNumberOfEp(mem_ptr_t<CellPamfReader> pSelf)
|
||||
|
||||
int cellPamfReaderGetEpIteratorWithIndex(mem_ptr_t<CellPamfReader> pSelf, u32 epIndex, mem_ptr_t<CellPamfEpIterator> pIt)
|
||||
{
|
||||
cellPamf.Warning("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x (stream=%d), epIndex=%d, pIt_addr=0x%x)",
|
||||
cellPamf.Error("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x (stream=%d), epIndex=%d, pIt_addr=0x%x)",
|
||||
pSelf.GetAddr(), pSelf->stream, epIndex, pIt.GetAddr());
|
||||
|
||||
const mem_ptr_t<PamfHeader> pAddr(pSelf->pAddr);
|
||||
@ -516,19 +518,25 @@ int cellPamfReaderGetEpIteratorWithIndex(mem_ptr_t<CellPamfReader> pSelf, u32 ep
|
||||
|
||||
int cellPamfReaderGetEpIteratorWithTimeStamp(mem_ptr_t<CellPamfReader> pSelf, mem_ptr_t<CellCodecTimeStamp> pTimeStamp, mem_ptr_t<CellPamfEpIterator> pIt)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellPamf);
|
||||
cellPamf.Error("cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=0x%x, pTimeStamp_addr=0x%x, pIt_addr=0x%x)",
|
||||
pSelf.GetAddr(), pTimeStamp.GetAddr(), pIt.GetAddr());
|
||||
|
||||
const mem_ptr_t<PamfHeader> pAddr(pSelf->pAddr);
|
||||
//TODO:
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfEpIteratorGetEp(mem_ptr_t<CellPamfEpIterator> pIt, mem_ptr_t<CellPamfEp> pEp)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellPamf);
|
||||
cellPamf.Error("cellPamfEpIteratorGetEp(pIt_addr=0x%x, pEp_addr=0x%x)", pIt.GetAddr(), pEp.GetAddr());
|
||||
//TODO:
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfEpIteratorMove(mem_ptr_t<CellPamfEpIterator> pIt, int steps, mem_ptr_t<CellPamfEp> pEp)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellPamf);
|
||||
cellPamf.Error("cellPamfEpIteratorMove(pIt_addr=0x%x, steps=%d, pEp_addr=0x%x)", pIt.GetAddr(), steps, pEp.GetAddr());
|
||||
//TODO:
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,10 @@ int cellSyncMutexLock(mem_ptr_t<CellSyncMutex> mutex)
|
||||
std::lock_guard<std::mutex> lock(g_SyncMutex);
|
||||
old_order = mutex->m_order;
|
||||
mutex->m_order = mutex->m_order + 1;
|
||||
if (old_order == mutex->m_freed)
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
@ -89,10 +93,9 @@ int cellSyncMutexLock(mem_ptr_t<CellSyncMutex> mutex)
|
||||
Sleep(1);
|
||||
if (++counter >= 5000)
|
||||
{
|
||||
Emu.Pause();
|
||||
cellSync.Error("cellSyncMutexLock(mutex=0x%x, old_order=%d, order=%d, freed=%d): TIMEOUT",
|
||||
counter = 0;
|
||||
cellSync.Warning("cellSyncMutexLock(mutex=0x%x, old_order=%d, order=%d, freed=%d): TIMEOUT",
|
||||
mutex.GetAddr(), (u16)old_order, (u16)mutex->m_order, (u16)mutex->m_freed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//while (_InterlockedExchange((volatile long*)&mutex->m_data, 1)) Sleep(1);
|
||||
|
@ -457,7 +457,7 @@ int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 as
|
||||
|
||||
int cellSysutilCheckCallback()
|
||||
{
|
||||
cellSysutil.Warning("cellSysutilCheckCallback()");
|
||||
cellSysutil.Log("cellSysutilCheckCallback()");
|
||||
Emu.GetCallbackManager().m_exit_callback.Check();
|
||||
|
||||
return CELL_OK;
|
||||
@ -667,7 +667,7 @@ int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
|
||||
|
||||
switch(audioOut)
|
||||
{
|
||||
case CELL_AUDIO_OUT_PRIMARY: return 1;
|
||||
case CELL_AUDIO_OUT_PRIMARY: return 2;
|
||||
case CELL_AUDIO_OUT_SECONDARY: return 0;
|
||||
}
|
||||
|
||||
|
@ -175,4 +175,11 @@ void sysPrxForUser_init()
|
||||
|
||||
sysPrxForUser.AddFunc(0x893305fa, sys_raw_spu_load);
|
||||
sysPrxForUser.AddFunc(0xb995662e, sys_raw_spu_image_load);
|
||||
|
||||
sysPrxForUser.AddFunc(0xda0eb71a, sys_lwcond_create);
|
||||
sysPrxForUser.AddFunc(0x1c9a942c, sys_lwcond_destroy);
|
||||
sysPrxForUser.AddFunc(0xef87a695, sys_lwcond_signal);
|
||||
sysPrxForUser.AddFunc(0xe9a1bd84, sys_lwcond_signal_all);
|
||||
sysPrxForUser.AddFunc(0x52aadadf, sys_lwcond_signal_to);
|
||||
sysPrxForUser.AddFunc(0x2a6d9d51, sys_lwcond_wait);
|
||||
}
|
||||
|
@ -2,19 +2,40 @@
|
||||
|
||||
#define RESULT(x) SC_ARGS_1 = (x)
|
||||
|
||||
template<bool is_fp, bool is_ptr, typename T>
|
||||
template<bool is_in_sp, bool is_fp, bool is_ptr, typename T, int i>
|
||||
struct get_arg;
|
||||
|
||||
template<typename T>
|
||||
struct get_arg<false, false, T> { static __forceinline T func(PPUThread& CPU, int i) { return (T&)CPU.GPR[i + 2]; } };
|
||||
template<typename T, int i>
|
||||
struct get_arg<false, false, false, T, i> // not fp, not ptr, 1..8
|
||||
{
|
||||
static __forceinline T func(PPUThread& CPU) { return (T&)CPU.GPR[i + 2]; }
|
||||
};
|
||||
|
||||
template<bool is_fp, typename T>
|
||||
struct get_arg<is_fp, true, T> { static __forceinline T func(PPUThread& CPU, int i) { return CPU.GPR[i + 2] ? (T)&Memory[CPU.GPR[i + 2]] : nullptr; } };
|
||||
template<bool is_fp, typename T, int i>
|
||||
struct get_arg<false, is_fp, true, T, i> // ptr, 1..8
|
||||
{
|
||||
static __forceinline T func(PPUThread& CPU) { return CPU.GPR[i + 2] ? (T)&Memory[CPU.GPR[i + 2]] : nullptr; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct get_arg<true, false, T> { static __forceinline T func(PPUThread& CPU, int i) { return CPU.FPR[i]; } };
|
||||
template<bool is_in_sp, typename T, int i>
|
||||
struct get_arg<is_in_sp, true, false, T, i> // fp, 1..12
|
||||
{
|
||||
static __forceinline T func(PPUThread& CPU) { return CPU.FPR[i]; }
|
||||
};
|
||||
|
||||
#define ARG(n) get_arg<std::is_floating_point<T##n>::value, std::is_pointer<T##n>::value, T##n>::func(CPU, n)
|
||||
template<typename T, int i>
|
||||
struct get_arg<true, false, false, T, i> // not fp, not ptr, 9..12
|
||||
{
|
||||
static __forceinline T func(PPUThread& CPU) { u64 res = Memory.Read64(CPU.GPR[1] + 0x70 + 0x8 * (i - 9)); return (T&)res; }
|
||||
};
|
||||
|
||||
template<bool is_fp, typename T, int i>
|
||||
struct get_arg<true, is_fp, true, T, i> // ptr, 9..12
|
||||
{
|
||||
static __forceinline T func(PPUThread& CPU) { u64 addr = Memory.Read64(CPU.GPR[1] + 0x70 + 0x8 * (i - 9)); return addr ? (T)&Memory[addr] : nullptr; }
|
||||
};
|
||||
|
||||
#define ARG(n) get_arg<((n) > 8), std::is_floating_point<T##n>::value, std::is_pointer<T##n>::value, T##n, n>::func(CPU)
|
||||
|
||||
template<typename TR>
|
||||
class binder_func_0 : public func_caller
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "lv2/SC_Rwlock.h"
|
||||
#include "lv2/SC_SPU_Thread.h"
|
||||
#include "lv2/SC_Lwmutex.h"
|
||||
#include "lv2/SC_Lwcond.h"
|
||||
#include "Emu/event.h"
|
||||
//#define SYSCALLS_DEBUG
|
||||
|
||||
@ -147,6 +148,14 @@ extern int sys_semaphore_trywait(u32 sem);
|
||||
extern int sys_semaphore_post(u32 sem, int count);
|
||||
extern int sys_semaphore_get_value(u32 sem, u32 count_addr);
|
||||
|
||||
//sys_lwcond
|
||||
extern int sys_lwcond_create(mem_ptr_t<sys_lwcond_t> lwcond, mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwcond_attribute_t> attr);
|
||||
extern int sys_lwcond_destroy(mem_ptr_t<sys_lwcond_t> lwcond);
|
||||
extern int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond);
|
||||
extern int sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_t> lwcond);
|
||||
extern int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id);
|
||||
extern int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout);
|
||||
|
||||
//sys_lwmutex
|
||||
extern int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_attribute_t> attr);
|
||||
extern int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex);
|
||||
@ -367,10 +376,12 @@ extern int sys_rsx_attribute();
|
||||
#define SC_ARG_5 CPU.GPR[8]
|
||||
#define SC_ARG_6 CPU.GPR[9]
|
||||
#define SC_ARG_7 CPU.GPR[10]
|
||||
/* // these definitions are wrong:
|
||||
#define SC_ARG_8 CPU.GPR[11]
|
||||
#define SC_ARG_9 CPU.GPR[12]
|
||||
#define SC_ARG_10 CPU.GPR[13]
|
||||
#define SC_ARG_11 CPU.GPR[14]
|
||||
*/
|
||||
|
||||
#define SC_ARGS_1 SC_ARG_0
|
||||
#define SC_ARGS_2 SC_ARGS_1,SC_ARG_1
|
||||
@ -380,10 +391,12 @@ extern int sys_rsx_attribute();
|
||||
#define SC_ARGS_6 SC_ARGS_5,SC_ARG_5
|
||||
#define SC_ARGS_7 SC_ARGS_6,SC_ARG_6
|
||||
#define SC_ARGS_8 SC_ARGS_7,SC_ARG_7
|
||||
/*
|
||||
#define SC_ARGS_9 SC_ARGS_8,SC_ARG_8
|
||||
#define SC_ARGS_10 SC_ARGS_9,SC_ARG_9
|
||||
#define SC_ARGS_11 SC_ARGS_10,SC_ARG_10
|
||||
#define SC_ARGS_12 SC_ARGS_11,SC_ARG_11
|
||||
*/
|
||||
|
||||
extern bool dump_enable;
|
||||
|
||||
|
131
rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp
Normal file
131
rpcs3/Emu/SysCalls/lv2/SC_Lwcond.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "SC_Lwmutex.h"
|
||||
#include "SC_Lwcond.h"
|
||||
|
||||
SysCallBase sys_lwcond("sys_lwcond");
|
||||
|
||||
int sys_lwcond_create(mem_ptr_t<sys_lwcond_t> lwcond, mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwcond_attribute_t> attr)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)",
|
||||
lwcond.GetAddr(), lwmutex.GetAddr(), attr.GetAddr());
|
||||
|
||||
if (!lwcond.IsGood() || !lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT;
|
||||
|
||||
u32 protocol = (u32)lwmutex->attribute & SYS_SYNC_ATTR_PROTOCOL_MASK;
|
||||
switch (protocol)
|
||||
{
|
||||
case SYS_SYNC_PRIORITY: break;
|
||||
case SYS_SYNC_RETRY: sys_lwcond.Error("Invalid SYS_SYNC_RETRY attr"); break;
|
||||
case SYS_SYNC_PRIORITY_INHERIT: sys_lwcond.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break;
|
||||
case SYS_SYNC_FIFO: break;
|
||||
default: sys_lwcond.Error("Invalid lwmutex protocol(%d)", protocol); break;
|
||||
}
|
||||
|
||||
lwcond->lwmutex_addr = lwmutex.GetAddr();
|
||||
lwcond->lwcond_queue = sys_lwcond.GetNewId(new LWCond(protocol, *(u64*)&attr->name));
|
||||
|
||||
sys_lwcond.Warning("*** lwcond created [%s] (protocol=0x%x): id=%d", attr->name, protocol, (u32)lwcond->lwcond_queue);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_lwcond_destroy(mem_ptr_t<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.GetAddr());
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
|
||||
Emu.GetIdManager().RemoveID(id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr());
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
|
||||
lwc->signal();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.GetAddr());
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
|
||||
lwc->signal_all();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id);
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
|
||||
if (!lwc->signal_to(ppu_thread_id)) return CELL_EPERM;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%llu)", lwcond.GetAddr(), timeout);
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
const u32 tid = GetCurrentPPUThread().GetId();
|
||||
mem_ptr_t<sys_lwmutex_t> lwmutex((u32)lwcond->lwmutex_addr);
|
||||
|
||||
if ((u32)lwmutex->owner != tid) return CELL_EPERM; // caller must own this lwmutex
|
||||
lwc->begin_waiting(tid);
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
||||
bool was_locked = true;
|
||||
do
|
||||
{
|
||||
if (Emu.IsStopped()) return CELL_ETIMEDOUT;
|
||||
if (was_locked) lwmutex->unlock(tid);
|
||||
Sleep(1);
|
||||
if (was_locked = (lwmutex->trylock(tid) == CELL_OK))
|
||||
{
|
||||
if (lwc->check(tid))
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_wait(lwcond_addr=0x%x): TIMEOUT", lwcond.GetAddr());
|
||||
counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lwc->stop_waiting(tid);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
}
|
118
rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h
Normal file
118
rpcs3/Emu/SysCalls/lv2/SC_Lwcond.h
Normal file
@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
|
||||
struct sys_lwcond_attribute_t
|
||||
{
|
||||
char name[8];
|
||||
};
|
||||
|
||||
struct sys_lwcond_t
|
||||
{
|
||||
be_t<u32> lwmutex_addr;
|
||||
be_t<u32> lwcond_queue;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
struct LWCond
|
||||
{
|
||||
std::mutex m_lock;
|
||||
Array<u32> waiters; // list of waiting threads
|
||||
Array<u32> signaled; // list of signaled threads
|
||||
u32 m_protocol; // protocol
|
||||
u64 m_name; // not used
|
||||
|
||||
LWCond(u32 prot, u64 name)
|
||||
: m_name(name)
|
||||
, m_protocol(prot)
|
||||
{
|
||||
}
|
||||
|
||||
void signal()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
if (waiters.GetCount())
|
||||
{
|
||||
if (m_protocol == SYS_SYNC_PRIORITY)
|
||||
{
|
||||
u64 max_prio = 0;
|
||||
u32 sel = 0;
|
||||
for (u32 i = 0; i < waiters.GetCount(); i++)
|
||||
{
|
||||
CPUThread* t = Emu.GetCPU().GetThread(waiters[i]);
|
||||
if (!t) continue;
|
||||
|
||||
u64 prio = t->GetPrio();
|
||||
if (prio > max_prio)
|
||||
{
|
||||
max_prio = prio;
|
||||
sel = i;
|
||||
}
|
||||
}
|
||||
signaled.AddCpy(waiters[sel]);
|
||||
waiters.RemoveAt(sel);
|
||||
}
|
||||
else // SYS_SYNC_FIFO
|
||||
{
|
||||
signaled.AddCpy(waiters[0]);
|
||||
waiters.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void signal_all()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
signaled.AppendFrom(waiters); // "nobody cares" protocol (!)
|
||||
waiters.Clear();
|
||||
}
|
||||
|
||||
bool signal_to(u32 id) // returns false if not found
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
for (u32 i = waiters.GetCount() - 1; ~i; i--)
|
||||
{
|
||||
if (waiters[i] == id)
|
||||
{
|
||||
waiters.RemoveAt(i);
|
||||
signaled.AddCpy(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void begin_waiting(u32 id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
waiters.AddCpy(id);
|
||||
}
|
||||
|
||||
void stop_waiting(u32 id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
for (u32 i = waiters.GetCount() - 1; ~i; i--)
|
||||
{
|
||||
if (waiters[i] == id)
|
||||
{
|
||||
waiters.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool check(u32 id) // returns true if signaled
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
for (u32 i = signaled.GetCount() - 1; ~i; i--)
|
||||
{
|
||||
if (signaled[i] == id)
|
||||
{
|
||||
signaled.RemoveAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
@ -9,7 +9,7 @@ std::mutex g_lwmutex;
|
||||
|
||||
int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_attribute_t> attr)
|
||||
{
|
||||
sc_lwmutex.Log("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)",
|
||||
sc_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)",
|
||||
lwmutex.GetAddr(), attr.GetAddr());
|
||||
|
||||
if (!lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT;
|
||||
@ -23,10 +23,10 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
|
||||
|
||||
switch ((u32)attr->attr_protocol)
|
||||
{
|
||||
case SYS_SYNC_PRIORITY: break;
|
||||
case SYS_SYNC_RETRY: sc_lwmutex.Error("TODO: SYS_SYNC_RETRY attr"); break;
|
||||
case SYS_SYNC_PRIORITY_INHERIT: sc_lwmutex.Error("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break;
|
||||
case SYS_SYNC_FIFO: sc_lwmutex.Error("TODO: SYS_SYNC_FIFO attr"); break;
|
||||
case SYS_SYNC_PRIORITY: sc_lwmutex.Warning("TODO: SYS_SYNC_PRIORITY attr"); break;
|
||||
case SYS_SYNC_RETRY: sc_lwmutex.Warning("TODO: SYS_SYNC_RETRY attr"); break;
|
||||
case SYS_SYNC_PRIORITY_INHERIT: sc_lwmutex.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break;
|
||||
case SYS_SYNC_FIFO: sc_lwmutex.Warning("TODO: SYS_SYNC_FIFO attr"); break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
@ -36,8 +36,7 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
|
||||
lwmutex->recursive_count = 0;
|
||||
lwmutex->sleep_queue = 0;
|
||||
|
||||
sc_lwmutex.Log("*** lwmutex created [%s] (protocol=0x%x, recursive=0x%x)",
|
||||
attr->name, (u32)attr->attr_protocol, (u32)attr->attr_recursive);
|
||||
sc_lwmutex.Warning("*** lwmutex created [%s] (attribute=0x%x): id=???", attr->name, (u32)lwmutex->attribute);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -46,71 +45,57 @@ int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sc_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
||||
|
||||
if (!lwmutex.IsGood()) return CELL_EFAULT;
|
||||
|
||||
if (!lwmutex->attribute) return CELL_EINVAL;
|
||||
|
||||
{ // global lock
|
||||
std::lock_guard<std::mutex> lock(g_lwmutex);
|
||||
|
||||
if (!lwmutex->owner)
|
||||
{
|
||||
lwmutex->owner = ~0; // make it unable to lock
|
||||
lwmutex->attribute = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_lwmutex_lock(mem_ptr_t<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
{
|
||||
sc_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.GetAddr(), timeout);
|
||||
sc_lwmutex.Warning("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.GetAddr(), timeout);
|
||||
|
||||
if (!lwmutex.IsGood()) return CELL_EFAULT;
|
||||
|
||||
PPCThread& thr = GetCurrentPPUThread();
|
||||
const u32 id = thr.GetId();
|
||||
if (!lwmutex->attribute) return CELL_EINVAL;
|
||||
|
||||
{ // global lock
|
||||
std::lock_guard<std::mutex> lock(g_lwmutex);
|
||||
const u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
if ((u32)lwmutex->attribute & SYS_SYNC_RECURSIVE)
|
||||
{
|
||||
if (id == (u32)lwmutex->owner)
|
||||
{
|
||||
lwmutex->recursive_count = lwmutex->recursive_count + 1;
|
||||
if (lwmutex->recursive_count == 0xffffffff) return CELL_EKRESOURCE;
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
else // recursive not allowed
|
||||
{
|
||||
if (id == (u32)lwmutex->owner)
|
||||
{
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lwmutex->owner) // lock
|
||||
{
|
||||
lwmutex->owner = id;
|
||||
lwmutex->recursive_count = 1;
|
||||
return CELL_OK;
|
||||
}
|
||||
lwmutex->waiter = id; // not used yet
|
||||
}
|
||||
int res = lwmutex->trylock(tid);
|
||||
if (res != CELL_EBUSY) return res;
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
||||
do // waiting
|
||||
{
|
||||
if (Emu.IsStopped()) return CELL_ETIMEDOUT;
|
||||
Sleep(1);
|
||||
|
||||
{ // global lock
|
||||
std::lock_guard<std::mutex> lock(g_lwmutex);
|
||||
|
||||
if (!lwmutex->owner) // lock
|
||||
{
|
||||
lwmutex->owner = id;
|
||||
lwmutex->recursive_count = 1;
|
||||
return CELL_OK;
|
||||
}
|
||||
lwmutex->waiter = id; // not used yet
|
||||
}
|
||||
res = lwmutex->trylock(tid);
|
||||
if (res != CELL_EBUSY) return res;
|
||||
if (!lwmutex->attribute) return CELL_EINVAL;
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
if (!timeout)
|
||||
{ // endless waiter
|
||||
sc_lwmutex.Error("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr());
|
||||
return CELL_OK;
|
||||
{
|
||||
sc_lwmutex.Warning("sys_lwmutex_lock(lwmutex_addr=0x%x): TIMEOUT", lwmutex.GetAddr());
|
||||
counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -122,77 +107,23 @@ int sys_lwmutex_lock(mem_ptr_t<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
|
||||
int sys_lwmutex_trylock(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sc_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
||||
sc_lwmutex.Warning("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
||||
|
||||
if (!lwmutex.IsGood()) return CELL_EFAULT;
|
||||
|
||||
PPCThread& thr = GetCurrentPPUThread();
|
||||
const u32 id = thr.GetId();
|
||||
if (!lwmutex->attribute) return CELL_EINVAL;
|
||||
|
||||
{ // global lock
|
||||
std::lock_guard<std::mutex> lock(g_lwmutex);
|
||||
|
||||
if ((u32)lwmutex->attribute & SYS_SYNC_RECURSIVE)
|
||||
{
|
||||
if (id == (u32)lwmutex->owner)
|
||||
{
|
||||
lwmutex->recursive_count = lwmutex->recursive_count + 1;
|
||||
if (lwmutex->recursive_count == 0xffffffff) return CELL_EKRESOURCE;
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
else // recursive not allowed
|
||||
{
|
||||
if (id == (u32)lwmutex->owner)
|
||||
{
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lwmutex->owner) // try lock
|
||||
{
|
||||
lwmutex->owner = id;
|
||||
lwmutex->recursive_count = 1;
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
}
|
||||
return lwmutex->trylock(GetCurrentPPUThread().GetId());
|
||||
}
|
||||
|
||||
int sys_lwmutex_unlock(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sc_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
||||
sc_lwmutex.Warning("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.GetAddr());
|
||||
|
||||
if (!lwmutex.IsGood()) return CELL_EFAULT;
|
||||
|
||||
PPCThread& thr = GetCurrentPPUThread();
|
||||
const u32 id = thr.GetId();
|
||||
if (!lwmutex->unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM;
|
||||
|
||||
{ // global lock
|
||||
std::lock_guard<std::mutex> lock(g_lwmutex);
|
||||
|
||||
if (id != (u32)lwmutex->owner)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
else
|
||||
{
|
||||
lwmutex->recursive_count = (u32)lwmutex->recursive_count - 1;
|
||||
if (!lwmutex->recursive_count)
|
||||
{
|
||||
lwmutex->waiter = 0; // not used yet
|
||||
lwmutex->owner = 0; // release
|
||||
/* CPUThread* thr = Emu.GetCPU().GetThread(lwmutex->owner);
|
||||
if(thr)
|
||||
{
|
||||
thr->Wait(false);
|
||||
} */
|
||||
}
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ enum
|
||||
{
|
||||
// First In, First Out
|
||||
SYS_SYNC_FIFO = 1,
|
||||
// Priority Order (doesn't care?)
|
||||
// Priority Order
|
||||
SYS_SYNC_PRIORITY = 2,
|
||||
// Basic Priority Inheritance Protocol
|
||||
SYS_SYNC_PRIORITY_INHERIT = 3,
|
||||
@ -26,6 +26,15 @@ enum
|
||||
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //???
|
||||
};
|
||||
|
||||
struct sys_lwmutex_attribute_t
|
||||
{
|
||||
be_t<u32> attr_protocol;
|
||||
be_t<u32> attr_recursive;
|
||||
char name[8];
|
||||
};
|
||||
|
||||
extern std::mutex g_lwmutex;
|
||||
|
||||
struct sys_lwmutex_t
|
||||
{
|
||||
union // sys_lwmutex_variable_t
|
||||
@ -44,11 +53,78 @@ struct sys_lwmutex_t
|
||||
be_t<u32> recursive_count;
|
||||
be_t<u32> sleep_queue;
|
||||
be_t<u32> pad;
|
||||
|
||||
int trylock(u32 tid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_lwmutex); // global lock
|
||||
|
||||
if ((u32)attribute & SYS_SYNC_RECURSIVE)
|
||||
{
|
||||
if (tid == (u32)owner)
|
||||
{
|
||||
recursive_count = (u32)recursive_count + 1;
|
||||
if ((u32)recursive_count == 0xffffffff) return CELL_EKRESOURCE;
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
else // recursive not allowed
|
||||
{
|
||||
if (tid == (u32)owner)
|
||||
{
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(u32)owner) // try lock
|
||||
{
|
||||
owner = tid;
|
||||
recursive_count = 1;
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
bool unlock(u32 tid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_lwmutex); // global lock
|
||||
|
||||
if (tid != (u32)owner)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
recursive_count = (u32)recursive_count - 1;
|
||||
if (!(u32)recursive_count)
|
||||
{
|
||||
waiter = 0; // not used yet
|
||||
owner = 0; // release
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct sys_lwmutex_attribute_t
|
||||
struct lwmutex_locker
|
||||
{
|
||||
be_t<u32> attr_protocol;
|
||||
be_t<u32> attr_recursive;
|
||||
char name[8];
|
||||
private:
|
||||
mem_ptr_t<sys_lwmutex_t> m_mutex;
|
||||
u32 m_id;
|
||||
public:
|
||||
const int res;
|
||||
|
||||
lwmutex_locker(u32 lwmutex_addr, u32 tid)
|
||||
: m_id(tid)
|
||||
, m_mutex(lwmutex_addr)
|
||||
, res(m_mutex->trylock(m_id))
|
||||
{
|
||||
}
|
||||
|
||||
~lwmutex_locker()
|
||||
{
|
||||
if (res == CELL_OK) m_mutex->unlock(m_id);
|
||||
}
|
||||
};
|
@ -162,6 +162,7 @@ int sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags)
|
||||
|
||||
int sys_memory_get_user_memory_size(u32 mem_info_addr)
|
||||
{
|
||||
sc_mem.Warning("sys_memory_get_user_memory_size(mem_info_addr=0x%x)", mem_info_addr);
|
||||
sys_memory_info info;
|
||||
info.total_user_memory = re(Memory.GetUserMemTotalSize());
|
||||
info.available_user_memory = re(Memory.GetUserMemAvailSize());
|
||||
|
@ -74,7 +74,7 @@ int cellPadClearBuf(u32 port_no)
|
||||
|
||||
int cellPadGetData(u32 port_no, u32 data_addr)
|
||||
{
|
||||
//ConLog.Warning("cellPadGetData[port_no: %d, data_addr: 0x%x]", port_no, data_addr);
|
||||
sys_io.Log("cellPadGetData[port_no: %d, data_addr: 0x%x]", port_no, data_addr);
|
||||
const Array<Pad>& pads = Emu.GetPadManager().GetPads();
|
||||
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
|
||||
if(port_no >= pads.GetCount()) return CELL_PAD_ERROR_INVALID_PARAMETER;
|
||||
|
@ -6,48 +6,167 @@ SysCallBase sys_rwlock("sys_rwlock");
|
||||
|
||||
int sys_rwlock_create(mem32_t rw_lock_id, mem_ptr_t<sys_rwlock_attribute_t> attr)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_create(rw_lock_id_addr=0x%x, attr_addr=0x%x)", rw_lock_id.GetAddr(), attr.GetAddr());
|
||||
sys_rwlock.Warning("sys_rwlock_create(rw_lock_id_addr=0x%x, attr_addr=0x%x)", rw_lock_id.GetAddr(), attr.GetAddr());
|
||||
|
||||
if (!rw_lock_id.IsGood() || !attr.IsGood()) return CELL_EFAULT;
|
||||
|
||||
switch ((u32)attr->attr_protocol)
|
||||
{
|
||||
case SYS_SYNC_PRIORITY: sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY attr"); break;
|
||||
case SYS_SYNC_RETRY: sys_rwlock.Error("Invalid SYS_SYNC_RETRY attr"); break;
|
||||
case SYS_SYNC_PRIORITY_INHERIT: sys_rwlock.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break;
|
||||
case SYS_SYNC_FIFO: break;
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if ((u32)attr->attr_pshared != 0x200)
|
||||
{
|
||||
sys_rwlock.Error("Invalid attr_pshared(0x%x)", (u32)attr->attr_pshared);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
rw_lock_id = sys_rwlock.GetNewId(new RWLock((u32)attr->attr_protocol, (u32)attr->attr_pshared,
|
||||
(u64)attr->key, (s32)attr->flags, *(u64*)&attr->name));
|
||||
|
||||
sys_rwlock.Warning("*** rwlock created [%s] (protocol=0x%x): id=%d",
|
||||
attr->name, (u32)attr->attr_protocol, rw_lock_id.GetValue());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_rwlock_destroy(u32 rw_lock_id)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_destroy(rw_lock_id=%d)", rw_lock_id);
|
||||
sys_rwlock.Warning("sys_rwlock_destroy(rw_lock_id=%d)", rw_lock_id);
|
||||
|
||||
RWLock* rw;
|
||||
if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH;
|
||||
|
||||
std::lock_guard<std::mutex> lock(rw->m_lock);
|
||||
|
||||
if (rw->wlock_queue.GetCount() || rw->rlock_list.GetCount() || rw->wlock_thread) return CELL_EBUSY;
|
||||
|
||||
Emu.GetIdManager().RemoveID(rw_lock_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_rwlock_rlock(u32 rw_lock_id, u64 timeout)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_rlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout);
|
||||
return CELL_OK;
|
||||
sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout);
|
||||
|
||||
RWLock* rw;
|
||||
if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH;
|
||||
const u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
if (rw->rlock_trylock(tid)) return CELL_OK;
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
||||
do
|
||||
{
|
||||
if (Emu.IsStopped()) return CELL_ETIMEDOUT;
|
||||
Sleep(1);
|
||||
|
||||
if (rw->rlock_trylock(tid)) return CELL_OK;
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d): TIMEOUT", rw_lock_id);
|
||||
counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
int sys_rwlock_tryrlock(u32 rw_lock_id)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_tryrlock(rw_lock_id=%d)", rw_lock_id);
|
||||
sys_rwlock.Warning("sys_rwlock_tryrlock(rw_lock_id=%d)", rw_lock_id);
|
||||
|
||||
RWLock* rw;
|
||||
if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH;
|
||||
|
||||
if (!rw->rlock_trylock(GetCurrentPPUThread().GetId())) return CELL_EBUSY;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_rwlock_runlock(u32 rw_lock_id)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_runlock(rw_lock_id=%d)", rw_lock_id);
|
||||
sys_rwlock.Warning("sys_rwlock_runlock(rw_lock_id=%d)", rw_lock_id);
|
||||
|
||||
RWLock* rw;
|
||||
if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH;
|
||||
|
||||
if (!rw->rlock_unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_rwlock_wlock(u32 rw_lock_id, u64 timeout)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_wlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout);
|
||||
return CELL_OK;
|
||||
sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d, timeout=%llu)", rw_lock_id, timeout);
|
||||
|
||||
RWLock* rw;
|
||||
if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH;
|
||||
const u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
if (!rw->wlock_check(tid)) return CELL_EDEADLK;
|
||||
|
||||
if (rw->wlock_trylock(tid, true)) return CELL_OK;
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
||||
do
|
||||
{
|
||||
if (Emu.IsStopped()) return CELL_ETIMEDOUT;
|
||||
Sleep(1);
|
||||
|
||||
if (rw->wlock_trylock(tid, true)) return CELL_OK;
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d): TIMEOUT", rw_lock_id);
|
||||
counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
int sys_rwlock_trywlock(u32 rw_lock_id)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_trywlock(rw_lock_id=%d)", rw_lock_id);
|
||||
sys_rwlock.Warning("sys_rwlock_trywlock(rw_lock_id=%d)", rw_lock_id);
|
||||
|
||||
RWLock* rw;
|
||||
if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH;
|
||||
const u32 tid = GetCurrentPPUThread().GetId();
|
||||
|
||||
if (!rw->wlock_check(tid)) return CELL_EDEADLK;
|
||||
|
||||
if (!rw->wlock_trylock(tid, false)) return CELL_EBUSY;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_rwlock_wunlock(u32 rw_lock_id)
|
||||
{
|
||||
sys_rwlock.Warning("Unimplemented function: sys_rwlock_wunlock(rw_lock_id=%d)", rw_lock_id);
|
||||
sys_rwlock.Warning("sys_rwlock_wunlock(rw_lock_id=%d)", rw_lock_id);
|
||||
|
||||
RWLock* rw;
|
||||
if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH;
|
||||
|
||||
if (!rw->wlock_unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -2,11 +2,153 @@
|
||||
|
||||
struct sys_rwlock_attribute_t
|
||||
{
|
||||
u32 attr_protocol; //sys_protocol_t
|
||||
u32 attr_pshared; //sys_process_shared_t
|
||||
u64 key; //sys_ipc_key_t
|
||||
s32 flags;
|
||||
u8 name[8];
|
||||
be_t<u32> attr_protocol;
|
||||
be_t<u32> attr_pshared; // == 0x200 (NOT SHARED)
|
||||
be_t<u64> key; // process-shared key (not used)
|
||||
be_t<s32> flags; // process-shared flags (not used)
|
||||
be_t<u32> pad;
|
||||
char name[8];
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
#pragma pack()
|
||||
|
||||
struct RWLock
|
||||
{
|
||||
std::mutex m_lock; // internal lock
|
||||
u32 wlock_thread; // write lock owner
|
||||
Array<u32> wlock_queue; // write lock queue
|
||||
Array<u32> rlock_list; // read lock list
|
||||
u32 m_protocol; // TODO
|
||||
|
||||
u32 m_pshared; // not used
|
||||
u64 m_key; // not used
|
||||
s32 m_flags; // not used
|
||||
union
|
||||
{
|
||||
u64 m_name_data; // not used
|
||||
char m_name[8];
|
||||
};
|
||||
|
||||
RWLock(u32 protocol, u32 pshared, u64 key, s32 flags, u64 name)
|
||||
: m_protocol(protocol)
|
||||
, m_pshared(pshared)
|
||||
, m_key(key)
|
||||
, m_flags(flags)
|
||||
, m_name_data(name)
|
||||
, wlock_thread(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool rlock_trylock(u32 tid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
if (!wlock_thread && !wlock_queue.GetCount())
|
||||
{
|
||||
rlock_list.AddCpy(tid);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rlock_unlock(u32 tid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
for (u32 i = rlock_list.GetCount() - 1; ~i; i--)
|
||||
{
|
||||
if (rlock_list[i] == tid)
|
||||
{
|
||||
rlock_list.RemoveAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wlock_check(u32 tid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
if (wlock_thread == tid)
|
||||
{
|
||||
return false; // deadlock
|
||||
}
|
||||
for (u32 i = rlock_list.GetCount() - 1; ~i; i--)
|
||||
{
|
||||
if (rlock_list[i] == tid)
|
||||
{
|
||||
return false; // deadlock
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wlock_trylock(u32 tid, bool enqueue)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
if (wlock_thread || rlock_list.GetCount()) // already locked
|
||||
{
|
||||
if (!enqueue)
|
||||
{
|
||||
return false; // do not enqueue
|
||||
}
|
||||
for (u32 i = wlock_queue.GetCount() - 1; ~i; i--)
|
||||
{
|
||||
if (wlock_queue[i] == tid)
|
||||
{
|
||||
return false; // already enqueued
|
||||
}
|
||||
}
|
||||
wlock_queue.AddCpy(tid); // enqueue new thread
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wlock_queue.GetCount())
|
||||
{
|
||||
// SYNC_FIFO only yet
|
||||
if (wlock_queue[0] == tid)
|
||||
{
|
||||
wlock_thread = tid;
|
||||
wlock_queue.RemoveAt(0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!enqueue)
|
||||
{
|
||||
return false; // do not enqueue
|
||||
}
|
||||
for (u32 i = wlock_queue.GetCount() - 1; ~i; i--)
|
||||
{
|
||||
if (wlock_queue[i] == tid)
|
||||
{
|
||||
return false; // already enqueued
|
||||
}
|
||||
}
|
||||
wlock_queue.AddCpy(tid); // enqueue new thread
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wlock_thread = tid; // easy way
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool wlock_unlock(u32 tid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
if (wlock_thread == tid)
|
||||
{
|
||||
wlock_thread = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
@ -9,17 +9,29 @@
|
||||
static SysCallBase sc_spu("sys_spu");
|
||||
extern SysCallBase sys_event;
|
||||
|
||||
static const u32 g_spu_group_thr_count = 255;
|
||||
static const u32 g_spu_group_thr_max = 255;
|
||||
|
||||
struct SpuGroupInfo
|
||||
{
|
||||
CPUThread* threads[g_spu_group_thr_count];
|
||||
sys_spu_thread_group_attribute& attr;
|
||||
volatile long lock;
|
||||
Array<u32> list;
|
||||
std::atomic<u32> lock;
|
||||
wxString m_name;
|
||||
int m_prio;
|
||||
int m_type;
|
||||
int m_ct;
|
||||
|
||||
SpuGroupInfo(sys_spu_thread_group_attribute& attr) : attr(attr), lock(0)
|
||||
SpuGroupInfo(wxString name, u32 num, int prio, int type, u32 ct)
|
||||
: m_name(name)
|
||||
, m_prio(prio)
|
||||
, m_type(type)
|
||||
, m_ct(ct)
|
||||
, lock(0)
|
||||
{
|
||||
memset(threads, 0, sizeof(CPUThread*) * g_spu_group_thr_count);
|
||||
list.SetCount(num);
|
||||
for (u32 i = 0; i < num; i++)
|
||||
{
|
||||
list[i] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -102,12 +114,12 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
if(spu_num >= g_spu_group_thr_count)
|
||||
if(spu_num >= g_spu_group_thr_max)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if(group_info->threads[spu_num])
|
||||
if(group_info->list[spu_num])
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
@ -133,20 +145,10 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
|
||||
new_thread.SetArg(3, a4);
|
||||
new_thread.Run();
|
||||
|
||||
thread = new_thread.GetId();
|
||||
thread = group_info->list[spu_num] = new_thread.GetId();
|
||||
|
||||
group_info->threads[spu_num] = &new_thread;
|
||||
|
||||
/*ConLog.Write("New SPU Thread:");
|
||||
ConLog.Write("SPU img offset = 0x%x", (u32)img->segs_addr);
|
||||
ConLog.Write("entry_point = 0x%x", spu_ep);
|
||||
ConLog.Write("name = %s", name.c_str());
|
||||
ConLog.Write("a1 = 0x%x", a1);
|
||||
ConLog.Write("a2 = 0x%x", a2);
|
||||
ConLog.Write("a3 = 0x%x", a3);
|
||||
ConLog.Write("a4 = 0x%x", a4);
|
||||
ConLog.Write("ls_offset = 0x%x", ((SPUThread&)new_thread).dmac.ls_offset);
|
||||
ConLog.SkipLn();*/
|
||||
sc_spu.Warning("*** New SPU Thread [%s] (img_offset=0x%x, ls_offset=0x%x, ep=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d",
|
||||
name.c_str(), (u32)img->segs_addr, ((SPUThread&)new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, thread.GetValue());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -192,11 +194,12 @@ int sys_spu_thread_group_start(u32 id)
|
||||
}
|
||||
|
||||
//Emu.Pause();
|
||||
for(int i=0; i<g_spu_group_thr_count; i++)
|
||||
for (int i = 0; i < group_info->list.GetCount(); i++)
|
||||
{
|
||||
if(group_info->threads[i])
|
||||
CPUThread* t;
|
||||
if (t = Emu.GetCPU().GetThread(group_info->list[i]))
|
||||
{
|
||||
group_info->threads[i]->Exec();
|
||||
t->Exec();
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,11 +218,12 @@ int sys_spu_thread_group_suspend(u32 id)
|
||||
}
|
||||
|
||||
//Emu.Pause();
|
||||
for(int i=0; i<g_spu_group_thr_count; i++)
|
||||
for (int i = 0; i < group_info->list.GetCount(); i++)
|
||||
{
|
||||
if(group_info->threads[i])
|
||||
CPUThread* t;
|
||||
if (t = Emu.GetCPU().GetThread(group_info->list[i]))
|
||||
{
|
||||
group_info->threads[i]->Pause();
|
||||
t->Pause();
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,21 +233,23 @@ int sys_spu_thread_group_suspend(u32 id)
|
||||
//170
|
||||
int sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t<sys_spu_thread_group_attribute> attr)
|
||||
{
|
||||
ConLog.Write("sys_spu_thread_group_create:");
|
||||
ConLog.Write("*** id_addr=0x%x", id.GetAddr());
|
||||
ConLog.Write("*** num=%d", num);
|
||||
ConLog.Write("*** prio=%d", prio);
|
||||
ConLog.Write("*** attr_addr=0x%x", attr.GetAddr());
|
||||
sc_spu.Warning("sys_spu_thread_group_create(id_addr=0x%x, num=%d, prio=%d, attr_addr=0x%x)",
|
||||
id.GetAddr(), num, prio, attr.GetAddr());
|
||||
|
||||
ConLog.Write("*** attr.name_len=%d", attr->name_len.ToLE());
|
||||
ConLog.Write("*** attr.name_addr=0x%x", attr->name_addr.ToLE());
|
||||
ConLog.Write("*** attr.type=%d", attr->type.ToLE());
|
||||
ConLog.Write("*** attr.option.ct=%d", attr->option.ct.ToLE());
|
||||
if (!id.IsGood() || !attr.IsGood()) return CELL_EFAULT;
|
||||
|
||||
const wxString name = Memory.ReadString(attr->name_addr, attr->name_len).mb_str();
|
||||
ConLog.Write("*** name='%s'", name.c_str());
|
||||
if (!Memory.IsGoodAddr(attr->name_addr, attr->name_len)) return CELL_EFAULT;
|
||||
|
||||
id = Emu.GetIdManager().GetNewID(wxString::Format("sys_spu_thread_group '%s'", name), new SpuGroupInfo(*attr));
|
||||
if (num > g_spu_group_thr_max) return CELL_EINVAL;
|
||||
|
||||
if (prio < 16 || prio > 255) return CELL_EINVAL;
|
||||
|
||||
const wxString name = Memory.ReadString(attr->name_addr, attr->name_len);
|
||||
|
||||
id = sc_spu.GetNewId(new SpuGroupInfo(name, num, prio, attr->type, attr->ct));
|
||||
|
||||
sc_spu.Warning("*** SPU Thread Group created [%s] (type=%d, option.ct=%d): id=%d",
|
||||
name.c_str(), (int)attr->type, (u32)attr->ct, id.GetValue());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -259,7 +265,7 @@ int sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (_InterlockedCompareExchange(&group_info->lock, 1, 0)) //get lock
|
||||
if (group_info->lock.exchange(1)) // acquire lock
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
@ -267,21 +273,24 @@ int sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status)
|
||||
cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
|
||||
status = 0; //unspecified because of ALL_THREADS_EXIT
|
||||
|
||||
for(int i=0; i<g_spu_group_thr_count; i++)
|
||||
for (int i = 0; i < group_info->list.GetCount(); i++)
|
||||
{
|
||||
if(group_info->threads[i])
|
||||
while (Emu.GetCPU().GetThread(group_info->list[i]))
|
||||
{
|
||||
while (!group_info->threads[i]->IsStopped()) Sleep(1);
|
||||
Sleep(1);
|
||||
if (Emu.IsStopped()) return CELL_OK;
|
||||
}
|
||||
group_info->list[i] = 0;
|
||||
}
|
||||
|
||||
_InterlockedExchange(&group_info->lock, 0); //release lock
|
||||
group_info->lock = 0; // release lock
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int sys_spu_thread_create(mem32_t thread_id, mem32_t entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sc_spu);
|
||||
sc_spu.Error("sys_spu_thread_create(thread_id_addr=0x%x, entry_addr=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x",
|
||||
thread_id.GetAddr(), entry.GetAddr(), arg, prio, stacksize, flags, threadname_addr);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -458,6 +467,7 @@ int sys_spu_thread_get_spu_cfg(u32 id, mem64_t value)
|
||||
//184
|
||||
int sys_spu_thread_write_snr(u32 id, u32 number, u32 value)
|
||||
{
|
||||
sc_spu.Log("sys_spu_thread_write_snr(id=0x%x, number=%d, value=0x%x)", id, number, value);
|
||||
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
||||
|
||||
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
||||
@ -504,9 +514,10 @@ int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
for(int i=0; i<g_spu_group_thr_count; ++i)
|
||||
for(int i=0; i<group->list.GetCount(); ++i)
|
||||
{
|
||||
if(group->threads[i])
|
||||
CPUThread* t;
|
||||
if(t = Emu.GetCPU().GetThread(group->list[i]))
|
||||
{
|
||||
bool finded_port = false;
|
||||
for(int j=0; j<equeue->pos; ++j)
|
||||
@ -514,7 +525,7 @@ int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32
|
||||
if(!equeue->ports[j]->thread)
|
||||
{
|
||||
finded_port = true;
|
||||
equeue->ports[j]->thread = group->threads[i];
|
||||
equeue->ports[j]->thread = t;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,8 @@ struct sys_spu_thread_group_attribute
|
||||
be_t<u32> name_len;
|
||||
be_t<u32> name_addr;
|
||||
be_t<int> type;
|
||||
struct{be_t<u32> ct;} option;
|
||||
/* struct {} option; */
|
||||
be_t<u32> ct; // memory container id
|
||||
};
|
||||
|
||||
struct sys_spu_thread_attribute
|
||||
|
@ -249,6 +249,7 @@
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_GCM.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_Heap.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_Keyboard.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_Lwcond.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_Lwmutex.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_Memory.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_Mouse.cpp" />
|
||||
|
@ -370,6 +370,9 @@
|
||||
<ClCompile Include="Emu\SysCalls\Modules\cellDmux.cpp">
|
||||
<Filter>Emu\SysCalls\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\lv2\SC_Lwcond.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="rpcs3.rc" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user