IPC support for lv2 sync objects

This commit is contained in:
Nekotekina 2017-07-24 18:59:48 +03:00
parent 60c6bb9865
commit bf53035e3f
13 changed files with 231 additions and 113 deletions

View File

@ -2,6 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
@ -12,18 +13,14 @@ namespace vm { using namespace ps3; }
logs::channel sys_cond("sys_cond");
template<> DECLARE(ipc_manager<lv2_cond, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr)
{
sys_cond.warning("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr);
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
{
sys_cond.error("sys_cond_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
return CELL_EINVAL;
}
auto mutex = idm::get<lv2_obj, lv2_mutex>(mutex_id);
if (!mutex)
@ -31,13 +28,21 @@ error_code sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_
return CELL_ESRCH;
}
if (const u32 id = idm::make<lv2_obj, lv2_cond>(attr->name_u64, std::move(mutex)))
if (auto error = lv2_obj::create<lv2_cond>(attr->pshared, attr->ipc_key, attr->flags, [&]
{
*cond_id = id;
return CELL_OK;
return std::make_shared<lv2_cond>(
attr->pshared,
attr->flags,
attr->ipc_key,
attr->name_u64,
std::move(mutex));
}))
{
return error;
}
return CELL_EAGAIN;
*cond_id = idm::last_id();
return CELL_OK;
}
error_code sys_cond_destroy(u32 cond_id)
@ -51,7 +56,6 @@ error_code sys_cond_destroy(u32 cond_id)
return CELL_EBUSY;
}
cond.mutex->cond_count--;
return {};
});

View File

@ -30,15 +30,20 @@ struct lv2_cond final : lv2_obj
atomic_t<u32> waiters{0};
std::deque<cpu_thread*> sq;
lv2_cond(u64 name, std::shared_ptr<lv2_mutex> mutex)
: shared(0)
, key(0)
, flags(0)
lv2_cond(u32 shared, s32 flags, u64 key, u64 name, std::shared_ptr<lv2_mutex> mutex)
: shared(shared)
, key(key)
, flags(flags)
, name(name)
, mutex(std::move(mutex))
{
this->mutex->cond_count++;
}
~lv2_cond()
{
this->mutex->cond_count--;
}
};
class ppu_thread;

View File

@ -99,10 +99,12 @@ error_code sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queu
return CELL_EINVAL;
}
auto queue = std::make_shared<lv2_event_queue>(protocol, type, attr->name_u64, event_queue_key, size);
if (event_queue_key == SYS_EVENT_QUEUE_LOCAL)
{
// Not an IPC queue
if (const u32 _id = idm::make<lv2_obj, lv2_event_queue>(protocol, type, attr->name_u64, event_queue_key, size))
if (const u32 _id = idm::import_existing<lv2_obj, lv2_event_queue>(std::move(queue)))
{
*equeue_id = _id;
return CELL_OK;
@ -111,25 +113,27 @@ error_code sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queu
return CELL_EAGAIN;
}
std::shared_ptr<lv2_event_queue> result;
// Create IPC queue
if (!ipc_manager<lv2_event_queue, u64>::add(event_queue_key, [&]() -> const std::shared_ptr<lv2_event_queue>&
if (!ipc_manager<lv2_event_queue, u64>::add(event_queue_key, [&]() -> std::shared_ptr<lv2_event_queue>
{
result = idm::make_ptr<lv2_obj, lv2_event_queue>(protocol, type, attr->name_u64, event_queue_key, size);
return result;
if (const u32 _id = idm::import_existing<lv2_obj, lv2_event_queue>(queue))
{
*equeue_id = _id;
return std::move(queue);
}
return nullptr;
}))
{
return CELL_EEXIST;
}
if (result)
if (queue)
{
*equeue_id = idm::last_id();
return CELL_OK;
return CELL_EAGAIN;
}
return CELL_EAGAIN;
return CELL_OK;
}
error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)

View File

@ -2,6 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
@ -13,6 +14,8 @@ namespace vm { using namespace ps3; }
logs::channel sys_event_flag("sys_event_flag");
template<> DECLARE(ipc_manager<lv2_event_flag, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attribute_t> attr, u64 init)
@ -37,12 +40,6 @@ error_code sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attribu
return CELL_EINVAL;
}
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
{
sys_event_flag.error("sys_event_flag_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
return CELL_EINVAL;
}
const u32 type = attr->type;
if (type != SYS_SYNC_WAITER_SINGLE && type != SYS_SYNC_WAITER_MULTIPLE)
@ -51,13 +48,23 @@ error_code sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attribu
return CELL_EINVAL;
}
if (const u32 _id = idm::make<lv2_obj, lv2_event_flag>(protocol, type, attr->name_u64, init))
if (auto error = lv2_obj::create<lv2_event_flag>(attr->pshared, attr->ipc_key, attr->flags, [&]
{
*id = _id;
return CELL_OK;
return std::make_shared<lv2_event_flag>(
attr->protocol,
attr->pshared,
attr->ipc_key,
attr->flags,
attr->type,
attr->name_u64,
init);
}))
{
return error;
}
return CELL_EAGAIN;
*id = idm::last_id();
return CELL_OK;
}
error_code sys_event_flag_destroy(u32 id)

View File

@ -45,11 +45,11 @@ struct lv2_event_flag final : lv2_obj
atomic_t<u64> pattern;
std::deque<cpu_thread*> sq;
lv2_event_flag(u32 protocol, s32 type, u64 name, u64 pattern)
lv2_event_flag(u32 protocol, u32 shared, u64 key, s32 flags, s32 type, u64 name, u64 pattern)
: protocol(protocol)
, shared(0)
, key(0)
, flags(0)
, shared(shared)
, key(key)
, flags(flags)
, type(type)
, name(name)
, pattern(pattern)

View File

@ -2,6 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
@ -11,6 +12,8 @@ namespace vm { using namespace ps3; }
logs::channel sys_mutex("sys_mutex");
template<> DECLARE(ipc_manager<lv2_mutex, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t> attr)
@ -22,48 +25,53 @@ error_code sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t
return CELL_EFAULT;
}
const u32 protocol = attr->protocol;
switch (protocol)
switch (attr->protocol)
{
case SYS_SYNC_FIFO: break;
case SYS_SYNC_PRIORITY: break;
case SYS_SYNC_PRIORITY_INHERIT:
sys_mutex.todo("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT");
sys_mutex.fatal("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT");
break;
default:
{
sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", protocol);
sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", attr->protocol);
return CELL_EINVAL;
}
}
const u32 recursive = attr->recursive;
switch (recursive)
switch (attr->recursive)
{
case SYS_SYNC_RECURSIVE: break;
case SYS_SYNC_NOT_RECURSIVE: break;
default:
{
sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", recursive);
sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", attr->recursive);
return CELL_EINVAL;
}
}
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->adaptive != SYS_SYNC_NOT_ADAPTIVE || attr->ipc_key || attr->flags)
if (attr->adaptive != SYS_SYNC_NOT_ADAPTIVE)
{
sys_mutex.error("sys_mutex_create(): unknown attributes (pshared=0x%x, adaptive=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->adaptive, attr->ipc_key, attr->flags);
return CELL_EINVAL;
sys_mutex.todo("sys_mutex_create(): unexpected adaptive (0x%x)", attr->adaptive);
}
if (const u32 id = idm::make<lv2_obj, lv2_mutex>(protocol, recursive, attr->name_u64))
if (auto error = lv2_obj::create<lv2_mutex>(attr->pshared, attr->ipc_key, attr->flags, [&]()
{
*mutex_id = id;
return CELL_OK;
return std::make_shared<lv2_mutex>(
attr->protocol,
attr->recursive,
attr->pshared,
attr->adaptive,
attr->ipc_key,
attr->flags,
attr->name_u64);
}))
{
return error;
}
return CELL_EAGAIN;
*mutex_id = idm::last_id();
return CELL_OK;
}
error_code sys_mutex_destroy(u32 mutex_id)

View File

@ -37,13 +37,13 @@ struct lv2_mutex final : lv2_obj
atomic_t<u32> cond_count{0}; // Condition Variables
std::deque<cpu_thread*> sq;
lv2_mutex(u32 protocol, u32 recursive, u64 name)
lv2_mutex(u32 protocol, u32 recursive, u32 shared, u32 adaptive, u64 key, s32 flags, u64 name)
: protocol(protocol)
, recursive(recursive)
, shared(0)
, adaptive(0)
, key(0)
, flags(0)
, shared(shared)
, adaptive(adaptive)
, key(key)
, flags(flags)
, name(name)
{
}

