Minor cleanup

This commit is contained in:
Nekotekina 2015-03-11 18:30:50 +03:00
parent db7bde0a6f
commit a3d400b5cc
20 changed files with 195 additions and 145 deletions

View file

@ -1,6 +1,14 @@
#pragma once #pragma once
#include "SPUThread.h" #include "SPUThread.h"
enum : u32
{
RAW_SPU_OFFSET = 0x00100000,
RAW_SPU_BASE_ADDR = 0xE0000000,
RAW_SPU_LS_OFFSET = 0x00000000,
RAW_SPU_PROB_OFFSET = 0x00040000,
};
__forceinline static u32 GetRawSPURegAddrByNum(int num, int offset) __forceinline static u32 GetRawSPURegAddrByNum(int num, int offset)
{ {
return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset; return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset;

View file

@ -604,19 +604,17 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
if (!queue) if (!queue)
{ {
LOG_WARNING(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data); LOG_WARNING(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data);
ch_in_mbox.push_uncond(CELL_ENOTCONN); // TODO: check error passing return ch_in_mbox.push_uncond(CELL_ENOTCONN); // TODO: check error passing
return;
} }
if (queue->events.size() >= queue->size) if (queue->events.size() >= queue->size)
{ {
ch_in_mbox.push_uncond(CELL_EBUSY); return ch_in_mbox.push_uncond(CELL_EBUSY);
return;
} }
queue->push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data); queue->push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data);
ch_in_mbox.push_uncond(CELL_OK);
return; return ch_in_mbox.push_uncond(CELL_OK);
} }
else if (code < 128) else if (code < 128)
{ {
@ -685,20 +683,22 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
if (!Emu.GetIdManager().GetIDData(data, ef)) if (!Emu.GetIdManager().GetIDData(data, ef))
{ {
ch_in_mbox.push_uncond(CELL_ESRCH); return ch_in_mbox.push_uncond(CELL_ESRCH);
return;
} }
while (ef->waiters < 0) while (ef->cancelled)
{ {
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
ef->flags |= 1ull << flag; ef->flags |= 1ull << flag;
ef->cv.notify_all();
ch_in_mbox.push_uncond(CELL_OK); if (ef->waiters)
return; {
ef->cv.notify_all();
}
return ch_in_mbox.push_uncond(CELL_OK);
} }
else if (code == 192) else if (code == 192)
{ {
@ -732,13 +732,18 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
return; return;
} }
while (ef->waiters < 0) while (ef->cancelled)
{ {
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
ef->flags |= 1ull << flag; ef->flags |= 1ull << flag;
if (ef->waiters)
{
ef->cv.notify_all(); ef->cv.notify_all();
}
return; return;
} }
else else
@ -958,8 +963,7 @@ void SPUThread::stop_and_signal(u32 code)
if (ch_in_mbox.get_count()) if (ch_in_mbox.get_count())
{ {
LOG_ERROR(SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq); LOG_ERROR(SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq);
ch_in_mbox.push_uncond(CELL_EBUSY); return ch_in_mbox.push_uncond(CELL_EBUSY);
return;
} }
if (Ini.HLELogging.GetValue()) if (Ini.HLELogging.GetValue())
@ -986,20 +990,17 @@ void SPUThread::stop_and_signal(u32 code)
if (!queue) if (!queue)
{ {
ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value return ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value
return;
} }
// protocol is ignored in current implementation // protocol is ignored in current implementation
queue->waiters++; assert(queue->waiters > 0); queue->waiters++;
while (queue->events.empty()) while (queue->events.empty())
{ {
if (queue->waiters < 0) if (queue->cancelled)
{ {
queue->waiters--; assert(queue->waiters < 0); return ch_in_mbox.push_uncond(CELL_ECANCELED);
ch_in_mbox.push_uncond(CELL_ECANCELED);
return;
} }
if (Emu.IsStopped()) if (Emu.IsStopped())
@ -1018,7 +1019,7 @@ void SPUThread::stop_and_signal(u32 code)
ch_in_mbox.push_uncond((u32)event.data3); ch_in_mbox.push_uncond((u32)event.data3);
queue->events.pop_front(); queue->events.pop_front();
queue->waiters--; assert(queue->waiters >= 0); queue->waiters--;
if (queue->events.size()) if (queue->events.size())
{ {

View file

@ -14,14 +14,6 @@ enum MemoryType
Memory_PSP, Memory_PSP,
}; };
enum : u32
{
RAW_SPU_OFFSET = 0x00100000,
RAW_SPU_BASE_ADDR = 0xE0000000,
RAW_SPU_LS_OFFSET = 0x00000000,
RAW_SPU_PROB_OFFSET = 0x00040000,
};
class MemoryBase class MemoryBase
{ {
std::vector<MemoryBlock*> MemoryBlocks; std::vector<MemoryBlock*> MemoryBlocks;
@ -98,4 +90,3 @@ public:
extern MemoryBase Memory; extern MemoryBase Memory;
#include "vm.h" #include "vm.h"

View file

@ -170,11 +170,15 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
} }
// protocol is ignored in current implementation // protocol is ignored in current implementation
cond->waiters++; assert(cond->waiters > 0); cond->waiters++;
// unlock mutex // unlock mutex
cond->mutex->owner.reset(); cond->mutex->owner.reset();
if (cond->mutex->waiters)
{
cond->mutex->cv.notify_one(); cond->mutex->cv.notify_one();
}
// save recursive value // save recursive value
const u32 recursive_value = cond->mutex->recursive_count.exchange(0); const u32 recursive_value = cond->mutex->recursive_count.exchange(0);
@ -189,7 +193,7 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
// cancel waiting if the mutex is free, restore its owner and recursive value // cancel waiting if the mutex is free, restore its owner and recursive value
cond->mutex->owner = thread; cond->mutex->owner = thread;
cond->mutex->recursive_count = recursive_value; cond->mutex->recursive_count = recursive_value;
cond->waiters--; assert(cond->waiters >= 0); cond->waiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }

View file

@ -24,7 +24,7 @@ struct cond_t
// TODO: use sleep queue, possibly remove condition variable // TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv; std::condition_variable cv;
std::atomic<s32> waiters; std::atomic<u32> waiters;
cond_t(std::shared_ptr<mutex_t>& mutex, u64 name) cond_t(std::shared_ptr<mutex_t>& mutex, u64 name)
: mutex(mutex) : mutex(mutex)

View file

@ -49,18 +49,11 @@ s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attr>
default: sys_event.Error("sys_event_queue_create(): unknown type (0x%x)", type); return CELL_EINVAL; default: sys_event.Error("sys_event_queue_create(): unknown type (0x%x)", type); return CELL_EINVAL;
} }
LV2_LOCK;
if (Emu.GetEventManager().CheckKey(event_queue_key))
{
return CELL_EEXIST;
}
std::shared_ptr<event_queue_t> queue(new event_queue_t(protocol, type, attr->name_u64, event_queue_key, size)); std::shared_ptr<event_queue_t> queue(new event_queue_t(protocol, type, attr->name_u64, event_queue_key, size));
if (!Emu.GetEventManager().RegisterKey(queue, event_queue_key)) if (!Emu.GetEventManager().RegisterKey(queue, event_queue_key))
{ {
return CELL_EAGAIN; return CELL_EEXIST;
} }
*equeue_id = Emu.GetIdManager().GetNewID(queue, TYPE_EVENT_QUEUE); *equeue_id = Emu.GetIdManager().GetNewID(queue, TYPE_EVENT_QUEUE);
@ -86,16 +79,18 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
return CELL_EINVAL; return CELL_EINVAL;
} }
assert(queue->waiters >= 0);
if (!mode && queue->waiters) if (!mode && queue->waiters)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
else
if (queue->cancelled.exchange(true))
{
throw __FUNCTION__;
}
if (queue->waiters)
{ {
// set special value for waiters
queue->waiters.exchange(-1);
queue->cv.notify_all(); queue->cv.notify_all();
} }
@ -107,7 +102,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array, s32 size, vm::ptr<u32> number) s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array, s32 size, vm::ptr<u32> number)
{ {
sys_event.Warning("sys_event_queue_tryreceive(equeue_id=%d, event_array=*0x%x, size=%d, number=*0x%x)", equeue_id, event_array, size, number); sys_event.Log("sys_event_queue_tryreceive(equeue_id=%d, event_array=*0x%x, size=%d, number=*0x%x)", equeue_id, event_array, size, number);
LV2_LOCK; LV2_LOCK;
@ -130,7 +125,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array,
s32 count = 0; s32 count = 0;
while (count < size && queue->events.size()) while (!queue->waiters && count < size && queue->events.size())
{ {
auto& event = queue->events.front(); auto& event = queue->events.front();
event_array[count++] = { be_t<u64>::make(event.source), be_t<u64>::make(event.data1), be_t<u64>::make(event.data2), be_t<u64>::make(event.data3) }; event_array[count++] = { be_t<u64>::make(event.source), be_t<u64>::make(event.data1), be_t<u64>::make(event.data2), be_t<u64>::make(event.data3) };
@ -140,11 +135,6 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array,
*number = count; *number = count;
if (queue->events.size())
{
queue->cv.notify_one();
}
return CELL_OK; return CELL_OK;
} }
@ -169,19 +159,19 @@ s32 sys_event_queue_receive(PPUThread& CPU, u32 equeue_id, vm::ptr<sys_event_t>
} }
// protocol is ignored in current implementation // protocol is ignored in current implementation
queue->waiters++; assert(queue->waiters > 0); queue->waiters++;
while (queue->events.empty()) while (queue->events.empty())
{ {
if (queue->waiters < 0) if (queue->cancelled)
{ {
queue->waiters--; assert(queue->waiters < 0); queue->waiters--;
return CELL_ECANCELED; return CELL_ECANCELED;
} }
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
queue->waiters--; assert(queue->waiters >= 0); queue->waiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
@ -202,12 +192,7 @@ s32 sys_event_queue_receive(PPUThread& CPU, u32 equeue_id, vm::ptr<sys_event_t>
CPU.GPR[7] = event.data3; CPU.GPR[7] = event.data3;
queue->events.pop_front(); queue->events.pop_front();
queue->waiters--; assert(queue->waiters >= 0); queue->waiters--;
if (queue->events.size())
{
queue->cv.notify_one();
}
return CELL_OK; return CELL_OK;
} }
@ -247,8 +232,6 @@ s32 sys_event_port_create(vm::ptr<u32> eport_id, s32 port_type, u64 name)
return CELL_EINVAL; return CELL_EINVAL;
} }
LV2_LOCK;
std::shared_ptr<event_port_t> eport(new event_port_t(port_type, name)); std::shared_ptr<event_port_t> eport(new event_port_t(port_type, name));
*eport_id = Emu.GetIdManager().GetNewID(eport, TYPE_EVENT_PORT); *eport_id = Emu.GetIdManager().GetNewID(eport, TYPE_EVENT_PORT);

