mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-12 09:48:37 +12: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)
|
SemaphoreAttributes SyncPrimManager::GetSemaphoreData(u32 id)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Semaphore> sem;
|
std::shared_ptr<semaphore_t> sem;
|
||||||
if (!Emu.GetIdManager().GetIDData(id, sem))
|
if (!Emu.GetIdManager().GetIDData(id, sem))
|
||||||
{
|
{
|
||||||
return{};
|
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)
|
LwMutexAttributes SyncPrimManager::GetLwMutexData(u32 id)
|
||||||
|
|
|
@ -12,181 +12,141 @@
|
||||||
|
|
||||||
SysCallBase sys_semaphore("sys_semaphore");
|
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);
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)",
|
sys_semaphore.Warning("sys_semaphore_create(sem=*0x%x, attr=*0x%x, initial_val=%d, max_val=%d)", sem, attr, initial_val, max_val);
|
||||||
sem.addr(), attr.addr(), initial_count, max_count);
|
|
||||||
|
|
||||||
if (!sem)
|
if (!sem || !attr)
|
||||||
{
|
{
|
||||||
sys_semaphore.Error("sys_semaphore_create(): invalid memory access (sem_addr=0x%x)", sem.addr());
|
|
||||||
return CELL_EFAULT;
|
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());
|
sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_val=%d, max_val=%d)", initial_val, max_val);
|
||||||
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);
|
|
||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (attr->protocol.data())
|
const u32 protocol = attr->protocol;
|
||||||
|
|
||||||
|
switch (protocol)
|
||||||
{
|
{
|
||||||
case se32(SYS_SYNC_FIFO): break;
|
case SYS_SYNC_FIFO: break;
|
||||||
case se32(SYS_SYNC_PRIORITY): break;
|
case SYS_SYNC_PRIORITY: break;
|
||||||
case se32(SYS_SYNC_PRIORITY_INHERIT): break;
|
case SYS_SYNC_PRIORITY_INHERIT: break;
|
||||||
default: sys_semaphore.Error("Unknown protocol attribute (0x%x)", attr->protocol); return CELL_EINVAL;
|
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;
|
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;
|
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;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
||||||
|
std::shared_ptr<semaphore_t> semaphore;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sem->queue.count()) // TODO: safely make object unusable
|
if (semaphore->waiters)
|
||||||
{
|
{
|
||||||
return CELL_EBUSY;
|
return CELL_EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
Emu.GetIdManager().RemoveID(sem_id);
|
Emu.GetIdManager().RemoveID(sem);
|
||||||
|
|
||||||
return CELL_OK;
|
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();
|
const u64 start_time = get_system_time();
|
||||||
|
|
||||||
std::shared_ptr<Semaphore> sem;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
||||||
|
std::shared_ptr<semaphore_t> semaphore;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 tid = GetCurrentPPUThread().GetId();
|
// protocol is ignored in current implementation
|
||||||
s32 old_value;
|
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 (timeout && get_system_time() - start_time > timeout)
|
||||||
{
|
{
|
||||||
if (!sem->queue.invalidate(tid, sem->protocol))
|
semaphore->waiters--; assert(semaphore->waiters >= 0);
|
||||||
{
|
|
||||||
if (sem->queue.pop(tid, sem->protocol))
|
|
||||||
{
|
|
||||||
return CELL_OK;
|
|
||||||
}
|
|
||||||
assert(!"sys_semaphore_wait() failed (timeout)");
|
|
||||||
}
|
|
||||||
return CELL_ETIMEDOUT;
|
return CELL_ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Emu.IsStopped())
|
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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
semaphore->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
semaphore->value--;
|
||||||
|
semaphore->waiters--; assert(semaphore->waiters >= 0);
|
||||||
|
|
||||||
return CELL_OK;
|
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;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
||||||
|
std::shared_ptr<semaphore_t> semaphore;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 old_value;
|
if (semaphore->value <= 0 || semaphore->waiters)
|
||||||
|
|
||||||
sem->value.atomic_op_sync([&old_value](s32& value)
|
|
||||||
{
|
|
||||||
old_value = value;
|
|
||||||
if (value > 0)
|
|
||||||
{
|
|
||||||
value--;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (old_value > 0)
|
|
||||||
{
|
|
||||||
return CELL_OK;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return CELL_EBUSY;
|
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;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
||||||
|
std::shared_ptr<semaphore_t> semaphore;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
@ -196,52 +156,35 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
|
||||||
return CELL_EINVAL;
|
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;
|
return CELL_EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (count > 0)
|
semaphore->value += count; assert(semaphore->value >= 0);
|
||||||
{
|
semaphore->cv.notify_all();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CELL_OK;
|
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)
|
if (!count)
|
||||||
{
|
{
|
||||||
sys_semaphore.Error("sys_semaphore_get_value(): invalid memory access (addr=0x%x)", count.addr());
|
|
||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Semaphore> sem;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(sem_id, sem))
|
|
||||||
|
std::shared_ptr<semaphore_t> semaphore;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(sem, semaphore))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
*count = sem->value.read_sync();
|
*count = std::max<s32>(0, semaphore->value - semaphore->waiters);
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct sys_semaphore_attribute
|
struct sys_semaphore_attribute_t
|
||||||
{
|
{
|
||||||
be_t<u32> protocol;
|
be_t<u32> protocol;
|
||||||
be_t<u32> pshared; // undefined
|
be_t<u32> pshared;
|
||||||
be_t<u64> ipc_key; // undefined
|
be_t<u64> ipc_key;
|
||||||
be_t<s32> flags; // undefined
|
be_t<s32> flags;
|
||||||
be_t<u32> pad; // not used
|
be_t<u32> pad;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
char name[8];
|
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 u32 protocol;
|
||||||
|
const s32 max;
|
||||||
const u64 name;
|
const u64 name;
|
||||||
|
|
||||||
Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name)
|
std::atomic<s32> value;
|
||||||
: max(max_count)
|
|
||||||
, protocol(protocol)
|
// 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)
|
, name(name)
|
||||||
|
, value(value)
|
||||||
|
, waiters(0)
|
||||||
{
|
{
|
||||||
value.write_relaxed(initial_count);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Aux
|
// 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
|
// SysCalls
|
||||||
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);
|
||||||
s32 sys_semaphore_destroy(u32 sem_id);
|
s32 sys_semaphore_destroy(u32 sem);
|
||||||
s32 sys_semaphore_wait(u32 sem_id, u64 timeout);
|
s32 sys_semaphore_wait(u32 sem, u64 timeout);
|
||||||
s32 sys_semaphore_trywait(u32 sem_id);
|
s32 sys_semaphore_trywait(u32 sem);
|
||||||
s32 sys_semaphore_post(u32 sem_id, s32 count);
|
s32 sys_semaphore_post(u32 sem, s32 count);
|
||||||
s32 sys_semaphore_get_value(u32 sem_id, vm::ptr<s32> count);
|
s32 sys_semaphore_get_value(u32 sem, vm::ptr<s32> count);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue