mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
Lv2 Semaphore rewritten
This commit is contained in:
parent
dba249554d
commit
0f233beff9
3 changed files with 100 additions and 152 deletions
|
@ -14,13 +14,13 @@
|
|||
|
||||
SemaphoreAttributes SyncPrimManager::GetSemaphoreData(u32 id)
|
||||
{
|
||||
std::shared_ptr<Semaphore> sem;
|
||||
std::shared_ptr<semaphore_t> sem;
|
||||
if (!Emu.GetIdManager().GetIDData(id, sem))
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
return{ std::string((const char*)&sem->name, 8), sem->value.read_sync(), sem->max };
|
||||
return{ std::string((const char*)&sem->name, 8), sem->value, sem->max };
|
||||
}
|
||||
|
||||
LwMutexAttributes SyncPrimManager::GetLwMutexData(u32 id)
|
||||
|
|
|
@ -12,181 +12,141 @@
|
|||
|
||||
SysCallBase sys_semaphore("sys_semaphore");
|
||||
|
||||
u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64)
|
||||
u32 semaphore_create(s32 initial_val, s32 max_val, u32 protocol, u64 name_u64)
|
||||
{
|
||||
std::shared_ptr<Semaphore> sem(new Semaphore(initial_count, max_count, protocol, name_u64));
|
||||
std::shared_ptr<semaphore_t> sem(new semaphore_t(protocol, max_val, name_u64, initial_val));
|
||||
|
||||
const u32 id = Emu.GetIdManager().GetNewID(sem, TYPE_SEMAPHORE);
|
||||
sem->queue.set_full_name(fmt::Format("Semaphore(%d)", id));
|
||||
|
||||
sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), protocol, id);
|
||||
return id;
|
||||
return Emu.GetIdManager().GetNewID(sem, TYPE_SEMAPHORE);
|
||||
}
|
||||
|
||||
s32 sys_semaphore_create(vm::ptr<u32> sem, vm::ptr<sys_semaphore_attribute> attr, s32 initial_count, s32 max_count)
|
||||
s32 sys_semaphore_create(vm::ptr<u32> sem, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val)
|
||||
{
|
||||
sys_semaphore.Warning("sys_semaphore_create(sem_addr=0x%x, attr_addr=0x%x, initial_count=%d, max_count=%d)",
|
||||
sem.addr(), attr.addr(), initial_count, max_count);
|
||||
sys_semaphore.Warning("sys_semaphore_create(sem=*0x%x, attr=*0x%x, initial_val=%d, max_val=%d)", sem, attr, initial_val, max_val);
|
||||
|
||||
if (!sem)
|
||||
if (!sem || !attr)
|
||||
{
|
||||
sys_semaphore.Error("sys_semaphore_create(): invalid memory access (sem_addr=0x%x)", sem.addr());
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
if (!attr)
|
||||
if (max_val <= 0 || initial_val > max_val || initial_val < 0)
|
||||
{
|
||||
sys_semaphore.Error("sys_semaphore_create(): An invalid argument value is specified (attr_addr=0x%x)", attr.addr());
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
if (max_count <= 0 || initial_count > max_count || initial_count < 0)
|
||||
{
|
||||
sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_count=%d, max_count=%d)", initial_count, max_count);
|
||||
sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_val=%d, max_val=%d)", initial_val, max_val);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
switch (attr->protocol.data())
|
||||
const u32 protocol = attr->protocol;
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case se32(SYS_SYNC_FIFO): break;
|
||||
case se32(SYS_SYNC_PRIORITY): break;
|
||||
case se32(SYS_SYNC_PRIORITY_INHERIT): break;
|
||||
default: sys_semaphore.Error("Unknown protocol attribute (0x%x)", attr->protocol); return CELL_EINVAL;
|
||||
case SYS_SYNC_FIFO: break;
|
||||
case SYS_SYNC_PRIORITY: break;
|
||||
case SYS_SYNC_PRIORITY_INHERIT: break;
|
||||
default: sys_semaphore.Error("sys_semaphore_create(): unknown protocol (0x%x)", protocol); return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (attr->pshared.data() != se32(0x200))
|
||||
if (attr->pshared.data() != se32(0x200) || attr->ipc_key.data() || attr->flags.data())
|
||||
{
|
||||
sys_semaphore.Error("Unknown pshared attribute (0x%x)", attr->pshared);
|
||||
sys_semaphore.Error("sys_semaphore_create(): unknown attributes (pshared=0x%x, ipc_key=0x%x, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
*sem = semaphore_create(initial_count, max_count, attr->protocol, attr->name_u64);
|
||||
*sem = semaphore_create(initial_val, max_val, protocol, attr->name_u64);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_semaphore_destroy(u32 sem_id)
|
||||
s32 sys_semaphore_destroy(u32 sem)
|
||||
{
|
||||
sys_semaphore.Warning("sys_semaphore_destroy(sem_id=%d)", sem_id);
|
||||
sys_semaphore.Warning("sys_semaphore_destroy(sem=%d)", sem);
|
||||
|
||||
std::shared_ptr<Semaphore> sem;
|
||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<semaphore_t> semaphore;
|
||||
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (sem->queue.count()) // TODO: safely make object unusable
|
||||
if (semaphore->waiters)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(sem_id);
|
||||
Emu.GetIdManager().RemoveID(sem);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_semaphore_wait(u32 sem_id, u64 timeout)
|
||||
s32 sys_semaphore_wait(u32 sem, u64 timeout)
|
||||
{
|
||||
sys_semaphore.Log("sys_semaphore_wait(sem_id=%d, timeout=%lld)", sem_id, timeout);
|
||||
sys_semaphore.Log("sys_semaphore_wait(sem=%d, timeout=0x%llx)", sem, timeout);
|
||||
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
std::shared_ptr<Semaphore> sem;
|
||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<semaphore_t> semaphore;
|
||||
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
const u32 tid = GetCurrentPPUThread().GetId();
|
||||
s32 old_value;
|
||||
// protocol is ignored in current implementation
|
||||
semaphore->waiters++; assert(semaphore->waiters > 0);
|
||||
|
||||
while (semaphore->value <= 0)
|
||||
{
|
||||
sem->value.atomic_op_sync([&old_value](s32& value)
|
||||
{
|
||||
old_value = value;
|
||||
if (value > 0)
|
||||
{
|
||||
value--;
|
||||
}
|
||||
});
|
||||
|
||||
if (old_value > 0)
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
sem->queue.push(tid, sem->protocol);
|
||||
}
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (sem->queue.pop(tid, sem->protocol))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
assert(!sem->value.read_sync());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
|
||||
if (timeout && get_system_time() - start_time > timeout)
|
||||
{
|
||||
if (!sem->queue.invalidate(tid, sem->protocol))
|
||||
{
|
||||
if (sem->queue.pop(tid, sem->protocol))
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
assert(!"sys_semaphore_wait() failed (timeout)");
|
||||
}
|
||||
semaphore->waiters--; assert(semaphore->waiters >= 0);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem_id);
|
||||
sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
semaphore->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
semaphore->value--;
|
||||
semaphore->waiters--; assert(semaphore->waiters >= 0);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_semaphore_trywait(u32 sem_id)
|
||||
s32 sys_semaphore_trywait(u32 sem)
|
||||
{
|
||||
sys_semaphore.Log("sys_semaphore_trywait(sem_id=%d)", sem_id);
|
||||
sys_semaphore.Log("sys_semaphore_trywait(sem=%d)", sem);
|
||||
|
||||
std::shared_ptr<Semaphore> sem;
|
||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<semaphore_t> semaphore;
|
||||
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
s32 old_value;
|
||||
|
||||
sem->value.atomic_op_sync([&old_value](s32& value)
|
||||
{
|
||||
old_value = value;
|
||||
if (value > 0)
|
||||
{
|
||||
value--;
|
||||
}
|
||||
});
|
||||
|
||||
if (old_value > 0)
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
if (semaphore->value <= 0 || semaphore->waiters)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
semaphore->value--;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_semaphore_post(u32 sem_id, s32 count)
|
||||
s32 sys_semaphore_post(u32 sem, s32 count)
|
||||
{
|
||||
sys_semaphore.Log("sys_semaphore_post(sem_id=%d, count=%d)", sem_id, count);
|
||||
sys_semaphore.Log("sys_semaphore_post(sem=%d, count=%d)", sem, count);
|
||||
|
||||
std::shared_ptr<Semaphore> sem;
|
||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<semaphore_t> semaphore;
|
||||
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
@ -196,52 +156,35 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
|
|||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (count + sem->value.read_sync() - (s32)sem->queue.count() > sem->max)
|
||||
if (semaphore->value + count > semaphore->max + semaphore->waiters)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sys_semaphore.Warning("sys_semaphore_post(%d) aborted", sem_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (u32 target = sem->queue.signal(sem->protocol))
|
||||
{
|
||||
count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
sem->value.atomic_op([count](s32& value)
|
||||
{
|
||||
value += count;
|
||||
});
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
semaphore->value += count; assert(semaphore->value >= 0);
|
||||
semaphore->cv.notify_all();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_semaphore_get_value(u32 sem_id, vm::ptr<s32> count)
|
||||
s32 sys_semaphore_get_value(u32 sem, vm::ptr<s32> count)
|
||||
{
|
||||
sys_semaphore.Log("sys_semaphore_get_value(sem_id=%d, count_addr=0x%x)", sem_id, count.addr());
|
||||
sys_semaphore.Log("sys_semaphore_get_value(sem=%d, count=*0x%x)", sem, count);
|
||||
|
||||
if (!count)
|
||||
{
|
||||
sys_semaphore.Error("sys_semaphore_get_value(): invalid memory access (addr=0x%x)", count.addr());
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
std::shared_ptr<Semaphore> sem;
|
||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<semaphore_t> semaphore;
|
||||
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
*count = sem->value.read_sync();
|
||||
*count = std::max<s32>(0, semaphore->value - semaphore->waiters);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
struct sys_semaphore_attribute
|
||||
struct sys_semaphore_attribute_t
|
||||
{
|
||||
be_t<u32> protocol;
|
||||
be_t<u32> pshared; // undefined
|
||||
be_t<u64> ipc_key; // undefined
|
||||
be_t<s32> flags; // undefined
|
||||
be_t<u32> pad; // not used
|
||||
be_t<u32> pshared;
|
||||
be_t<u64> ipc_key;
|
||||
be_t<s32> flags;
|
||||
be_t<u32> pad;
|
||||
|
||||
union
|
||||
{
|
||||
char name[8];
|
||||
|
@ -14,31 +15,35 @@ struct sys_semaphore_attribute
|
|||
};
|
||||
};
|
||||
|
||||
struct Semaphore
|
||||
struct semaphore_t
|
||||
{
|
||||
sleep_queue_t queue;
|
||||
atomic_le_t<s32> value;
|
||||
|
||||
const s32 max;
|
||||
const u32 protocol;
|
||||
const s32 max;
|
||||
const u64 name;
|
||||
|
||||
Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name)
|
||||
: max(max_count)
|
||||
, protocol(protocol)
|
||||
std::atomic<s32> value;
|
||||
|
||||
// TODO: use sleep queue, possibly remove condition variable
|
||||
std::condition_variable cv;
|
||||
std::atomic<s32> waiters;
|
||||
|
||||
semaphore_t(u32 protocol, s32 max, u64 name, s32 value)
|
||||
: protocol(protocol)
|
||||
, max(max)
|
||||
, name(name)
|
||||
, value(value)
|
||||
, waiters(0)
|
||||
{
|
||||
value.write_relaxed(initial_count);
|
||||
}
|
||||
};
|
||||
|
||||
// Aux
|
||||
u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64);
|
||||
u32 semaphore_create(s32 initial_val, s32 max_val, u32 protocol, u64 name_u64);
|
||||
|
||||
// SysCalls
|
||||
s32 sys_semaphore_create(vm::ptr<u32> sem, vm::ptr<sys_semaphore_attribute> attr, s32 initial_count, s32 max_count);
|
||||
s32 sys_semaphore_destroy(u32 sem_id);
|
||||
s32 sys_semaphore_wait(u32 sem_id, u64 timeout);
|
||||
s32 sys_semaphore_trywait(u32 sem_id);
|
||||
s32 sys_semaphore_post(u32 sem_id, s32 count);
|
||||
s32 sys_semaphore_get_value(u32 sem_id, vm::ptr<s32> count);
|
||||
s32 sys_semaphore_create(vm::ptr<u32> sem, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val);
|
||||
s32 sys_semaphore_destroy(u32 sem);
|
||||
s32 sys_semaphore_wait(u32 sem, u64 timeout);
|
||||
s32 sys_semaphore_trywait(u32 sem);
|
||||
s32 sys_semaphore_post(u32 sem, s32 count);
|
||||
s32 sys_semaphore_get_value(u32 sem, vm::ptr<s32> count);
|
||||
|
|
Loading…
Add table
Reference in a new issue