View file

@ -78,10 +78,11 @@ struct event_queue_t
const s32 size; const s32 size;
std::deque<event_t> events; std::deque<event_t> events;
std::atomic<bool> cancelled;
// TODO: use sleep queue, possibly remove condition variable // TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv; std::condition_variable cv;
std::atomic<s32> waiters; std::atomic<u32> waiters;
event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size) event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size)
: protocol(protocol) : protocol(protocol)
@ -89,6 +90,7 @@ struct event_queue_t
, name(name) , name(name)
, key(key) , key(key)
, size(size) , size(size)
, cancelled(false)
, waiters(0) , waiters(0)
{ {
} }
@ -96,8 +98,12 @@ struct event_queue_t
void push(u64 source, u64 data1, u64 data2, u64 data3) void push(u64 source, u64 data1, u64 data2, u64 data3)
{ {
events.emplace_back(source, data1, data2, data3); events.emplace_back(source, data1, data2, data3);
if (waiters)
{
cv.notify_one(); cv.notify_one();
} }
}
}; };
struct event_port_t struct event_port_t

View file

@ -16,8 +16,6 @@ s32 sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attr> attr, u6
{ {
sys_event_flag.Warning("sys_event_flag_create(id=*0x%x, attr=*0x%x, init=0x%llx)", id, attr, init); sys_event_flag.Warning("sys_event_flag_create(id=*0x%x, attr=*0x%x, init=0x%llx)", id, attr, init);
LV2_LOCK;
if (!id || !attr) if (!id || !attr)
{ {
return CELL_EFAULT; return CELL_EFAULT;
@ -69,11 +67,6 @@ s32 sys_event_flag_destroy(u32 id)
return CELL_ESRCH; return CELL_ESRCH;
} }
while (ef->waiters < 0)
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
if (ef->waiters) if (ef->waiters)
{ {
return CELL_EBUSY; return CELL_EBUSY;
@ -124,7 +117,7 @@ s32 sys_event_flag_wait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 t
return CELL_EPERM; return CELL_EPERM;
} }
while (ef->waiters < 0) while (ef->cancelled)
{ {
// wait until other threads return CELL_ECANCELED (to prevent modifying bit pattern) // wait until other threads return CELL_ECANCELED (to prevent modifying bit pattern)
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
@ -150,11 +143,9 @@ s32 sys_event_flag_wait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 t
break; break;
} }
if (ef->waiters <= 0) if (ef->cancelled)
{ {
ef->waiters++; assert(ef->waiters <= 0); if (!--ef->cancelled)
if (!ef->waiters)
{ {
ef->cv.notify_all(); ef->cv.notify_all();
} }
@ -164,7 +155,7 @@ s32 sys_event_flag_wait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 t
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
ef->waiters--; assert(ef->waiters >= 0); ef->waiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
@ -187,9 +178,7 @@ s32 sys_event_flag_wait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 t
ef->flags = 0; ef->flags = 0;
} }
ef->waiters--; assert(ef->waiters >= 0); if (--ef->waiters && ef->flags)
if (ef->flags)
{ {
ef->cv.notify_one(); ef->cv.notify_one();
} }
@ -235,7 +224,7 @@ s32 sys_event_flag_trywait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result)
return CELL_EBUSY; return CELL_EBUSY;
} }
while (ef->waiters < 0) while (ef->cancelled)
{ {
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
@ -270,13 +259,17 @@ s32 sys_event_flag_set(u32 id, u64 bitptn)
return CELL_ESRCH; return CELL_ESRCH;
} }
while (ef->waiters < 0) while (ef->cancelled)
{ {
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
ef->flags |= bitptn; ef->flags |= bitptn;
if (ef->waiters)
{
ef->cv.notify_all(); ef->cv.notify_all();
}
return CELL_OK; return CELL_OK;
} }
@ -294,7 +287,7 @@ s32 sys_event_flag_clear(u32 id, u64 bitptn)
return CELL_ESRCH; return CELL_ESRCH;
} }
while (ef->waiters < 0) while (ef->cancelled)
{ {
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
@ -322,7 +315,7 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
return CELL_ESRCH; return CELL_ESRCH;
} }
while (ef->waiters < 0) while (ef->cancelled)
{ {
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
@ -332,9 +325,10 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
*num = ef->waiters; *num = ef->waiters;
} }
// negate value to signal waiting threads and prevent modifying bit pattern if ((ef->cancelled = ef->waiters.exchange(0)))
ef->waiters = -ef->waiters; {
ef->cv.notify_all(); ef->cv.notify_all();
}
return CELL_OK; return CELL_OK;
} }

