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
#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)
{
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)
{
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;
return ch_in_mbox.push_uncond(CELL_ENOTCONN); // TODO: check error passing
}
if (queue->events.size() >= queue->size)
{
ch_in_mbox.push_uncond(CELL_EBUSY);
return;
return ch_in_mbox.push_uncond(CELL_EBUSY);
}
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)
{
@ -685,20 +683,22 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
if (!Emu.GetIdManager().GetIDData(data, ef))
{
ch_in_mbox.push_uncond(CELL_ESRCH);
return;
return ch_in_mbox.push_uncond(CELL_ESRCH);
}
while (ef->waiters < 0)
while (ef->cancelled)
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
ef->flags |= 1ull << flag;
ef->cv.notify_all();
ch_in_mbox.push_uncond(CELL_OK);
return;
if (ef->waiters)
{
ef->cv.notify_all();
}
return ch_in_mbox.push_uncond(CELL_OK);
}
else if (code == 192)
{
@ -732,13 +732,18 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
return;
}
while (ef->waiters < 0)
while (ef->cancelled)
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
ef->flags |= 1ull << flag;
ef->cv.notify_all();
if (ef->waiters)
{
ef->cv.notify_all();
}
return;
}
else
@ -958,8 +963,7 @@ void SPUThread::stop_and_signal(u32 code)
if (ch_in_mbox.get_count())
{
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;
return ch_in_mbox.push_uncond(CELL_EBUSY);
}
if (Ini.HLELogging.GetValue())
@ -986,20 +990,17 @@ void SPUThread::stop_and_signal(u32 code)
if (!queue)
{
ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value
return;
return ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value
}
// protocol is ignored in current implementation
queue->waiters++; assert(queue->waiters > 0);
queue->waiters++;
while (queue->events.empty())
{
if (queue->waiters < 0)
if (queue->cancelled)
{
queue->waiters--; assert(queue->waiters < 0);
ch_in_mbox.push_uncond(CELL_ECANCELED);
return;
return ch_in_mbox.push_uncond(CELL_ECANCELED);
}
if (Emu.IsStopped())
@ -1018,7 +1019,7 @@ void SPUThread::stop_and_signal(u32 code)
ch_in_mbox.push_uncond((u32)event.data3);
queue->events.pop_front();
queue->waiters--; assert(queue->waiters >= 0);
queue->waiters--;
if (queue->events.size())
{

View File

@ -14,14 +14,6 @@ enum MemoryType
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
{
std::vector<MemoryBlock*> MemoryBlocks;
@ -98,4 +90,3 @@ public:
extern MemoryBase Memory;
#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
cond->waiters++; assert(cond->waiters > 0);
cond->waiters++;
// unlock mutex
cond->mutex->owner.reset();
cond->mutex->cv.notify_one();
if (cond->mutex->waiters)
{
cond->mutex->cv.notify_one();
}
// save recursive value
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
cond->mutex->owner = thread;
cond->mutex->recursive_count = recursive_value;
cond->waiters--; assert(cond->waiters >= 0);
cond->waiters--;
return CELL_ETIMEDOUT;
}

View File

@ -24,7 +24,7 @@ struct cond_t
// TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv;
std::atomic<s32> waiters;
std::atomic<u32> waiters;
cond_t(std::shared_ptr<mutex_t>& mutex, u64 name)
: 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;
}
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));
if (!Emu.GetEventManager().RegisterKey(queue, event_queue_key))
{
return CELL_EAGAIN;
return CELL_EEXIST;
}
*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;
}
assert(queue->waiters >= 0);
if (!mode && queue->waiters)
{
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();
}
@ -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)
{
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;
@ -130,7 +125,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array,
s32 count = 0;
while (count < size && queue->events.size())
while (!queue->waiters && count < size && queue->events.size())
{
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) };
@ -140,11 +135,6 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array,
*number = count;
if (queue->events.size())
{
queue->cv.notify_one();
}
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
queue->waiters++; assert(queue->waiters > 0);
queue->waiters++;
while (queue->events.empty())
{
if (queue->waiters < 0)
if (queue->cancelled)
{
queue->waiters--; assert(queue->waiters < 0);
queue->waiters--;
return CELL_ECANCELED;
}
if (timeout && get_system_time() - start_time > timeout)
{
queue->waiters--; assert(queue->waiters >= 0);
queue->waiters--;
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;
queue->events.pop_front();
queue->waiters--; assert(queue->waiters >= 0);
if (queue->events.size())
{
queue->cv.notify_one();
}
queue->waiters--;
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;
}
LV2_LOCK;
std::shared_ptr<event_port_t> eport(new event_port_t(port_type, name));
*eport_id = Emu.GetIdManager().GetNewID(eport, TYPE_EVENT_PORT);

View File

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

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);
LV2_LOCK;
if (!id || !attr)
{
return CELL_EFAULT;
@ -69,11 +67,6 @@ s32 sys_event_flag_destroy(u32 id)
return CELL_ESRCH;
}
while (ef->waiters < 0)
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
if (ef->waiters)
{
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;
}
while (ef->waiters < 0)
while (ef->cancelled)
{
// wait until other threads return CELL_ECANCELED (to prevent modifying bit pattern)
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;
}
if (ef->waiters <= 0)
if (ef->cancelled)
{
ef->waiters++; assert(ef->waiters <= 0);
if (!ef->waiters)
if (!--ef->cancelled)
{
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)
{
ef->waiters--; assert(ef->waiters >= 0);
ef->waiters--;
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->waiters--; assert(ef->waiters >= 0);
if (ef->flags)
if (--ef->waiters && ef->flags)
{
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;
}
while (ef->waiters < 0)
while (ef->cancelled)
{
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;
}
while (ef->waiters < 0)
while (ef->cancelled)
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
ef->flags |= bitptn;
ef->cv.notify_all();
if (ef->waiters)
{
ef->cv.notify_all();
}
return CELL_OK;
}
@ -294,7 +287,7 @@ s32 sys_event_flag_clear(u32 id, u64 bitptn)
return CELL_ESRCH;
}
while (ef->waiters < 0)
while (ef->cancelled)
{
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;
}
while (ef->waiters < 0)
while (ef->cancelled)
{
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
@ -332,10 +325,11 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
*num = ef->waiters;
}
// negate value to signal waiting threads and prevent modifying bit pattern
ef->waiters = -ef->waiters;
ef->cv.notify_all();
if ((ef->cancelled = ef->waiters.exchange(0)))
{
ef->cv.notify_all();
}
return CELL_OK;
}

View File

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

View File

@ -38,6 +38,7 @@ s32 _sys_lwcond_destroy(u32 lwcond_id)
LV2_LOCK;
std::shared_ptr<lwcond_t> cond;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{
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;
std::shared_ptr<lwcond_t> cond;
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{
return CELL_ESRCH;
}
std::shared_ptr<lwmutex_t> mutex;
if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{
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->waiters--;
cond->cv.notify_one();
if (--cond->waiters)
{
cond->cv.notify_one();
}
return CELL_OK;
}
@ -130,12 +134,13 @@ s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode)
LV2_LOCK;
std::shared_ptr<lwcond_t> cond;
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{
return CELL_ESRCH;
}
std::shared_ptr<lwmutex_t> mutex;
if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{
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);
cond->cv.notify_all();
if (count)
{
cond->cv.notify_all();
}
if (mode == 1)
{
@ -176,12 +185,13 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout)
LV2_LOCK;
std::shared_ptr<lwcond_t> cond;
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
{
return CELL_ESRCH;
}
std::shared_ptr<lwmutex_t> mutex;
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
{
return CELL_ESRCH;
@ -189,10 +199,14 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout)
// finalize unlocking the mutex
mutex->signaled++;
mutex->cv.notify_one();
if (mutex->waiters)
{
mutex->cv.notify_one();
}
// protocol is ignored in current implementation
cond->waiters++; assert(cond->waiters > 0);
cond->waiters++;
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)
{
// cancel waiting
cond->waiters--; assert(cond->waiters >= 0);
cond->waiters--;
if (mutex->signaled)
{

View File

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

View File

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

View File

@ -76,7 +76,7 @@ struct lwmutex_t
// TODO: use sleep queue, possibly remove condition variable
std::condition_variable cv;
std::atomic<s32> waiters;
std::atomic<u32> waiters;
lwmutex_t(u32 protocol, u64 name)
: 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);
LV2_LOCK;
if (!mutex_id || !attr)
{
return CELL_EFAULT;
@ -119,13 +117,13 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
}
// protocol is ignored in current implementation
mutex->waiters++; assert(mutex->waiters > 0);
mutex->waiters++;
while (!mutex->owner.expired())
{
if (timeout && get_system_time() - start_time > timeout)
{
mutex->waiters--; assert(mutex->waiters >= 0);
mutex->waiters--;
return CELL_ETIMEDOUT;
}
@ -139,7 +137,7 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
}
mutex->owner = thread;
mutex->waiters--; assert(mutex->waiters >= 0);
mutex->waiters--;
return CELL_OK;
}
@ -218,7 +216,11 @@ s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id)
else
{
mutex->owner.reset();
mutex->cv.notify_one();
if (mutex->waiters)
{
mutex->cv.notify_one();
}
}
return CELL_OK;

View File

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

View File

@ -50,12 +50,13 @@ s32 sys_rwlock_destroy(u32 rw_lock_id)
LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{
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;
}
@ -74,15 +75,20 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout)
LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{
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)
{
rwlock->rwaiters--;
return CELL_ETIMEDOUT;
}
@ -92,10 +98,11 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout)
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->rwaiters--;
return CELL_OK;
}
@ -107,12 +114,13 @@ s32 sys_rwlock_tryrlock(u32 rw_lock_id)
LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{
return CELL_ESRCH;
}
if (rwlock->writer || rwlock->waiters)
if (rwlock->writer || rwlock->wwaiters)
{
return CELL_EBUSY;
}
@ -129,6 +137,7 @@ s32 sys_rwlock_runlock(u32 rw_lock_id)
LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{
return CELL_ESRCH;
@ -139,9 +148,9 @@ s32 sys_rwlock_runlock(u32 rw_lock_id)
return CELL_EPERM;
}
if (!--rwlock->readers)
if (!--rwlock->readers && rwlock->wwaiters)
{
rwlock->cv.notify_one();
rwlock->wcv.notify_one();
}
return CELL_OK;
@ -156,6 +165,7 @@ s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout)
LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{
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
rwlock->waiters++; assert(rwlock->waiters > 0);
rwlock->wwaiters++;
while (rwlock->readers || rwlock->writer)
{
if (timeout && get_system_time() - start_time > timeout)
{
rwlock->waiters--; assert(rwlock->waiters >= 0);
rwlock->wwaiters--;
return CELL_ETIMEDOUT;
}
@ -183,11 +193,11 @@ s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout)
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->waiters--; assert(rwlock->waiters >= 0);
rwlock->wwaiters--;
return CELL_OK;
}
@ -199,6 +209,7 @@ s32 sys_rwlock_trywlock(PPUThread& CPU, u32 rw_lock_id)
LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{
return CELL_ESRCH;
@ -209,7 +220,7 @@ s32 sys_rwlock_trywlock(PPUThread& CPU, u32 rw_lock_id)
return CELL_EDEADLK;
}
if (rwlock->readers || rwlock->writer || rwlock->waiters)
if (rwlock->readers || rwlock->writer || rwlock->wwaiters)
{
return CELL_EBUSY;
}
@ -226,6 +237,7 @@ s32 sys_rwlock_wunlock(PPUThread& CPU, u32 rw_lock_id)
LV2_LOCK;
std::shared_ptr<rwlock_t> rwlock;
if (!Emu.GetIdManager().GetIDData(rw_lock_id, rwlock))
{
return CELL_ESRCH;
@ -237,7 +249,15 @@ s32 sys_rwlock_wunlock(PPUThread& CPU, u32 rw_lock_id)
}
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;
}

View File

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

View File

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

View File

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

View File

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