View File

@ -2,6 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
@ -11,6 +12,8 @@ namespace vm { using namespace ps3; }
logs::channel sys_rwlock("sys_rwlock");
template<> DECLARE(ipc_manager<lv2_rwlock, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_rwlock_create(vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribute_t> attr)
@ -33,19 +36,16 @@ error_code sys_rwlock_create(vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribu
return CELL_EINVAL;
}
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
if (auto error = lv2_obj::create<lv2_rwlock>(attr->pshared, attr->ipc_key, attr->flags, [&]
{
sys_rwlock.error("sys_rwlock_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
return CELL_EINVAL;
return std::make_shared<lv2_rwlock>(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64);
}))
{
return error;
}
if (const u32 id = idm::make<lv2_obj, lv2_rwlock>(protocol, attr->name_u64))
{
*rw_lock_id = id;
return CELL_OK;
}
return CELL_EAGAIN;
*rw_lock_id = idm::last_id();
return CELL_OK;
}
error_code sys_rwlock_destroy(u32 rw_lock_id)

View File

@ -32,11 +32,11 @@ struct lv2_rwlock final : lv2_obj
std::deque<cpu_thread*> rq;
std::deque<cpu_thread*> wq;
lv2_rwlock(u32 protocol, u64 name)
lv2_rwlock(u32 protocol, u32 shared, u64 key, s32 flags, u64 name)
: protocol(protocol)
, shared(0)
, key(0)
, flags(0)
, shared(shared)
, key(key)
, flags(flags)
, name(name)
{
}

View File

@ -2,6 +2,7 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
@ -11,6 +12,8 @@ namespace vm { using namespace ps3; }
logs::channel sys_semaphore("sys_semaphore");
template<> DECLARE(ipc_manager<lv2_sema, u64>::g_ipc) {};
extern u64 get_system_time();
error_code sys_semaphore_create(vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val)
@ -39,19 +42,16 @@ error_code sys_semaphore_create(vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attri
return CELL_EINVAL;
}
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
if (auto error = lv2_obj::create<lv2_sema>(attr->pshared, attr->ipc_key, attr->flags, [&]
{
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 std::make_shared<lv2_sema>(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64, max_val, initial_val);
}))
{
return error;
}
if (const u32 id = idm::make<lv2_obj, lv2_sema>(protocol, attr->name_u64, max_val, initial_val))
{
*sem_id = id;
return CELL_OK;
}
return CELL_EAGAIN;
*sem_id = idm::last_id();
return CELL_OK;
}
error_code sys_semaphore_destroy(u32 sem_id)

View File

@ -32,11 +32,11 @@ struct lv2_sema final : lv2_obj
atomic_t<s32> val;
std::deque<cpu_thread*> sq;
lv2_sema(u32 protocol, u64 name, s32 max, s32 value)
lv2_sema(u32 protocol, u32 shared, u64 key, s32 flags, u64 name, s32 max, s32 value)
: protocol(protocol)
, shared(0)
, key(0)
, flags(0)
, shared(shared)
, key(key)
, flags(flags)
, name(name)
, max(max)
, val(value)

View File

@ -7,46 +7,52 @@
#include "Emu/Memory/vm.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include <deque>
// attr_protocol (waiting scheduling policy)
enum
{
// First In, First Out
SYS_SYNC_FIFO = 1,
// Priority Order
SYS_SYNC_PRIORITY = 2,
// Basic Priority Inheritance Protocol (probably not implemented)
SYS_SYNC_PRIORITY_INHERIT = 3,
// Not selected while unlocking
SYS_SYNC_RETRY = 4,
//
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF,
SYS_SYNC_FIFO = 0x1, // First In, First Out Order
SYS_SYNC_PRIORITY = 0x2, // Priority Order
SYS_SYNC_PRIORITY_INHERIT = 0x3, // Basic Priority Inheritance Protocol
SYS_SYNC_RETRY = 0x4, // Not selected while unlocking
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xf,
};
// attr_recursive (recursive locks policy)
enum
{
// Recursive locks are allowed
SYS_SYNC_RECURSIVE = 0x10,
// Recursive locks are NOT allowed
SYS_SYNC_NOT_RECURSIVE = 0x20,
//
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //???
SYS_SYNC_RECURSIVE = 0x10,
SYS_SYNC_NOT_RECURSIVE = 0x20,
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xf0,
};
// attr_pshared
// attr_pshared (sharing among processes policy)
enum
{
SYS_SYNC_NOT_PROCESS_SHARED = 0x200,
SYS_SYNC_PROCESS_SHARED = 0x100,
SYS_SYNC_NOT_PROCESS_SHARED = 0x200,
SYS_SYNC_ATTR_PSHARED_MASK = 0xf00,
};
// attr_flags (creation policy)
enum
{
SYS_SYNC_NEWLY_CREATED = 0x1, // Create new object, fails if specified IPC key exists
SYS_SYNC_NOT_CREATE = 0x2, // Reference existing object, fails if IPC key not found
SYS_SYNC_NOT_CARE = 0x3, // Reference existing object, create new one if IPC key not found
SYS_SYNC_ATTR_FLAGS_MASK = 0xf,
};
// attr_adaptive
enum
{
SYS_SYNC_ADAPTIVE = 0x1000,
SYS_SYNC_NOT_ADAPTIVE = 0x2000,
SYS_SYNC_ADAPTIVE = 0x1000,
SYS_SYNC_NOT_ADAPTIVE = 0x2000,
SYS_SYNC_ATTR_ADAPTIVE_MASK = 0xf000,
};
// Base class for some kernel objects (shared set of 8192 objects).
@ -126,6 +132,81 @@ struct lv2_obj
static void cleanup();
template <typename T, typename F>
static error_code create(u32 pshared, u64 ipc_key, s32 flags, F&& make)
{
switch (pshared)
{
case SYS_SYNC_PROCESS_SHARED:
{
switch (flags)
{
case SYS_SYNC_NEWLY_CREATED:
case SYS_SYNC_NOT_CARE:
{
std::shared_ptr<T> result = make();
if (!ipc_manager<T, u64>::add(ipc_key, [&] { if (!idm::import_existing<lv2_obj, T>(result)) result.reset(); return result; }, &result))
{
if (flags == SYS_SYNC_NEWLY_CREATED)
{
return CELL_EEXIST;
}
if (!idm::import_existing<lv2_obj, T>(result))
{
return CELL_EAGAIN;
}
return CELL_OK;
}
else if (!result)
{
return CELL_EAGAIN;
}
else
{
return CELL_OK;
}
}
case SYS_SYNC_NOT_CREATE:
{
auto result = ipc_manager<T, u64>::get(ipc_key);
if (!result)
{
return CELL_ESRCH;
}
if (!idm::import_existing<lv2_obj, T>(result))
{
return CELL_EAGAIN;
}
return CELL_OK;
}
default:
{
return CELL_EINVAL;
}
}
}
case SYS_SYNC_NOT_PROCESS_SHARED:
{
if (!idm::import<lv2_obj, T>(std::forward<F>(make)))
{
return CELL_EAGAIN;
}
return CELL_OK;
}
default:
{
return CELL_EINVAL;
}
}
}
private:
// Scheduler mutex
static semaphore<> g_mutex;

View File

@ -7,7 +7,7 @@
// IPC manager for objects of type T and IPC keys of type K.
// External declaration of g_ipc is required.
template<typename T, typename K>
template <typename T, typename K>
class ipc_manager final
{
std::unordered_map<K, std::weak_ptr<T>> m_map;
@ -18,18 +18,27 @@ class ipc_manager final
public:
// Add new object if specified ipc_key is not used
template<typename F>
static bool add(const K& ipc_key, F&& provider)
template <typename F>
static bool add(const K& ipc_key, F&& provider, std::shared_ptr<T>* out = nullptr)
{
writer_lock lock(g_ipc.m_mutex);
// Get object location
std::weak_ptr<T>& wptr = g_ipc.m_map[ipc_key];
if (wptr.expired())
if ((out && !(*out = wptr.lock())) || wptr.expired())
{
// Call a function which must return the object
wptr = provider();
if (out)
{
*out = provider();
wptr = *out;
}
else
{
wptr = provider();
}
return true;
}