View file

@ -34,10 +34,11 @@ struct event_flag_t
const u64 name; const u64 name;
std::atomic<u64> flags; std::atomic<u64> flags;
std::atomic<u32> cancelled;
// TODO: use sleep queue, possibly remove condition variable // TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv; std::condition_variable cv;
std::atomic<s32> waiters; std::atomic<u32> waiters;
event_flag_t(u64 pattern, u32 protocol, s32 type, u64 name) event_flag_t(u64 pattern, u32 protocol, s32 type, u64 name)
: flags(pattern) : flags(pattern)

View file

@ -38,6 +38,7 @@ s32 _sys_lwcond_destroy(u32 lwcond_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwcond_t> cond; std::shared_ptr<lwcond_t> cond;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -60,12 +61,13 @@ s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mod
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwcond_t> cond; std::shared_ptr<lwcond_t> cond;
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
std::shared_ptr<lwmutex_t> mutex;
if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -117,8 +119,10 @@ s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mod
cond->signaled1++; cond->signaled1++;
} }
cond->waiters--; if (--cond->waiters)
{
cond->cv.notify_one(); cond->cv.notify_one();
}
return CELL_OK; return CELL_OK;
} }
@ -130,12 +134,13 @@ s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwcond_t> cond; std::shared_ptr<lwcond_t> cond;
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
std::shared_ptr<lwmutex_t> mutex;
if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -147,7 +152,11 @@ s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode)
} }
const s32 count = cond->waiters.exchange(0); const s32 count = cond->waiters.exchange(0);
if (count)
{
cond->cv.notify_all(); cond->cv.notify_all();
}
if (mode == 1) if (mode == 1)
{ {
@ -176,12 +185,13 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwcond_t> cond; std::shared_ptr<lwcond_t> cond;
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -189,10 +199,14 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout)
// finalize unlocking the mutex // finalize unlocking the mutex
mutex->signaled++; mutex->signaled++;
if (mutex->waiters)
{
mutex->cv.notify_one(); mutex->cv.notify_one();
}
// protocol is ignored in current implementation // protocol is ignored in current implementation
cond->waiters++; assert(cond->waiters > 0); cond->waiters++;
while (!(cond->signaled1 && mutex->signaled) && !cond->signaled2) while (!(cond->signaled1 && mutex->signaled) && !cond->signaled2)
{ {
@ -202,7 +216,7 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout)
if (is_timedout && !cond->signaled1) if (is_timedout && !cond->signaled1)
{ {
// cancel waiting // cancel waiting
cond->waiters--; assert(cond->waiters >= 0); cond->waiters--;
if (mutex->signaled) if (mutex->signaled)
{ {

View file

@ -26,7 +26,7 @@ struct lwcond_t
// TODO: use sleep queue // TODO: use sleep queue
std::condition_variable cv; std::condition_variable cv;
std::atomic<s32> waiters; std::atomic<u32> waiters;
lwcond_t(u64 name) lwcond_t(u64 name)
: name(name) : name(name)

View file

@ -53,6 +53,7 @@ s32 _sys_lwmutex_destroy(u32 lwmutex_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwmutex_t> mutex; std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -77,19 +78,20 @@ s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwmutex_t> mutex; std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// protocol is ignored in current implementation // protocol is ignored in current implementation
mutex->waiters++; assert(mutex->waiters > 0); mutex->waiters++;
while (!mutex->signaled) while (!mutex->signaled)
{ {
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
mutex->waiters--; assert(mutex->waiters >= 0); mutex->waiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
@ -104,7 +106,7 @@ s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout)
mutex->signaled--; mutex->signaled--;
mutex->waiters--; assert(mutex->waiters >= 0); mutex->waiters--;
return CELL_OK; return CELL_OK;
} }
@ -116,6 +118,7 @@ s32 _sys_lwmutex_trylock(u32 lwmutex_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwmutex_t> mutex; std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -138,6 +141,7 @@ s32 _sys_lwmutex_unlock(u32 lwmutex_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lwmutex_t> mutex; std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -149,7 +153,11 @@ s32 _sys_lwmutex_unlock(u32 lwmutex_id)
} }
mutex->signaled++; mutex->signaled++;
if (mutex->waiters)
{
mutex->cv.notify_one(); mutex->cv.notify_one();
}
return CELL_OK; return CELL_OK;
} }

View file

@ -76,7 +76,7 @@ struct lwmutex_t
// TODO: use sleep queue, possibly remove condition variable // TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv; std::condition_variable cv;
std::atomic<s32> waiters; std::atomic<u32> waiters;
lwmutex_t(u32 protocol, u64 name) lwmutex_t(u32 protocol, u64 name)
: protocol(protocol) : protocol(protocol)

View file

@ -16,8 +16,6 @@ s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t> attr)
{ {
sys_mutex.Warning("sys_mutex_create(mutex_id=*0x%x, attr=*0x%x)", mutex_id, attr); sys_mutex.Warning("sys_mutex_create(mutex_id=*0x%x, attr=*0x%x)", mutex_id, attr);
LV2_LOCK;
if (!mutex_id || !attr) if (!mutex_id || !attr)
{ {
return CELL_EFAULT; return CELL_EFAULT;
@ -119,13 +117,13 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
} }
// protocol is ignored in current implementation // protocol is ignored in current implementation
mutex->waiters++; assert(mutex->waiters > 0); mutex->waiters++;
while (!mutex->owner.expired()) while (!mutex->owner.expired())
{ {
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
mutex->waiters--; assert(mutex->waiters >= 0); mutex->waiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
@ -139,7 +137,7 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
} }
mutex->owner = thread; mutex->owner = thread;
mutex->waiters--; assert(mutex->waiters >= 0); mutex->waiters--;
return CELL_OK; return CELL_OK;
} }
@ -218,8 +216,12 @@ s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id)
else else
{ {
mutex->owner.reset(); mutex->owner.reset();
if (mutex->waiters)
{
mutex->cv.notify_one(); mutex->cv.notify_one();
} }
}
return CELL_OK; return CELL_OK;
} }

