Small changes

lwmutex completely implemented
This commit is contained in:
Nekotekina 2014-02-09 15:11:48 +04:00
parent ed40732e7b
commit 3308fefa7f
14 changed files with 259 additions and 128 deletions

View File

@ -126,7 +126,11 @@ public:
: sm(_sm) : sm(_sm)
, tid(get_tid()) , tid(get_tid())
{ {
if (!tid) throw "SMutexLockerBase: invalid thread id"; if (!tid)
{
ConLog.Error("SMutexLockerBase: thread id == 0");
Emu.Pause();
}
sm.lock(tid); sm.lock(tid);
} }

View File

@ -9,12 +9,13 @@ struct reservation_struct
volatile u32 owner; // id of thread that got reservation volatile u32 owner; // id of thread that got reservation
volatile u32 addr; volatile u32 addr;
volatile u32 size; volatile u32 size;
volatile u32 data32;
volatile u64 data64;
// atm, PPU can't break SPU MFC reservation correctly
__forceinline void clear() __forceinline void clear()
{ {
owner = 0; owner = 0;
addr = 0;
size = 0;
} }
}; };

View File

@ -2361,14 +2361,13 @@ private:
} }
void LWARX(u32 rd, u32 ra, u32 rb) void LWARX(u32 rd, u32 ra, u32 rb)
{ {
ConLog.Warning("LWARX");
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
SMutexLocker lock(reservation.mutex); SMutexLocker lock(reservation.mutex);
reservation.owner = lock.tid; reservation.owner = lock.tid;
reservation.addr = addr; reservation.addr = addr;
reservation.size = 4; reservation.size = 4;
CPU.GPR[rd] = Memory.Read32(addr); reservation.data32 = CPU.GPR[rd] = Memory.Read32(addr);
} }
void LDX(u32 rd, u32 ra, u32 rb) void LDX(u32 rd, u32 ra, u32 rb)
{ {
@ -2538,14 +2537,13 @@ private:
} }
void LDARX(u32 rd, u32 ra, u32 rb) void LDARX(u32 rd, u32 ra, u32 rb)
{ {
ConLog.Warning("LDARX");
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
SMutexLocker lock(reservation.mutex); SMutexLocker lock(reservation.mutex);
reservation.owner = lock.tid; reservation.owner = lock.tid;
reservation.addr = addr; reservation.addr = addr;
reservation.size = 8; reservation.size = 8;
CPU.GPR[rd] = Memory.Read64(addr); reservation.data64 = CPU.GPR[rd] = Memory.Read64(addr);
} }
void DCBF(u32 ra, u32 rb) void DCBF(u32 ra, u32 rb)
{ {
@ -2658,14 +2656,13 @@ private:
} }
void STWCX_(u32 rs, u32 ra, u32 rb) void STWCX_(u32 rs, u32 ra, u32 rb)
{ {
ConLog.Warning("STWCX_");
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
SMutexLocker lock(reservation.mutex); SMutexLocker lock(reservation.mutex);
if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 4) if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 4)
{ {
Memory.Write32(addr, CPU.GPR[rs]); // Memory.Write32(addr, CPU.GPR[rs]);
CPU.SetCR_EQ(0, true); CPU.SetCR_EQ(0, InterlockedCompareExchange((volatile long*)(Memory + addr), (u32)CPU.GPR[rs], reservation.data32) == reservation.data32);
reservation.clear(); reservation.clear();
} }
else else
@ -2712,14 +2709,13 @@ private:
} }
void STDCX_(u32 rs, u32 ra, u32 rb) void STDCX_(u32 rs, u32 ra, u32 rb)
{ {
ConLog.Warning("STDCX_");
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
SMutexLocker lock(reservation.mutex); SMutexLocker lock(reservation.mutex);
if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 8) if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 8)
{ {
Memory.Write64(addr, CPU.GPR[rs]); // Memory.Write64(addr, CPU.GPR[rs]);
CPU.SetCR_EQ(0, true); CPU.SetCR_EQ(0, InterlockedCompareExchange64((volatile long long*)(Memory + addr), CPU.GPR[rs], reservation.data64) == reservation.data64);
reservation.clear(); reservation.clear();
} }
else else

View File