View file

@ -29,7 +29,7 @@ struct mutex_t
// TODO: use sleep queue, possibly remove condition variable // TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv; std::condition_variable cv;
std::atomic<s32> waiters; std::atomic<u32> waiters;
mutex_t(bool recursive, u32 protocol, u64 name) mutex_t(bool recursive, u32 protocol, u64 name)
: recursive(recursive) : recursive(recursive)

View file

@ -50,12 +50,13 @@ s32 sys_rwlock_destroy(u32 rw_lock_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock; std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock)) if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
if (rwlock.use_count() > 2 || rwlock->readers || rwlock->writer || rwlock->waiters) if (rwlock->readers || rwlock->writer || rwlock->rwaiters || rwlock->wwaiters)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -74,15 +75,20 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock; std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock)) if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
while (rwlock->writer || rwlock->waiters) // waiting threads are not properly registered in current implementation
rwlock->rwaiters++;
while (rwlock->writer || rwlock->wwaiters)
{ {
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
rwlock->rwaiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
@ -92,10 +98,11 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout)
return CELL_OK; return CELL_OK;
} }
rwlock->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); rwlock->rcv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
rwlock->readers++; rwlock->readers++;
rwlock->rwaiters--;
return CELL_OK; return CELL_OK;
} }
@ -107,12 +114,13 @@ s32 sys_rwlock_tryrlock(u32 rw_lock_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock; std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock)) if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
if (rwlock->writer || rwlock->waiters) if (rwlock->writer || rwlock->wwaiters)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -129,6 +137,7 @@ s32 sys_rwlock_runlock(u32 rw_lock_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock; std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock)) if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -139,9 +148,9 @@ s32 sys_rwlock_runlock(u32 rw_lock_id)
return CELL_EPERM; return CELL_EPERM;
} }
if (!--rwlock->readers) if (!--rwlock->readers && rwlock->wwaiters)
{ {
rwlock->cv.notify_one(); rwlock->wcv.notify_one();
} }
return CELL_OK; return CELL_OK;
@ -156,6 +165,7 @@ s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock; std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock)) if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -167,13 +177,13 @@ s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout)
} }
// protocol is ignored in current implementation // protocol is ignored in current implementation
rwlock->waiters++; assert(rwlock->waiters > 0); rwlock->wwaiters++;
while (rwlock->readers || rwlock->writer) while (rwlock->readers || rwlock->writer)
{ {
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
rwlock->waiters--; assert(rwlock->waiters >= 0); rwlock->wwaiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
@ -183,11 +193,11 @@ s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout)
return CELL_OK; return CELL_OK;
} }
rwlock->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); rwlock->wcv.wait_for(lv2_lock, std::chrono::milliseconds(1));
} }
rwlock->writer = CPU.GetId(); rwlock->writer = CPU.GetId();
rwlock->waiters--; assert(rwlock->waiters >= 0); rwlock->wwaiters--;
return CELL_OK; return CELL_OK;
} }
@ -199,6 +209,7 @@ s32 sys_rwlock_trywlock(PPUThread& CPU, u32 rw_lock_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock; std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock)) if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -209,7 +220,7 @@ s32 sys_rwlock_trywlock(PPUThread& CPU, u32 rw_lock_id)
return CELL_EDEADLK; return CELL_EDEADLK;
} }
if (rwlock->readers || rwlock->writer || rwlock->waiters) if (rwlock->readers || rwlock->writer || rwlock->wwaiters)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -226,6 +237,7 @@ s32 sys_rwlock_wunlock(PPUThread& CPU, u32 rw_lock_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock; std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock)) if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -237,7 +249,15 @@ s32 sys_rwlock_wunlock(PPUThread& CPU, u32 rw_lock_id)
} }
rwlock->writer = 0; rwlock->writer = 0;
rwlock->cv.notify_all();
if (rwlock->wwaiters)
{
rwlock->wcv.notify_one();
}
else if (rwlock->rwaiters)
{
rwlock->rcv.notify_all();
}
return CELL_OK; return CELL_OK;
} }