@ -83,7 +83,7 @@ struct CellAudioPortConfig
struct CellAudioConfig //custom structure struct CellAudioConfig //custom structure
{ {
bool m_is_audio_initialized; bool m_is_audio_initialized;
bool m_is_audio_port_open; bool m_is_audio_port_opened;
bool m_is_audio_port_started; bool m_is_audio_port_started;
}; };
@ -216,7 +216,7 @@ int cellAudioPortOpen(mem_ptr_t<CellAudioPortParam> audioParam, mem32_t portNum)
cellAudio.Warning("cellAudioPortOpen(audioParam_addr=0x%x,portNum_addr=0x%x)",audioParam.GetAddr(),portNum.GetAddr()); cellAudio.Warning("cellAudioPortOpen(audioParam_addr=0x%x,portNum_addr=0x%x)",audioParam.GetAddr(),portNum.GetAddr());
if(!audioParam.IsGood() || !portNum.IsGood()) return CELL_AUDIO_ERROR_PORT_OPEN; if(!audioParam.IsGood() || !portNum.IsGood()) return CELL_AUDIO_ERROR_PORT_OPEN;
m_config->m_is_audio_port_open = true; m_config->m_is_audio_port_opened = true;
m_param->nChannel = audioParam->nChannel; m_param->nChannel = audioParam->nChannel;
m_param->nBlock = audioParam->nBlock; m_param->nBlock = audioParam->nBlock;
@ -238,13 +238,13 @@ int cellAudioGetPortConfig(u32 portNum, mem_ptr_t<CellAudioPortConfig> portConfi
//if(portNum > 7) return CELL_AUDIO_ERROR_PORT_FULL; //if(portNum > 7) return CELL_AUDIO_ERROR_PORT_FULL;
if(m_config->m_is_audio_port_open == false) if(!m_config->m_is_audio_port_opened)
{ {
portConfig->status = CELL_AUDIO_STATUS_CLOSE; portConfig->status = CELL_AUDIO_STATUS_CLOSE;
return CELL_OK; return CELL_OK;
} }
if(m_config->m_is_audio_port_started == true) if(m_config->m_is_audio_port_started)
{ {
portConfig->status = CELL_AUDIO_STATUS_RUN; portConfig->status = CELL_AUDIO_STATUS_RUN;
} }
@ -268,7 +268,7 @@ int cellAudioPortStart(u32 portNum)
{ {
cellAudio.Warning("cellAudioPortStart(portNum=0x%x)",portNum); cellAudio.Warning("cellAudioPortStart(portNum=0x%x)",portNum);
if (m_config->m_is_audio_port_open == true) if (!m_config->m_is_audio_port_opened)
return CELL_AUDIO_ERROR_PORT_OPEN; return CELL_AUDIO_ERROR_PORT_OPEN;
m_config->m_is_audio_port_started = true; m_config->m_is_audio_port_started = true;
@ -279,10 +279,10 @@ int cellAudioPortClose(u32 portNum)
{ {
cellAudio.Warning("cellAudioPortClose(portNum=0x%x)",portNum); cellAudio.Warning("cellAudioPortClose(portNum=0x%x)",portNum);
if (m_config->m_is_audio_port_open == false) if (!m_config->m_is_audio_port_opened)
return CELL_AUDIO_ERROR_PORT_NOT_OPEN; return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
m_config->m_is_audio_port_open = false; m_config->m_is_audio_port_opened = false;
return CELL_OK; return CELL_OK;
} }
@ -1016,6 +1016,6 @@ void cellAudio_init()
void cellAudio_unload() void cellAudio_unload()
{ {
m_config->m_is_audio_initialized = false; m_config->m_is_audio_initialized = false;
m_config->m_is_audio_port_open = false; m_config->m_is_audio_port_opened = false;
m_config->m_is_audio_port_started = false; m_config->m_is_audio_port_started = false;
} }

View File

@ -127,7 +127,7 @@ extern int sys_game_process_exitspawn(u32 path_addr, u32 argv_addr, u32 envp_add
u32 data, u32 data_size, int prio, u64 flags ); u32 data, u32 data_size, int prio, u64 flags );
//sys_event //sys_event
extern int sys_event_queue_create(u32 equeue_id_addr, u32 attr_addr, u64 event_queue_key, int size); extern int sys_event_queue_create(mem32_t equeue_id, mem_ptr_t<sys_event_queue_attr> attr, u64 event_queue_key, int size);
extern int sys_event_queue_receive(u32 equeue_id, u32 event_addr, u32 timeout); extern int sys_event_queue_receive(u32 equeue_id, u32 event_addr, u32 timeout);
extern int sys_event_port_create(u32 eport_id_addr, int port_type, u64 name); extern int sys_event_port_create(u32 eport_id_addr, int port_type, u64 name);
extern int sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id); extern int sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id);