View file

@ -23,16 +23,19 @@ struct rwlock_t
std::atomic<u32> readers; // reader count std::atomic<u32> readers; // reader count
std::atomic<u32> writer; // writer id std::atomic<u32> writer; // writer id
// TODO: use sleep queue, possibly remove condition variable // TODO: use sleep queue, possibly remove condition variables
std::condition_variable cv; std::condition_variable rcv;
std::atomic<s32> waiters; std::condition_variable wcv;
std::atomic<u32> rwaiters;
std::atomic<u32> wwaiters;
rwlock_t(u32 protocol, u64 name) rwlock_t(u32 protocol, u64 name)
: protocol(protocol) : protocol(protocol)
, name(name) , name(name)
, readers(0) , readers(0)
, writer(0) , writer(0)
, waiters(0) , rwaiters(0)
, wwaiters(0)
{ {
} }
}; };

View file

@ -62,6 +62,7 @@ s32 sys_semaphore_destroy(u32 sem)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<semaphore_t> semaphore; std::shared_ptr<semaphore_t> semaphore;
if (!Emu.GetIdManager().GetIDData(sem, semaphore)) if (!Emu.GetIdManager().GetIDData(sem, semaphore))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -86,19 +87,20 @@ s32 sys_semaphore_wait(u32 sem, u64 timeout)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<semaphore_t> semaphore; std::shared_ptr<semaphore_t> semaphore;
if (!Emu.GetIdManager().GetIDData(sem, semaphore)) if (!Emu.GetIdManager().GetIDData(sem, semaphore))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// protocol is ignored in current implementation // protocol is ignored in current implementation
semaphore->waiters++; assert(semaphore->waiters > 0); semaphore->waiters++;
while (semaphore->value <= 0) while (semaphore->value <= 0)
{ {
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
semaphore->waiters--; assert(semaphore->waiters >= 0); semaphore->waiters--;
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
@ -112,7 +114,7 @@ s32 sys_semaphore_wait(u32 sem, u64 timeout)
} }
semaphore->value--; semaphore->value--;
semaphore->waiters--; assert(semaphore->waiters >= 0); semaphore->waiters--;
return CELL_OK; return CELL_OK;
} }
@ -124,6 +126,7 @@ s32 sys_semaphore_trywait(u32 sem)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<semaphore_t> semaphore; std::shared_ptr<semaphore_t> semaphore;
if (!Emu.GetIdManager().GetIDData(sem, semaphore)) if (!Emu.GetIdManager().GetIDData(sem, semaphore))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -146,6 +149,7 @@ s32 sys_semaphore_post(u32 sem, s32 count)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<semaphore_t> semaphore; std::shared_ptr<semaphore_t> semaphore;
if (!Emu.GetIdManager().GetIDData(sem, semaphore)) if (!Emu.GetIdManager().GetIDData(sem, semaphore))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -156,13 +160,20 @@ s32 sys_semaphore_post(u32 sem, s32 count)
return CELL_EINVAL; return CELL_EINVAL;
} }
if (semaphore->value + count > semaphore->max + semaphore->waiters) const u64 new_value = semaphore->value + count;
const u64 max_value = semaphore->max + semaphore->waiters;
if (new_value > max_value)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
semaphore->value += count; assert(semaphore->value >= 0); semaphore->value += count;
if (semaphore->waiters)
{
semaphore->cv.notify_all(); semaphore->cv.notify_all();
}
return CELL_OK; return CELL_OK;
} }
@ -179,6 +190,7 @@ s32 sys_semaphore_get_value(u32 sem, vm::ptr<s32> count)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<semaphore_t> semaphore; std::shared_ptr<semaphore_t> semaphore;
if (!Emu.GetIdManager().GetIDData(sem, semaphore)) if (!Emu.GetIdManager().GetIDData(sem, semaphore))
{ {
return CELL_ESRCH; return CELL_ESRCH;

View file

@ -25,7 +25,7 @@ struct semaphore_t
// TODO: use sleep queue, possibly remove condition variable // TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv; std::condition_variable cv;
std::atomic<s32> waiters; std::atomic<u32> waiters;
semaphore_t(u32 protocol, s32 max, u64 name, s32 value) semaphore_t(u32 protocol, s32 max, u64 name, s32 value)
: protocol(protocol) : protocol(protocol)

View file

@ -32,8 +32,7 @@ s32 sys_timer_create(vm::ptr<u32> timer_id)
if (queue) if (queue)
{ {
queue->events.emplace_back(timer->source, timer->data1, timer->data2, timer->start); queue->push(timer->source, timer->data1, timer->data2, timer->start);
queue->cv.notify_one();
} }
if (timer->period && queue) if (timer->period && queue)
@ -64,6 +63,7 @@ s32 sys_timer_destroy(u32 timer_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lv2_timer_t> timer; std::shared_ptr<lv2_timer_t> timer;
if (!Emu.GetIdManager().GetIDData(timer_id, timer)) if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -86,6 +86,7 @@ s32 sys_timer_get_information(u32 timer_id, vm::ptr<sys_timer_information_t> inf
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lv2_timer_t> timer; std::shared_ptr<lv2_timer_t> timer;
if (!Emu.GetIdManager().GetIDData(timer_id, timer)) if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -94,7 +95,6 @@ s32 sys_timer_get_information(u32 timer_id, vm::ptr<sys_timer_information_t> inf
info->next_expiration_time = timer->start; info->next_expiration_time = timer->start;
info->period = timer->period; info->period = timer->period;
info->timer_state = timer->state; info->timer_state = timer->state;
return CELL_OK; return CELL_OK;
@ -109,6 +109,7 @@ s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lv2_timer_t> timer; std::shared_ptr<lv2_timer_t> timer;
if (!Emu.GetIdManager().GetIDData(timer_id, timer)) if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -160,6 +161,7 @@ s32 sys_timer_stop(u32 timer_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lv2_timer_t> timer; std::shared_ptr<lv2_timer_t> timer;
if (!Emu.GetIdManager().GetIDData(timer_id, timer)) if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{ {
return CELL_ESRCH; return CELL_ESRCH;
@ -204,6 +206,7 @@ s32 sys_timer_disconnect_event_queue(u32 timer_id)
LV2_LOCK; LV2_LOCK;
std::shared_ptr<lv2_timer_t> timer; std::shared_ptr<lv2_timer_t> timer;
if (!Emu.GetIdManager().GetIDData(timer_id, timer)) if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{ {
return CELL_ESRCH; return CELL_ESRCH;