View File

@ -6,30 +6,24 @@
SysCallBase sys_event("sys_event"); SysCallBase sys_event("sys_event");
//128 //128
int sys_event_queue_create(u32 equeue_id_addr, u32 attr_addr, u64 event_queue_key, int size) int sys_event_queue_create(mem32_t equeue_id, mem_ptr_t<sys_event_queue_attr> attr, u64 event_queue_key, int size)
{ {
sys_event.Warning("sys_event_queue_create(equeue_id_addr=0x%x, attr_addr=0x%x, event_queue_key=0x%llx, size=%d)", sys_event.Warning("sys_event_queue_create(equeue_id_addr=0x%x, attr_addr=0x%x, event_queue_key=0x%llx, size=%d)",
equeue_id_addr, attr_addr, event_queue_key, size); equeue_id.GetAddr(), attr.GetAddr(), event_queue_key, size);
if(size <= 0 || size > 127) if(size <= 0 || size > 127)
{ {
return CELL_EINVAL; return CELL_EINVAL;
} }
if(!Memory.IsGoodAddr(equeue_id_addr, 4) || !Memory.IsGoodAddr(attr_addr, sizeof(sys_event_queue_attr))) if(!equeue_id.IsGood() || !attr.IsGood())
{ {
return CELL_EFAULT; return CELL_EFAULT;
} }
auto& attr = (sys_event_queue_attr&)Memory[attr_addr]; equeue_id = sys_event.GetNewId(new EventQueue((u32)attr->protocol, (int)attr->type, attr->name_u64, event_queue_key, size));
sys_event.Warning("name = %s", attr.name); sys_event.Warning("*** event_queue created[%s] (protocol=0x%x, type=0x%x): id = %d",
sys_event.Warning("type = %d", re(attr.type)); attr->name, (u32)attr->protocol, (int)attr->type, equeue_id.GetValue());
EventQueue* equeue = new EventQueue();
equeue->size = size;
equeue->pos = 0;
equeue->type = re(attr.type);
strncpy(equeue->name, attr.name, 8);
Memory.Write32(equeue_id_addr, sys_event.GetNewId(equeue));
return CELL_OK; return CELL_OK;
} }
@ -79,10 +73,10 @@ int sys_event_queue_receive(u32 equeue_id, u32 event_addr, u32 timeout)
{ {
auto dst = (sys_event_data&)Memory[event_addr]; auto dst = (sys_event_data&)Memory[event_addr];
re(dst.source, equeue->ports[i]->name); dst.source = equeue->ports[i]->name;
re(dst.data1, equeue->ports[i]->data1); dst.data1 = equeue->ports[i]->data1;
re(dst.data2, equeue->ports[i]->data2); dst.data2 = equeue->ports[i]->data2;
re(dst.data3, equeue->ports[i]->data3); dst.data3 = equeue->ports[i]->data3;
equeue->ports[i]->has_data = false; equeue->ports[i]->has_data = false;

View File

@ -7,24 +7,16 @@ 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) 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)", sys_lwcond.Log("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)",
lwcond.GetAddr(), lwmutex.GetAddr(), attr.GetAddr()); lwcond.GetAddr(), lwmutex.GetAddr(), attr.GetAddr());
if (!lwcond.IsGood() || !lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT; if (!lwcond.IsGood() || !lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT;
switch (lwmutex->attribute.ToBE()) lwcond->lwmutex = lwmutex.GetAddr();
{ lwcond->lwcond_queue = sys_lwcond.GetNewId(new LWCond(attr->name_u64));
case se32(SYS_SYNC_PRIORITY): break;
case se32(SYS_SYNC_RETRY): sys_lwcond.Error("Invalid SYS_SYNC_RETRY attr"); break;
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwcond.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break;
case se32(SYS_SYNC_FIFO): break;
default: sys_lwcond.Error("Invalid lwmutex protocol(%d)", (u32)lwmutex->attribute); break;
}
lwcond->lwmutex_addr = lwmutex.GetAddr(); sys_lwcond.Warning("*** lwcond created [%s] (attr=0x%x, lwmutex.sq=0x%x): id=0x%x",
lwcond->lwcond_queue = sys_lwcond.GetNewId(new LWCond((u32)lwmutex->attribute, *(u64*)&attr->name)); attr->name, (u32)lwmutex->attribute, (u32)lwmutex->sleep_queue, (u32)lwcond->lwcond_queue);
sys_lwcond.Warning("*** lwcond created [%s] (protocol=0x%x): id=%d", attr->name, (u32)lwmutex->attribute, (u32)lwcond->lwcond_queue);
return CELL_OK; return CELL_OK;
} }
@ -50,7 +42,7 @@ int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond)
u32 id = (u32)lwcond->lwcond_queue; u32 id = (u32)lwcond->lwcond_queue;
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
lwc->signal(); lwc->signal(mem_ptr_t<sys_lwmutex_t>(lwcond->lwmutex)->attribute);
return CELL_OK; return CELL_OK;
} }
@ -92,7 +84,8 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
u32 id = (u32)lwcond->lwcond_queue; u32 id = (u32)lwcond->lwcond_queue;
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
const u32 tid = GetCurrentPPUThread().GetId(); const u32 tid = GetCurrentPPUThread().GetId();
mem_ptr_t<sys_lwmutex_t> lwmutex((u32)lwcond->lwmutex_addr);
mem_ptr_t<sys_lwmutex_t> lwmutex(lwcond->lwmutex);
if ((u32)lwmutex->owner.GetOwner() != tid) return CELL_EPERM; // caller must own this lwmutex if ((u32)lwmutex->owner.GetOwner() != tid) return CELL_EPERM; // caller must own this lwmutex
lwc->begin_waiting(tid); lwc->begin_waiting(tid);

View File

@ -2,12 +2,16 @@
struct sys_lwcond_attribute_t struct sys_lwcond_attribute_t
{ {
char name[8]; union
{
char name[8];
u64 name_u64;
};
}; };
struct sys_lwcond_t struct sys_lwcond_t
{ {
be_t<u32> lwmutex_addr; be_t<u32> lwmutex;
be_t<u32> lwcond_queue; be_t<u32> lwcond_queue;
}; };
@ -18,22 +22,20 @@ struct LWCond
std::mutex m_lock; std::mutex m_lock;
Array<u32> waiters; // list of waiting threads Array<u32> waiters; // list of waiting threads
Array<u32> signaled; // list of signaled threads Array<u32> signaled; // list of signaled threads
u32 m_protocol; // protocol
u64 m_name; // not used u64 m_name; // not used
LWCond(u32 prot, u64 name) LWCond(u64 name)
: m_name(name) : m_name(name)
, m_protocol(prot)
{ {
} }
void signal() void signal(u32 _protocol)
{ {
std::lock_guard<std::mutex> lock(m_lock); std::lock_guard<std::mutex> lock(m_lock);
if (waiters.GetCount()) if (waiters.GetCount())
{ {
if (m_protocol == SYS_SYNC_PRIORITY) if ((_protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) == SYS_SYNC_PRIORITY)
{ {
u64 max_prio = 0; u64 max_prio = 0;
u32 sel = 0; u32 sel = 0;

View File

@ -7,7 +7,7 @@ SysCallBase sc_lwmutex("sys_lwmutex");
int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_attribute_t> attr) int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_attribute_t> attr)
{ {
sc_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)", sc_lwmutex.Log("sys_lwmutex_create(lwmutex_addr=0x%x, lwmutex_attr_addr=0x%x)",
lwmutex.GetAddr(), attr.GetAddr()); lwmutex.GetAddr(), attr.GetAddr());
if (!lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT; if (!lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT;
@ -16,40 +16,49 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
{ {
case se32(SYS_SYNC_RECURSIVE): break; case se32(SYS_SYNC_RECURSIVE): break;
case se32(SYS_SYNC_NOT_RECURSIVE): break; case se32(SYS_SYNC_NOT_RECURSIVE): break;
default: return CELL_EINVAL; default: sc_lwmutex.Error("Unknown 0x%x recursive attr", (u32)attr->attr_recursive); return CELL_EINVAL;
} }
switch (attr->attr_protocol.ToBE()) switch (attr->attr_protocol.ToBE())
{ {
case se32(SYS_SYNC_PRIORITY): sc_lwmutex.Warning("TODO: SYS_SYNC_PRIORITY attr"); break; case se32(SYS_SYNC_PRIORITY): break;
case se32(SYS_SYNC_RETRY): break; case se32(SYS_SYNC_RETRY): break;
case se32(SYS_SYNC_PRIORITY_INHERIT): sc_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT attr"); break; case se32(SYS_SYNC_PRIORITY_INHERIT): sc_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL;
case se32(SYS_SYNC_FIFO): sc_lwmutex.Warning("TODO: SYS_SYNC_FIFO attr"); break; case se32(SYS_SYNC_FIFO): break;
default: return CELL_EINVAL; default: sc_lwmutex.Error("Unknown 0x%x protocol attr", (u32)attr->attr_protocol); return CELL_EINVAL;
} }
lwmutex->attribute = (u32)attr->attr_protocol | (u32)attr->attr_recursive; lwmutex->attribute = attr->attr_protocol | attr->attr_recursive;
lwmutex->all_info = 0; lwmutex->all_info = 0;
lwmutex->pad = 0; lwmutex->pad = 0;
lwmutex->recursive_count = 0; lwmutex->recursive_count = 0;
lwmutex->sleep_queue = 0;
sc_lwmutex.Warning("*** lwmutex created [%s] (attribute=0x%x): id=???", attr->name, (u32)lwmutex->attribute); u32 sq_id = sc_lwmutex.GetNewId(new SleepQueue(attr->name_u64));
lwmutex->sleep_queue = sq_id;
sc_lwmutex.Log("*** lwmutex created [%s] (attribute=0x%x): sleep_queue=0x%x",
attr->name, (u32)lwmutex->attribute, sq_id);
return CELL_OK; return CELL_OK;
} }
int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex) int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
{ {
sc_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr()); sc_lwmutex.Log("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr());
if (!lwmutex.IsGood()) return CELL_EFAULT; if (!lwmutex.IsGood()) return CELL_EFAULT;
u32 sq_id = lwmutex->sleep_queue;
if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH;
// try to make it unable to lock // try to make it unable to lock
switch (int res = lwmutex->trylock(~0)) switch (int res = lwmutex->trylock(~0))
{ {
case CELL_OK: lwmutex->attribute = 0; case CELL_OK:
default: return res; lwmutex->attribute = 0;
lwmutex->sleep_queue = 0;
Emu.GetIdManager().RemoveID(sq_id);
default: return res;
} }
} }

View File

@ -31,7 +31,103 @@ struct sys_lwmutex_attribute_t
{ {
be_t<u32> attr_protocol; be_t<u32> attr_protocol;
be_t<u32> attr_recursive; be_t<u32> attr_recursive;
char name[8]; union
{
char name[8];
u64 name_u64;
};
};
class SleepQueue
{
/* struct q_rec
{
u32 tid;
u64 prio;
q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {}
}; */
SMutex m_mutex;
Array<u32> list;
u64 m_name;
public:
SleepQueue(u64 name)
: m_name(name)
{
}
void push(u32 tid)
{
SMutexLocker lock(m_mutex);
list.AddCpy(tid);
}
u32 pop() // SYS_SYNC_FIFO
{
SMutexLocker lock(m_mutex);
while (true)
{
if (list.GetCount())
{
u32 res = list[0];
list.RemoveAt(0);
if (Emu.GetIdManager().CheckID(res))
// check thread
{
return res;
}
}
return 0;
};
}
u32 pop_prio() // SYS_SYNC_PRIORITY
{
SMutexLocker lock(m_mutex);
while (true)
{
if (list.GetCount())
{
u64 max_prio = 0;
u32 sel = 0;
for (u32 i = 0; i < list.GetCount(); i++)
{
CPUThread* t = Emu.GetCPU().GetThread(list[i]);
if (!t)
{
list[i] = 0;
sel = i;
break;
}
u64 prio = t->GetPrio();
if (prio > max_prio)
{
max_prio = prio;
sel = i;
}
}
u32 res = list[sel];
list.RemoveAt(sel);
/* if (Emu.GetIdManager().CheckID(res)) */
if (res)
// check thread
{
return res;
}
}
return 0;
}
}
u32 pop_prio_inherit() // (TODO)
{
ConLog.Error("TODO: SleepQueue::pop_prio_inherit()");
Emu.Pause();
}
}; };
struct sys_lwmutex_t struct sys_lwmutex_t
@ -53,16 +149,16 @@ struct sys_lwmutex_t
be_t<u32> sleep_queue; be_t<u32> sleep_queue;
be_t<u32> pad; be_t<u32> pad;
int enter(u32 tid) // check and process (non-)recursive mutex int trylock(be_t<u32> tid)
{ {
if (!attribute) return CELL_EINVAL; if (!attribute.ToBE()) return CELL_EINVAL;
if (tid == (u32)owner.GetOwner()) if (tid == owner.GetOwner())
{ {
if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE))
{ {
recursive_count += 1; recursive_count += 1;
if (!recursive_count) return CELL_EKRESOURCE; if (!recursive_count.ToBE()) return CELL_EKRESOURCE;
return CELL_OK; return CELL_OK;
} }
else else
@ -70,52 +166,64 @@ struct sys_lwmutex_t
return CELL_EDEADLK; return CELL_EDEADLK;
} }
} }
return CELL_EBUSY;
}
int trylock(u32 tid)
{
switch (int res = enter(tid))
{
case CELL_EBUSY: break;
default: return res;
}
switch (owner.trylock(tid)) switch (owner.trylock(tid))
{ {
case SMR_OK: recursive_count = 1; return CELL_OK; case SMR_OK: recursive_count = 1; return CELL_OK;
default: return CELL_EBUSY; case SMR_FAILED: return CELL_EBUSY;
default: return CELL_EINVAL;
} }
} }
int unlock(u32 tid) int unlock(be_t<u32> tid)
{ {
if (tid != (u32)owner.GetOwner()) if (tid != owner.GetOwner())
{ {
return CELL_EPERM; return CELL_EPERM;
} }
else else
{ {
recursive_count -= 1; recursive_count -= 1;
if (!recursive_count) if (!recursive_count.ToBE())
{ {
owner.unlock(tid); be_t<u32> target = 0;
switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK))
{
case se32(SYS_SYNC_FIFO):
case se32(SYS_SYNC_PRIORITY):
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH;
target = attribute.ToBE() & se32(SYS_SYNC_FIFO) ? sq->pop() : sq->pop_prio();
case se32(SYS_SYNC_RETRY): default: owner.unlock(tid, target); break;
}
} }
return CELL_OK; return CELL_OK;
} }
} }
int lock(u32 tid, u64 timeout) int lock(be_t<u32> tid, u64 timeout)
{ {
switch (int res = enter(tid)) switch (int res = trylock(tid))
{ {
case CELL_EBUSY: break; case CELL_EBUSY: break;
default: return res; default: return res;
} }
switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK))
{
case se32(SYS_SYNC_PRIORITY):
case se32(SYS_SYNC_FIFO):
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH;
sq->push(tid);
default: break;
}
switch (owner.lock(tid, timeout)) switch (owner.lock(tid, timeout))
{ {
case SMR_OK: recursive_count = 1; return CELL_OK; case SMR_OK: case SMR_SIGNAL: recursive_count = 1; return CELL_OK;
case SMR_TIMEOUT: return CELL_ETIMEDOUT; case SMR_TIMEOUT: return CELL_ETIMEDOUT;
default: return CELL_EINVAL; default: return CELL_EINVAL;
} }
} }
}; };
@ -123,13 +231,17 @@ struct sys_lwmutex_t
class lwmutex_locker class lwmutex_locker
{ {
mem_ptr_t<sys_lwmutex_t> m_mutex; mem_ptr_t<sys_lwmutex_t> m_mutex;
u32 m_id; be_t<u32> m_id;
lwmutex_locker(u32 lwmutex_addr, u32 tid, u64 timeout = 0) lwmutex_locker(mem_ptr_t<sys_lwmutex_t> lwmutex, be_t<u32> tid, u64 timeout = 0)
: m_id(tid) : m_id(tid)
, m_mutex(lwmutex_addr) , m_mutex(lwmutex)
{ {
if (int res = m_mutex->lock(m_id, timeout)) throw "lwmutex_locker: m_mutex->lock failed"; if (int res = m_mutex->lock(m_id, timeout))
{
ConLog.Error("lwmutex_locker: m_mutex->lock failed(res=0x%x)", res);
Emu.Pause();
}
} }
~lwmutex_locker() ~lwmutex_locker()

View File

@ -21,11 +21,11 @@ int sys_rwlock_create(mem32_t rw_lock_id, mem_ptr_t<sys_rwlock_attribute_t> attr
if (attr->attr_pshared.ToBE() != se32(0x200)) if (attr->attr_pshared.ToBE() != se32(0x200))
{ {
sys_rwlock.Error("Invalid attr_pshared(0x%x)", (u32)attr->attr_pshared);
return CELL_EINVAL; return CELL_EINVAL;
} }
rw_lock_id = sys_rwlock.GetNewId(new RWLock((u32)attr->attr_protocol, (u32)attr->attr_pshared, rw_lock_id = sys_rwlock.GetNewId(new RWLock((u32)attr->attr_protocol, attr->name_u64));
(u64)attr->key, (s32)attr->flags, *(u64*)&attr->name));
sys_rwlock.Warning("*** rwlock created [%s] (protocol=0x%x): id=%d", sys_rwlock.Warning("*** rwlock created [%s] (protocol=0x%x): id=%d",
attr->name, (u32)attr->attr_protocol, rw_lock_id.GetValue()); attr->name, (u32)attr->attr_protocol, rw_lock_id.GetValue());

View File

@ -6,8 +6,12 @@ struct sys_rwlock_attribute_t
be_t<u32> attr_pshared; // == 0x200 (NOT SHARED) be_t<u32> attr_pshared; // == 0x200 (NOT SHARED)
be_t<u64> key; // process-shared key (not used) be_t<u64> key; // process-shared key (not used)
be_t<s32> flags; // process-shared flags (not used) be_t<s32> flags; // process-shared flags (not used)
be_t<u32> pad; be_t<u32> pad; // not used
char name[8]; union
{
char name[8];
u64 name_u64;
};
}; };
#pragma pack() #pragma pack()
@ -20,21 +24,15 @@ struct RWLock
Array<u32> rlock_list; // read lock list Array<u32> rlock_list; // read lock list
u32 m_protocol; // TODO u32 m_protocol; // TODO
u32 m_pshared; // not used
u64 m_key; // not used
s32 m_flags; // not used
union union
{ {
u64 m_name_data; // not used u64 m_name_u64;
char m_name[8]; char m_name[8];
}; };
RWLock(u32 protocol, u32 pshared, u64 key, s32 flags, u64 name) RWLock(u32 protocol, u64 name)
: m_protocol(protocol) : m_protocol(protocol)
, m_pshared(pshared) , m_name_u64(name)
, m_key(key)
, m_flags(flags)
, m_name_data(name)
, wlock_thread(0) , wlock_thread(0)
{ {
} }

View File

@ -194,13 +194,12 @@ int sys_spu_thread_get_exit_status(u32 id, mem32_t status)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!(*(SPUThread*)thr).SPU.Out_MBox.GetCount() || !thr->IsStopped()) u32 res;
if (!(*(SPUThread*)thr).SPU.Out_MBox.Pop(res) || !thr->IsStopped())
{ {
return CELL_ESTAT; return CELL_ESTAT;
} }
u32 res;
(*(SPUThread*)thr).SPU.Out_MBox.PopUncond(res);
status = res; status = res;
return CELL_OK; return CELL_OK;
} }

View File

@ -1,18 +1,28 @@
#pragma once #pragma once
enum EventQueueType
{
SYS_PPU_QUEUE = 1,
SYS_SPU_QUEUE = 2,
};
struct sys_event_queue_attr struct sys_event_queue_attr
{ {
u32 attr_protocol; be_t<u32> protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO
int type; be_t<int> type;
char name[8]; union
{
char name[8];
u64 name_u64;
};
}; };
struct sys_event_data struct sys_event_data
{ {
u64 source; be_t<u64> source;
u64 data1; be_t<u64> data1;
u64 data2; be_t<u64> data2;
u64 data3; be_t<u64> data3;
}; };
struct EventQueue; struct EventQueue;
@ -34,6 +44,19 @@ struct EventQueue
EventPort* ports[127]; EventPort* ports[127];
int size; int size;
int pos; int pos;
int type;
char name[8]; u32 m_protocol;
int m_type;
u64 m_name;
u64 m_key;
EventQueue(u32 protocol, int type, u64 name, u64 key, int size)
: m_type(type)
, m_protocol(protocol)
, m_name(name)
, m_key(key)
, size(size)
, pos(0)
{
}
}; };