mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-21 09:40:01 +00:00
Merge pull request #1033 from Nekotekina/master
Cleanup, lv2 timer/lwmutex/lwcond rewritten
This commit is contained in:
commit
db7bde0a6f
@ -677,12 +677,12 @@ SceFiosDate sceFiosDateGetCurrent()
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
||||
SceFiosDate sceFiosDateFromComponents(const struct vm::psv::ptr<tm> pComponents)
|
||||
SceFiosDate sceFiosDateFromComponents(vm::psv::ptr<const tm> pComponents)
|
||||
{
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
||||
struct vm::psv::ptr<tm> sceFiosDateToComponents(SceFiosDate date, struct vm::psv::ptr<tm> pOutComponents)
|
||||
vm::psv::ptr<tm> sceFiosDateToComponents(SceFiosDate date, vm::psv::ptr<tm> pOutComponents)
|
||||
{
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
@ -175,8 +175,6 @@ namespace sce_libc_func
|
||||
void exit(ARMv7Context& context)
|
||||
{
|
||||
sceLibc.Warning("exit()");
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
for (auto func : g_atexit)
|
||||
{
|
||||
|
@ -287,7 +287,7 @@ struct SceNpMatching2RoomGroup
|
||||
|
||||
struct SceNpMatching2RoomMemberDataExternal
|
||||
{
|
||||
struct vm::psv::ptr<SceNpMatching2RoomMemberDataExternal> next;
|
||||
vm::psv::ptr<SceNpMatching2RoomMemberDataExternal> next;
|
||||
SceNpId npId;
|
||||
u64 joinDate;
|
||||
SceNpMatching2Role role;
|
||||
@ -297,7 +297,7 @@ struct SceNpMatching2RoomMemberDataExternal
|
||||
|
||||
struct SceNpMatching2RoomMemberDataInternal
|
||||
{
|
||||
struct vm::psv::ptr<SceNpMatching2RoomMemberDataInternal> next;
|
||||
vm::psv::ptr<SceNpMatching2RoomMemberDataInternal> next;
|
||||
SceNpId npId;
|
||||
|
||||
u64 joinDate;
|
||||
|
@ -106,7 +106,7 @@ void CPUThreadManager::RemoveThread(u32 id)
|
||||
}
|
||||
|
||||
// Removing the ID should trigger the actual deletion of the thread
|
||||
Emu.GetIdManager().RemoveID(id);
|
||||
Emu.GetIdManager().RemoveID<CPUThread>(id);
|
||||
Emu.CheckStatus();
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
#define ID_MANAGER_INCLUDED
|
||||
|
||||
#define rID_ANY -1 // was wxID_ANY
|
||||
|
||||
enum IDType
|
||||
{
|
||||
// Special objects
|
||||
@ -133,11 +131,13 @@ public:
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool CheckID(const u32 id)
|
||||
template<typename T> bool CheckID(const u32 id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mtx_main);
|
||||
|
||||
return m_id_map.find(id) != m_id_map.end();
|
||||
auto f = m_id_map.find(id);
|
||||
|
||||
return f != m_id_map.end() && f->second.GetInfo() == typeid(T);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
@ -148,12 +148,7 @@ public:
|
||||
m_cur_id = s_first_id;
|
||||
}
|
||||
|
||||
template<typename T
|
||||
#ifdef __GNUG__
|
||||
= char
|
||||
#endif
|
||||
>
|
||||
u32 GetNewID(std::shared_ptr<T>& data = nullptr, const IDType type = TYPE_OTHER)
|
||||
template<typename T> u32 GetNewID(std::shared_ptr<T>& data, const IDType type = TYPE_OTHER)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mtx_main);
|
||||
|
||||
@ -172,12 +167,12 @@ public:
|
||||
return m_id_map[id];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool GetIDData(const u32 id, std::shared_ptr<T>& result)
|
||||
template<typename T> bool GetIDData(const u32 id, std::shared_ptr<T>& result)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mtx_main);
|
||||
|
||||
auto f = m_id_map.find(id);
|
||||
|
||||
if (f == m_id_map.end() || f->second.GetInfo() != typeid(T)) {
|
||||
return false;
|
||||
}
|
||||
@ -189,23 +184,18 @@ public:
|
||||
|
||||
bool HasID(const u32 id)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mtx_main);
|
||||
std::lock_guard<std::mutex> lock(m_mtx_main);
|
||||
|
||||
if(id == rID_ANY) {
|
||||
return m_id_map.begin() != m_id_map.end();
|
||||
}
|
||||
}
|
||||
return CheckID(id);
|
||||
return m_id_map.find(id) != m_id_map.end();
|
||||
}
|
||||
|
||||
bool RemoveID(const u32 id)
|
||||
template<typename T> bool RemoveID(const u32 id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mtx_main);
|
||||
|
||||
auto item = m_id_map.find(id);
|
||||
|
||||
if (item == m_id_map.end()) {
|
||||
if (item == m_id_map.end() || item->second.GetInfo() != typeid(T)) {
|
||||
return false;
|
||||
}
|
||||
if (item->second.GetType() < TYPE_OTHER) {
|
||||
|
@ -195,29 +195,68 @@ public:
|
||||
const atomic_type res = InterlockedXor(&data, (atomic_type&)(right)) ^ (atomic_type&)(right);
|
||||
return (T&)res;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T> struct atomic_le_t : public _atomic_base<T>
|
||||
template<typename T> inline static typename std::enable_if<std::is_arithmetic<T>::value, T>::type operator ++(_atomic_base<be_t<T>>& left, int)
|
||||
{
|
||||
};
|
||||
T result;
|
||||
|
||||
template<typename T> struct atomic_be_t : public _atomic_base<typename to_be_t<T>::type>
|
||||
left.atomic_op([&result](be_t<T>& value)
|
||||
{
|
||||
result = value++;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> inline static typename std::enable_if<std::is_arithmetic<T>::value, T>::type operator --(_atomic_base<be_t<T>>& left, int)
|
||||
{
|
||||
};
|
||||
T result;
|
||||
|
||||
left.atomic_op([&result](be_t<T>& value)
|
||||
{
|
||||
result = value--;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename T2> inline static typename std::enable_if<std::is_arithmetic<T>::value, T>::type operator +=(_atomic_base<be_t<T>>& left, T2 right)
|
||||
{
|
||||
T result;
|
||||
|
||||
left.atomic_op([&result, right](be_t<T>& value)
|
||||
{
|
||||
result = (value += right);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename T2> inline static typename std::enable_if<std::is_arithmetic<T>::value, T>::type operator -=(_atomic_base<be_t<T>>& left, T2 right)
|
||||
{
|
||||
T result;
|
||||
|
||||
left.atomic_op([&result, right](be_t<T>& value)
|
||||
{
|
||||
result = (value -= right);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> using atomic_le_t = _atomic_base<T>;
|
||||
|
||||
template<typename T> using atomic_be_t = _atomic_base<typename to_be_t<T>::type>;
|
||||
|
||||
namespace ps3
|
||||
{
|
||||
template<typename T> struct atomic_t : public atomic_be_t<T>
|
||||
{
|
||||
};
|
||||
template<typename T> using atomic_t = atomic_be_t<T>;
|
||||
}
|
||||
|
||||
namespace psv
|
||||
{
|
||||
template<typename T> struct atomic_t : public atomic_le_t<T>
|
||||
{
|
||||
};
|
||||
template<typename T> using atomic_t = atomic_le_t<T>;
|
||||
}
|
||||
|
||||
using namespace ps3;
|
||||
|
@ -78,10 +78,10 @@ namespace vm
|
||||
}
|
||||
|
||||
template<typename AT2>
|
||||
operator const _ptr_base<T, lvl, AT2>() const
|
||||
operator _ptr_base<T, lvl, AT2>() const
|
||||
{
|
||||
const AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<const _ptr_base<T, lvl, AT2>&>(addr);
|
||||
AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<_ptr_base<T, lvl, AT2>&>(addr);
|
||||
}
|
||||
|
||||
AT addr() const
|
||||
@ -94,9 +94,9 @@ namespace vm
|
||||
m_addr = value;
|
||||
}
|
||||
|
||||
static const _ptr_base make(const AT& addr)
|
||||
static _ptr_base make(const AT& addr)
|
||||
{
|
||||
return reinterpret_cast<const _ptr_base&>(addr);
|
||||
return reinterpret_cast<_ptr_base&>(addr);
|
||||
}
|
||||
|
||||
_ptr_base& operator = (const _ptr_base& right) = default;
|
||||
@ -203,10 +203,10 @@ namespace vm
|
||||
}
|
||||
|
||||
template<typename AT2>
|
||||
operator const _ptr_base<T, 1, AT2>() const
|
||||
operator _ptr_base<T, 1, AT2>() const
|
||||
{
|
||||
const AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<const _ptr_base<T, 1, AT2>&>(addr);
|
||||
AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<_ptr_base<T, 1, AT2>&>(addr);
|
||||
}
|
||||
|
||||
T* get_ptr() const
|
||||
@ -269,17 +269,17 @@ namespace vm
|
||||
explicit operator bool() const { return m_addr != 0; }
|
||||
|
||||
template<typename AT2>
|
||||
operator const _ptr_base<void, 1, AT2>() const
|
||||
operator _ptr_base<void, 1, AT2>() const
|
||||
{
|
||||
const AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<const _ptr_base<void, 1, AT2>&>(addr);
|
||||
AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<_ptr_base<void, 1, AT2>&>(addr);
|
||||
}
|
||||
|
||||
template<typename AT2>
|
||||
operator const _ptr_base<const void, 1, AT2>() const
|
||||
operator _ptr_base<const void, 1, AT2>() const
|
||||
{
|
||||
const AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<const _ptr_base<const void, 1, AT2>&>(addr);
|
||||
AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<_ptr_base<const void, 1, AT2>&>(addr);
|
||||
}
|
||||
|
||||
static const _ptr_base make(const AT& addr)
|
||||
@ -332,10 +332,10 @@ namespace vm
|
||||
explicit operator bool() const { return m_addr != 0; }
|
||||
|
||||
template<typename AT2>
|
||||
operator const _ptr_base<const void, 1, AT2>() const
|
||||
operator _ptr_base<const void, 1, AT2>() const
|
||||
{
|
||||
const AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<const _ptr_base<const void, 1, AT2>&>(addr);
|
||||
AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<_ptr_base<const void, 1, AT2>&>(addr);
|
||||
}
|
||||
|
||||
static const _ptr_base make(const AT& addr)
|
||||
@ -381,10 +381,10 @@ namespace vm
|
||||
explicit operator bool() const { return m_addr != 0; }
|
||||
|
||||
template<typename AT2>
|
||||
operator const _ptr_base<type, 1, AT2>() const
|
||||
operator _ptr_base<type, 1, AT2>() const
|
||||
{
|
||||
const AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<const _ptr_base<type, 1, AT2>&>(addr);
|
||||
AT2 addr = convert_le_be<AT2>(m_addr);
|
||||
return reinterpret_cast<_ptr_base<type, 1, AT2>&>(addr);
|
||||
}
|
||||
|
||||
static const _ptr_base make(const AT& addr)
|
||||
@ -411,106 +411,30 @@ namespace vm
|
||||
};
|
||||
|
||||
//BE pointer to LE data
|
||||
template<typename T, int lvl = 1, typename AT = u32> struct bptrl : public _ptr_base<T, lvl, typename to_be_t<AT>::type>
|
||||
{
|
||||
static const bptrl make(AT addr)
|
||||
{
|
||||
auto res = _ptr_base<T, lvl, typename to_be_t<AT>::type>::make(convert_le_be<typename to_be_t<AT>::type>(addr));
|
||||
return static_cast<const bptrl&>(res);
|
||||
}
|
||||
|
||||
using _ptr_base<T, lvl, typename to_be_t<AT>::type>::operator=;
|
||||
};
|
||||
template<typename T, int lvl = 1, typename AT = u32> using bptrl = _ptr_base<T, lvl, typename to_be_t<AT>::type>;
|
||||
|
||||
//BE pointer to BE data
|
||||
template<typename T, int lvl = 1, typename AT = u32> struct bptrb : public _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>
|
||||
{
|
||||
static const bptrb make(AT addr)
|
||||
{
|
||||
auto res = _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>::make(convert_le_be<typename to_be_t<AT>::type>(addr));
|
||||
return static_cast<const bptrb&>(res);
|
||||
}
|
||||
|
||||
using _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>::operator=;
|
||||
};
|
||||
template<typename T, int lvl = 1, typename AT = u32> using bptrb = _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>;
|
||||
|
||||
//LE pointer to BE data
|
||||
template<typename T, int lvl = 1, typename AT = u32> struct lptrb : public _ptr_base<typename to_be_t<T>::type, lvl, AT>
|
||||
{
|
||||
static const lptrb make(AT addr)
|
||||
{
|
||||
auto res = _ptr_base<typename to_be_t<T>::type, lvl, AT>::make(addr);
|
||||
return static_cast<const lptrb&>(res);
|
||||
}
|
||||
|
||||
using _ptr_base<typename to_be_t<T>::type, lvl, AT>::operator=;
|
||||
};
|
||||
template<typename T, int lvl = 1, typename AT = u32> using lptrb = _ptr_base<typename to_be_t<T>::type, lvl, AT>;
|
||||
|
||||
//LE pointer to LE data
|
||||
template<typename T, int lvl = 1, typename AT = u32> struct lptrl : public _ptr_base<T, lvl, AT>
|
||||
{
|
||||
static const lptrl make(AT addr)
|
||||
{
|
||||
auto res = _ptr_base<T, lvl, AT>::make(addr);
|
||||
return static_cast<const lptrl&>(res);
|
||||
}
|
||||
|
||||
using _ptr_base<T, lvl, AT>::operator=;
|
||||
};
|
||||
template<typename T, int lvl = 1, typename AT = u32> using lptrl = _ptr_base<T, lvl, AT>;
|
||||
|
||||
namespace ps3
|
||||
{
|
||||
template<typename T, int lvl = 1, typename AT = u32> struct ptr;
|
||||
template<typename T, int lvl = 1, typename AT = u32> struct bptr;
|
||||
|
||||
//default pointer for HLE functions (LE pointer to BE data)
|
||||
template<typename T, int lvl, typename AT> struct ptr : public lptrb<T, lvl, AT>
|
||||
{
|
||||
static const ptr make(AT addr)
|
||||
{
|
||||
auto res = lptrb<T, lvl, AT>::make(addr);
|
||||
return static_cast<const ptr&>(res);
|
||||
}
|
||||
|
||||
vm::ps3::bptr<T, lvl, AT> to_be() const
|
||||
{
|
||||
return vm::ps3::bptr<T, lvl, AT>::make(this->addr());
|
||||
}
|
||||
|
||||
using lptrb<T, lvl, AT>::operator=;
|
||||
};
|
||||
template<typename T, int lvl = 1, typename AT = u32> using ptr = lptrb<T, lvl, AT>;
|
||||
|
||||
//default pointer for HLE structures (BE pointer to BE data)
|
||||
template<typename T, int lvl, typename AT> struct bptr : public bptrb<T, lvl, AT>
|
||||
{
|
||||
static const bptr make(AT addr)
|
||||
{
|
||||
auto res = bptrb<T, lvl, AT>::make(addr);
|
||||
return static_cast<const bptr&>(res);
|
||||
}
|
||||
|
||||
vm::ps3::ptr<T, lvl, AT> to_le() const
|
||||
{
|
||||
return vm::ps3::ptr<T, lvl, AT>::make(this->addr());
|
||||
}
|
||||
|
||||
using bptrb<T, lvl, AT>::operator=;
|
||||
};
|
||||
template<typename T, int lvl = 1, typename AT = u32> using bptr = bptrb<T, lvl, AT>;
|
||||
}
|
||||
|
||||
namespace psv
|
||||
{
|
||||
//default pointer for HLE functions & structures (LE pointer to LE data)
|
||||
template<typename T, int lvl = 1, typename AT = u32> struct ptr : public lptrl<T, lvl, AT>
|
||||
{
|
||||
static const ptr make(AT addr)
|
||||
{
|
||||
auto res = lptrl<T, lvl, AT>::make(addr);
|
||||
return static_cast<const ptr&>(res);
|
||||
}
|
||||
|
||||
using lptrl<T, lvl, AT>::operator=;
|
||||
};
|
||||
template<typename T, int lvl = 1, typename AT = u32> using ptr = lptrl<T, lvl, AT>;
|
||||
}
|
||||
|
||||
//PS3 emulation is main now, so lets it be as default
|
||||
@ -519,36 +443,14 @@ namespace vm
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
// external specializations for fmt::format function
|
||||
// external specialization for fmt::format function
|
||||
|
||||
template<typename T, int lvl, typename AT>
|
||||
struct unveil<vm::ps3::ptr<T, lvl, AT>, false>
|
||||
struct unveil<vm::_ptr_base<T, lvl, AT>, false>
|
||||
{
|
||||
typedef typename unveil<AT>::result_type result_type;
|
||||
|
||||
__forceinline static result_type get_value(const vm::ps3::ptr<T, lvl, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, int lvl, typename AT>
|
||||
struct unveil<vm::ps3::bptr<T, lvl, AT>, false>
|
||||
{
|
||||
typedef typename unveil<AT>::result_type result_type;
|
||||
|
||||
__forceinline static result_type get_value(const vm::ps3::bptr<T, lvl, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, int lvl, typename AT>
|
||||
struct unveil<vm::psv::ptr<T, lvl, AT>, false>
|
||||
{
|
||||
typedef typename unveil<AT>::result_type result_type;
|
||||
|
||||
__forceinline static result_type get_value(const vm::psv::ptr<T, lvl, AT>& arg)
|
||||
__forceinline static result_type get_value(const vm::_ptr_base<T, lvl, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
@ -561,16 +463,16 @@ template<typename T, bool is_enum>
|
||||
struct cast_ppu_gpr;
|
||||
|
||||
template<typename T, int lvl, typename AT>
|
||||
struct cast_ppu_gpr<vm::ps3::ptr<T, lvl, AT>, false>
|
||||
struct cast_ppu_gpr<vm::_ptr_base<T, lvl, AT>, false>
|
||||
{
|
||||
__forceinline static u64 to_gpr(const vm::ps3::ptr<T, lvl, AT>& value)
|
||||
__forceinline static u64 to_gpr(const vm::_ptr_base<T, lvl, AT>& value)
|
||||
{
|
||||
return value.addr();
|
||||
return cast_ppu_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
__forceinline static vm::ps3::ptr<T, lvl, AT> from_gpr(const u64 reg)
|
||||
__forceinline static vm::_ptr_base<T, lvl, AT> from_gpr(const u64 reg)
|
||||
{
|
||||
return vm::ps3::ptr<T, lvl, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return vm::_ptr_base<T, lvl, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
}
|
||||
};
|
||||
|
||||
@ -580,15 +482,15 @@ template<typename T, bool is_enum>
|
||||
struct cast_armv7_gpr;
|
||||
|
||||
template<typename T, int lvl, typename AT>
|
||||
struct cast_armv7_gpr<vm::psv::ptr<T, lvl, AT>, false>
|
||||
struct cast_armv7_gpr<vm::_ptr_base<T, lvl, AT>, false>
|
||||
{
|
||||
__forceinline static u32 to_gpr(const vm::psv::ptr<T, lvl, AT>& value)
|
||||
__forceinline static u32 to_gpr(const vm::_ptr_base<T, lvl, AT>& value)
|
||||
{
|
||||
return value.addr();
|
||||
return cast_armv7_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
__forceinline static vm::psv::ptr<T, lvl, AT> from_gpr(const u32 reg)
|
||||
__forceinline static vm::_ptr_base<T, lvl, AT> from_gpr(const u32 reg)
|
||||
{
|
||||
return vm::psv::ptr<T, lvl, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return vm::_ptr_base<T, lvl, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
}
|
||||
};
|
||||
|
@ -61,51 +61,30 @@ namespace vm
|
||||
};
|
||||
|
||||
//BE reference to LE data
|
||||
template<typename T, typename AT = u32> struct brefl : public _ref_base<T, typename to_be_t<AT>::type>
|
||||
{
|
||||
using _ref_base<T, typename to_be_t<AT>::type>::operator=;
|
||||
};
|
||||
template<typename T, typename AT = u32> using brefl = _ref_base<T, typename to_be_t<AT>::type>;
|
||||
|
||||
//BE reference to BE data
|
||||
template<typename T, typename AT = u32> struct brefb : public _ref_base<typename to_be_t<T>::type, typename to_be_t<AT>::type>
|
||||
{
|
||||
using _ref_base<typename to_be_t<T>::type, typename to_be_t<AT>::type>::operator=;
|
||||
};
|
||||
template<typename T, typename AT = u32> using brefb = _ref_base<typename to_be_t<T>::type, typename to_be_t<AT>::type>;
|
||||
|
||||
//LE reference to BE data
|
||||
template<typename T, typename AT = u32> struct lrefb : public _ref_base<typename to_be_t<T>::type, AT>
|
||||
{
|
||||
using _ref_base<typename to_be_t<T>::type, AT>::operator=;
|
||||
};
|
||||
template<typename T, typename AT = u32> using lrefb = _ref_base<typename to_be_t<T>::type, AT>;
|
||||
|
||||
//LE reference to LE data
|
||||
template<typename T, typename AT = u32> struct lrefl : public _ref_base<T, AT>
|
||||
{
|
||||
using _ref_base<T, AT>::operator=;
|
||||
};
|
||||
template<typename T, typename AT = u32> using lrefl = _ref_base<T, AT>;
|
||||
|
||||
namespace ps3
|
||||
{
|
||||
//default reference for HLE functions (LE reference to BE data)
|
||||
template<typename T, typename AT = u32> struct ref : public lrefb<T, AT>
|
||||
{
|
||||
using lrefb<T, AT>::operator=;
|
||||
};
|
||||
template<typename T, typename AT = u32> using ref = lrefb<T, AT>;
|
||||
|
||||
//default reference for HLE structures (BE reference to BE data)
|
||||
template<typename T, typename AT = u32> struct bref : public brefb<T, AT>
|
||||
{
|
||||
using brefb<T, AT>::operator=;
|
||||
};
|
||||
template<typename T, typename AT = u32> using bref = brefb<T, AT>;
|
||||
}
|
||||
|
||||
namespace psv
|
||||
{
|
||||
//default reference for HLE functions & structures (LE reference to LE data)
|
||||
template<typename T, typename AT = u32> struct ref : public lrefl<T, AT>
|
||||
{
|
||||
using lrefl<T, AT>::operator=;
|
||||
};
|
||||
template<typename T, typename AT = u32> using ref = lrefl<T, AT>;
|
||||
}
|
||||
|
||||
//PS3 emulation is main now, so lets it be as default
|
||||
@ -114,36 +93,14 @@ namespace vm
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
// external specializations for fmt::format function
|
||||
// external specialization for fmt::format function
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct unveil<vm::ps3::ref<T, AT>, false>
|
||||
struct unveil<vm::_ref_base<T, AT>, false>
|
||||
{
|
||||
typedef typename unveil<AT>::result_type result_type;
|
||||
|
||||
__forceinline static result_type get_value(const vm::ps3::ref<T, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct unveil<vm::ps3::bref<T, AT>, false>
|
||||
{
|
||||
typedef typename unveil<AT>::result_type result_type;
|
||||
|
||||
__forceinline static result_type get_value(const vm::ps3::bref<T, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct unveil<vm::psv::ref<T, AT>, false>
|
||||
{
|
||||
typedef typename unveil<AT>::result_type result_type;
|
||||
|
||||
__forceinline static result_type get_value(const vm::psv::ref<T, AT>& arg)
|
||||
__forceinline static result_type get_value(const vm::_ref_base<T, AT>& arg)
|
||||
{
|
||||
return unveil<AT>::get_value(arg.addr());
|
||||
}
|
||||
@ -156,16 +113,16 @@ template<typename T, bool is_enum>
|
||||
struct cast_ppu_gpr;
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct cast_ppu_gpr<vm::ps3::ref<T, AT>, false>
|
||||
struct cast_ppu_gpr<vm::_ref_base<T, AT>, false>
|
||||
{
|
||||
__forceinline static u64 to_gpr(const vm::ps3::ref<T, AT>& value)
|
||||
__forceinline static u64 to_gpr(const vm::_ref_base<T, AT>& value)
|
||||
{
|
||||
return value.addr();
|
||||
return cast_ppu_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
__forceinline static vm::ps3::ref<T, AT> from_gpr(const u64 reg)
|
||||
__forceinline static vm::_ref_base<T, AT> from_gpr(const u64 reg)
|
||||
{
|
||||
return vm::ps3::ref<T, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return vm::_ref_base<T, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
}
|
||||
};
|
||||
|
||||
@ -175,15 +132,15 @@ template<typename T, bool is_enum>
|
||||
struct cast_armv7_gpr;
|
||||
|
||||
template<typename T, typename AT>
|
||||
struct cast_armv7_gpr<vm::psv::ref<T, AT>, false>
|
||||
struct cast_armv7_gpr<vm::_ref_base<T, AT>, false>
|
||||
{
|
||||
__forceinline static u32 to_gpr(const vm::psv::ref<T, AT>& value)
|
||||
__forceinline static u32 to_gpr(const vm::_ref_base<T, AT>& value)
|
||||
{
|
||||
return value.addr();
|
||||
return cast_armv7_gpr<AT, std::is_enum<AT>::value>::to_gpr(value.addr());
|
||||
}
|
||||
|
||||
__forceinline static vm::psv::ref<T, AT> from_gpr(const u32 reg)
|
||||
__forceinline static vm::_ref_base<T, AT> from_gpr(const u32 reg)
|
||||
{
|
||||
return vm::psv::ref<T, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
return vm::_ref_base<T, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
|
||||
}
|
||||
};
|
||||
|
@ -530,7 +530,7 @@ int cellAdecOpen(vm::ptr<CellAdecType> type, vm::ptr<CellAdecResource> res, vm::
|
||||
|
||||
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
|
||||
|
||||
*handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc.to_le(), cb->cbArg));
|
||||
*handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -542,7 +542,7 @@ int cellAdecOpenEx(vm::ptr<CellAdecType> type, vm::ptr<CellAdecResourceEx> res,
|
||||
|
||||
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
|
||||
|
||||
*handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc.to_le(), cb->cbArg));
|
||||
*handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -571,7 +571,7 @@ int cellAdecClose(u32 handle)
|
||||
}
|
||||
|
||||
if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId());
|
||||
Emu.GetIdManager().RemoveID(handle);
|
||||
Emu.GetIdManager().RemoveID<AudioDecoder>(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -710,7 +710,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr)
|
||||
}
|
||||
}
|
||||
es.dmux = nullptr;
|
||||
Emu.GetIdManager().RemoveID(task.es.es);
|
||||
Emu.GetIdManager().RemoveID<ElementaryStream>(task.es.es);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -814,7 +814,7 @@ int cellDmuxOpen(vm::ptr<const CellDmuxType> demuxerType, vm::ptr<const CellDmux
|
||||
|
||||
// TODO: check demuxerResource and demuxerCb arguments
|
||||
|
||||
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg));
|
||||
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -832,7 +832,7 @@ int cellDmuxOpenEx(vm::ptr<const CellDmuxType> demuxerType, vm::ptr<const CellDm
|
||||
|
||||
// TODO: check demuxerResourceEx and demuxerCb arguments
|
||||
|
||||
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg));
|
||||
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -850,7 +850,7 @@ int cellDmuxOpen2(vm::ptr<const CellDmuxType2> demuxerType2, vm::ptr<const CellD
|
||||
|
||||
// TODO: check demuxerType2, demuxerResource2 and demuxerCb arguments
|
||||
|
||||
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg));
|
||||
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -880,7 +880,7 @@ int cellDmuxClose(u32 demuxerHandle)
|
||||
}
|
||||
|
||||
if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId());
|
||||
Emu.GetIdManager().RemoveID(demuxerHandle);
|
||||
Emu.GetIdManager().RemoveID<Demuxer>(demuxerHandle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -1008,7 +1008,7 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
|
||||
|
||||
std::shared_ptr<ElementaryStream> es(new ElementaryStream(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize,
|
||||
esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2,
|
||||
esCb->cbEsMsgFunc.to_le(), esCb->cbArg, esSpecificInfo_addr));
|
||||
esCb->cbEsMsgFunc, esCb->cbArg, esSpecificInfo_addr));
|
||||
|
||||
u32 id = Emu.GetIdManager().GetNewID(es);
|
||||
es->id = id;
|
||||
|
@ -41,7 +41,7 @@ int cellGifDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellGifDecSrc
|
||||
case se32(CELL_GIFDEC_FILE):
|
||||
// Get file descriptor
|
||||
vm::var<be_t<u32>> fd;
|
||||
int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr<const void>::make(0), 0);
|
||||
int ret = cellFsOpen(src->fileName, 0, fd, vm::ptr<const void>::make(0), 0);
|
||||
current_subHandle->fd = fd.value();
|
||||
if (ret != CELL_OK) return CELL_GIFDEC_ERROR_OPEN_FILE;
|
||||
|
||||
@ -266,7 +266,7 @@ int cellGifDecClose(u32 mainHandle, u32 subHandle)
|
||||
return CELL_GIFDEC_ERROR_FATAL;
|
||||
|
||||
cellFsClose(subHandle_data->fd);
|
||||
Emu.GetIdManager().RemoveID(subHandle);
|
||||
Emu.GetIdManager().RemoveID<CellGifDecSubHandle>(subHandle);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ int cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJpgDecSrc
|
||||
case se32(CELL_JPGDEC_FILE):
|
||||
// Get file descriptor
|
||||
vm::var<be_t<u32>> fd;
|
||||
int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr<const void>::make(0), 0);
|
||||
int ret = cellFsOpen(src->fileName, 0, fd, vm::ptr<const void>::make(0), 0);
|
||||
current_subHandle->fd = fd.value();
|
||||
if (ret != CELL_OK) return CELL_JPGDEC_ERROR_OPEN_FILE;
|
||||
|
||||
@ -75,7 +75,7 @@ int cellJpgDecClose(u32 mainHandle, u32 subHandle)
|
||||
return CELL_JPGDEC_ERROR_FATAL;
|
||||
|
||||
cellFsClose(subHandle_data->fd);
|
||||
Emu.GetIdManager().RemoveID(subHandle);
|
||||
Emu.GetIdManager().RemoveID<CellJpgDecSubHandle>(subHandle);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ s32 pngDecOpen(
|
||||
case se32(CELL_PNGDEC_FILE):
|
||||
// Get file descriptor
|
||||
vm::var<be_t<u32>> fd;
|
||||
int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr<const void>::make(0), 0);
|
||||
int ret = cellFsOpen(src->fileName, 0, fd, vm::ptr<const void>::make(0), 0);
|
||||
stream->fd = fd.value();
|
||||
if (ret != CELL_OK) return CELL_PNGDEC_ERROR_OPEN_FILE;
|
||||
|
||||
|
@ -382,9 +382,9 @@ s32 cellSaveDataListSave2(
|
||||
return CELL_SAVEDATA_ERROR_CBRESULT;
|
||||
}
|
||||
|
||||
setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum);
|
||||
setSaveDataList(saveEntries, listSet->fixedList, listSet->fixedListNum);
|
||||
if (listSet->newData)
|
||||
addNewSaveDataEntry(saveEntries, listSet->newData.to_le());
|
||||
addNewSaveDataEntry(saveEntries, listSet->newData);
|
||||
if (saveEntries.size() == 0) {
|
||||
cellSysutil.Error("cellSaveDataListSave2: No save entries found!"); // TODO: Find a better way to handle this error
|
||||
return CELL_OK;
|
||||
@ -474,9 +474,9 @@ s32 cellSaveDataListLoad2(
|
||||
return CELL_SAVEDATA_ERROR_CBRESULT;
|
||||
}
|
||||
|
||||
setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum);
|
||||
setSaveDataList(saveEntries, listSet->fixedList, listSet->fixedListNum);
|
||||
if (listSet->newData)
|
||||
addNewSaveDataEntry(saveEntries, listSet->newData.to_le());
|
||||
addNewSaveDataEntry(saveEntries, listSet->newData);
|
||||
if (saveEntries.size() == 0) {
|
||||
cellSysutil.Error("cellSaveDataListLoad2: No save entries found!"); // TODO: Find a better way to handle this error
|
||||
return CELL_OK;
|
||||
|
@ -167,14 +167,8 @@ s32 spursInit(
|
||||
}
|
||||
}
|
||||
|
||||
if (s32 res = lwmutex_create(spurs->m.mutex, SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, *(u64*)"_spuPrv"))
|
||||
{
|
||||
assert(!"lwmutex_create() failed");
|
||||
}
|
||||
if (s32 res = lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv"))
|
||||
{
|
||||
assert(!"lwcond_create() failed");
|
||||
}
|
||||
lwmutex_create(spurs->m.mutex, false, SYS_SYNC_PRIORITY, *(u64*)"_spuPrv");
|
||||
lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv");
|
||||
|
||||
spurs->m.flags1 = (flags & SAF_EXIT_IF_NO_WORK ? SF1_EXIT_IF_NO_WORK : 0) | (isSecond ? SF1_32_WORKLOADS : 0);
|
||||
spurs->m.wklFlagReceiver.write_relaxed(0xff);
|
||||
@ -850,7 +844,7 @@ s32 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
assert(!"sys_lwmutex_lock() failed");
|
||||
}
|
||||
if (s32 res = sys_lwcond_signal(spurs->get_lwcond()))
|
||||
if (s32 res = sys_lwcond_signal(CPU, spurs->get_lwcond()))
|
||||
{
|
||||
assert(!"sys_lwcond_signal() failed");
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ s32 syncMutexInitialize(vm::ptr<CellSyncMutex> mutex)
|
||||
{
|
||||
return CELL_SYNC_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (mutex.addr() % 4)
|
||||
{
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
// prx: set zero and sync
|
||||
mutex->data.exchange({});
|
||||
mutex->sync_var.exchange({});
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -51,26 +51,22 @@ s32 cellSyncMutexLock(vm::ptr<CellSyncMutex> mutex)
|
||||
{
|
||||
return CELL_SYNC_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (mutex.addr() % 4)
|
||||
{
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
// prx: increase m_acq and remember its old value
|
||||
be_t<u16> order;
|
||||
mutex->data.atomic_op([&order](CellSyncMutex::data_t& mutex)
|
||||
{
|
||||
order = mutex.m_acq++;
|
||||
});
|
||||
// prx: increase acquire_count and remember its old value
|
||||
const be_t<u16> order = be_t<u16>::make(mutex->acquire_count++);
|
||||
|
||||
// prx: wait until this old value is equal to m_rel
|
||||
// prx: wait until release_count is equal to old acquire_count
|
||||
g_sync_mutex_wm.wait_op(mutex.addr(), [mutex, order]()
|
||||
{
|
||||
return order == mutex->data.read_relaxed().m_rel;
|
||||
return order == mutex->release_count.read_relaxed();
|
||||
});
|
||||
|
||||
// prx: sync
|
||||
mutex->data.read_sync();
|
||||
mutex->sync_var.read_sync();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -83,19 +79,16 @@ s32 cellSyncMutexTryLock(vm::ptr<CellSyncMutex> mutex)
|
||||
{
|
||||
return CELL_SYNC_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (mutex.addr() % 4)
|
||||
{
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
// prx: exit if m_acq and m_rel are not equal, increase m_acq
|
||||
return mutex->data.atomic_op(CELL_OK, [](CellSyncMutex::data_t& mutex) -> s32
|
||||
// prx: lock only if acquire_count and release_count are equal
|
||||
return mutex->sync_var.atomic_op(CELL_OK, [](CellSyncMutex::sync_t& mutex) -> s32
|
||||
{
|
||||
if (mutex.m_acq++ != mutex.m_rel)
|
||||
{
|
||||
return CELL_SYNC_ERROR_BUSY;
|
||||
}
|
||||
return CELL_OK;
|
||||
return (mutex.acquire_count++ != mutex.release_count) ? CELL_SYNC_ERROR_BUSY : CELL_OK;
|
||||
});
|
||||
}
|
||||
|
||||
@ -112,10 +105,8 @@ s32 cellSyncMutexUnlock(vm::ptr<CellSyncMutex> mutex)
|
||||
return CELL_SYNC_ERROR_ALIGN;
|
||||
}
|
||||
|
||||
mutex->data.atomic_op_sync([](CellSyncMutex::data_t& mutex)
|
||||
{
|
||||
mutex.m_rel++;
|
||||
});
|
||||
// prx: increase release count
|
||||
mutex->release_count++;
|
||||
|
||||
g_sync_mutex_wm.notify(mutex.addr());
|
||||
|
||||
|
@ -29,15 +29,21 @@ enum
|
||||
CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114, // ???
|
||||
};
|
||||
|
||||
struct CellSyncMutex
|
||||
union CellSyncMutex
|
||||
{
|
||||
struct data_t
|
||||
struct sync_t
|
||||
{
|
||||
be_t<u16> m_rel; // release order (increased when mutex is unlocked)
|
||||
be_t<u16> m_acq; // acquire order (increased when mutex is locked)
|
||||
be_t<u16> release_count; // increased when mutex is unlocked
|
||||
be_t<u16> acquire_count; // increased when mutex is locked
|
||||
};
|
||||
|
||||
atomic_t<data_t> data;
|
||||
struct
|
||||
{
|
||||
atomic_t<u16> release_count;
|
||||
atomic_t<u16> acquire_count;
|
||||
};
|
||||
|
||||
atomic_t<sync_t> sync_var;
|
||||
};
|
||||
|
||||
static_assert(sizeof(CellSyncMutex) == 4, "CellSyncMutex: wrong size");
|
||||
|
@ -576,7 +576,7 @@ int cellVdecOpen(vm::ptr<const CellVdecType> type, vm::ptr<const CellVdecResourc
|
||||
cellVdec.Warning("cellVdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||
type.addr(), res.addr(), cb.addr(), handle.addr());
|
||||
|
||||
*handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc.to_le(), cb->cbArg));
|
||||
*handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -586,7 +586,7 @@ int cellVdecOpenEx(vm::ptr<const CellVdecTypeEx> type, vm::ptr<const CellVdecRes
|
||||
cellVdec.Warning("cellVdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
|
||||
type.addr(), res.addr(), cb.addr(), handle.addr());
|
||||
|
||||
*handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc.to_le(), cb->cbArg));
|
||||
*handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -615,7 +615,7 @@ int cellVdecClose(u32 handle)
|
||||
}
|
||||
|
||||
if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId());
|
||||
Emu.GetIdManager().RemoveID(handle);
|
||||
Emu.GetIdManager().RemoveID<VideoDecoder>(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ int cellVpostClose(u32 handle)
|
||||
return CELL_VPOST_ERROR_C_ARG_HDL_INVALID;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(handle);
|
||||
Emu.GetIdManager().RemoveID<VpostInstance>(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "Emu/SysCalls/lv2/sys_interrupt.h"
|
||||
#include "Emu/SysCalls/lv2/sys_spu.h"
|
||||
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
|
||||
#include "Emu/SysCalls/lv2/sys_spinlock.h"
|
||||
#include "Emu/SysCalls/lv2/sys_prx.h"
|
||||
#include "Emu/SysCalls/lv2/sys_ppu_thread.h"
|
||||
#include "Emu/SysCalls/lv2/sys_process.h"
|
||||
@ -33,6 +32,8 @@ u32 g_tls_size;
|
||||
|
||||
std::array<std::atomic<u32>, TLS_MAX> g_tls_owners;
|
||||
|
||||
waiter_map_t g_sys_spinlock_wm("sys_spinlock_wm"); // TODO
|
||||
|
||||
void sys_initialize_tls()
|
||||
{
|
||||
sysPrxForUser.Log("sys_initialize_tls()");
|
||||
@ -89,6 +90,549 @@ void ppu_free_tls(u32 thread)
|
||||
}
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
|
||||
{
|
||||
sysPrxForUser.Warning("sys_lwmutex_create(lwmutex=*0x%x, attr=*0x%x)", lwmutex, attr);
|
||||
|
||||
const bool recursive = attr->recursive.data() == se32(SYS_SYNC_RECURSIVE);
|
||||
|
||||
if (!recursive && attr->recursive.data() != se32(SYS_SYNC_NOT_RECURSIVE))
|
||||
{
|
||||
sysPrxForUser.Error("sys_lwmutex_create(): invalid recursive attribute (0x%x)", attr->recursive);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const u32 protocol = attr->protocol;
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case SYS_SYNC_FIFO: break;
|
||||
case SYS_SYNC_RETRY: break;
|
||||
case SYS_SYNC_PRIORITY: break;
|
||||
default: sysPrxForUser.Error("sys_lwmutex_create(): invalid protocol (0x%x)", protocol); return CELL_EINVAL;
|
||||
}
|
||||
|
||||
std::shared_ptr<lwmutex_t> lw(new lwmutex_t(protocol, attr->name_u64));
|
||||
|
||||
lwmutex->lock_var.write_relaxed({ lwmutex::free, lwmutex::zero });
|
||||
lwmutex->attribute = attr->recursive | attr->protocol;
|
||||
lwmutex->recursive_count = 0;
|
||||
lwmutex->sleep_queue = Emu.GetIdManager().GetNewID(lw);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
// check to prevent recursive locking in the next call
|
||||
if (lwmutex->lock_var.read_relaxed().owner == CPU.GetId())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
// attempt to lock the mutex
|
||||
if (s32 res = sys_lwmutex_trylock(CPU, lwmutex))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
if (s32 res = _sys_lwmutex_destroy(lwmutex->sleep_queue))
|
||||
{
|
||||
// unlock the mutex if failed
|
||||
sys_lwmutex_unlock(CPU, lwmutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// deleting succeeded
|
||||
lwmutex->owner.exchange(lwmutex::dead);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout);
|
||||
|
||||
const be_t<u32> tid = be_t<u32>::make(CPU.GetId());
|
||||
|
||||
// try to lock lightweight mutex
|
||||
const be_t<u32> old_owner = lwmutex->owner.compare_and_swap(lwmutex::free, tid);
|
||||
|
||||
if (old_owner.data() == se32(lwmutex_free))
|
||||
{
|
||||
// locking succeeded
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (old_owner.data() == tid.data())
|
||||
{
|
||||
// recursive locking
|
||||
|
||||
if ((lwmutex->attribute.data() & se32(SYS_SYNC_RECURSIVE)) == 0)
|
||||
{
|
||||
// if not recursive
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
|
||||
if (lwmutex->recursive_count.data() == -1)
|
||||
{
|
||||
// if recursion limit reached
|
||||
return CELL_EKRESOURCE;
|
||||
}
|
||||
|
||||
// recursive locking succeeded
|
||||
lwmutex->recursive_count++;
|
||||
lwmutex->lock_var.read_sync();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (old_owner.data() == se32(lwmutex_dead))
|
||||
{
|
||||
// invalid or deleted mutex
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 300; i++)
|
||||
{
|
||||
if (lwmutex->owner.read_relaxed().data() == se32(lwmutex_free))
|
||||
{
|
||||
if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid))
|
||||
{
|
||||
// locking succeeded
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// atomically increment waiter value using 64 bit op
|
||||
lwmutex->all_info++;
|
||||
|
||||
if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid))
|
||||
{
|
||||
// locking succeeded
|
||||
lwmutex->all_info--;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// lock using the syscall
|
||||
const s32 res = _sys_lwmutex_lock(lwmutex->sleep_queue, timeout);
|
||||
|
||||
lwmutex->all_info--;
|
||||
|
||||
if (res == CELL_OK)
|
||||
{
|
||||
// locking succeeded
|
||||
auto old = lwmutex->owner.exchange(tid);
|
||||
|
||||
if (old.data() != se32(lwmutex_reserved))
|
||||
{
|
||||
sysPrxForUser.Fatal("sys_lwmutex_lock(lwmutex=*0x%x): locking failed (owner=0x%x)", lwmutex, old);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (res == CELL_EBUSY && lwmutex->attribute.data() & se32(SYS_SYNC_RETRY))
|
||||
{
|
||||
// TODO (protocol is ignored in current implementation)
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
const be_t<u32> tid = be_t<u32>::make(CPU.GetId());
|
||||
|
||||
// try to lock lightweight mutex
|
||||
const be_t<u32> old_owner = lwmutex->owner.compare_and_swap(lwmutex::free, tid);
|
||||
|
||||
if (old_owner.data() == se32(lwmutex_free))
|
||||
{
|
||||
// locking succeeded
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (old_owner.data() == tid.data())
|
||||
{
|
||||
// recursive locking
|
||||
|
||||
if ((lwmutex->attribute.data() & se32(SYS_SYNC_RECURSIVE)) == 0)
|
||||
{
|
||||
// if not recursive
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
|
||||
if (lwmutex->recursive_count.data() == -1)
|
||||
{
|
||||
// if recursion limit reached
|
||||
return CELL_EKRESOURCE;
|
||||
}
|
||||
|
||||
// recursive locking succeeded
|
||||
lwmutex->recursive_count++;
|
||||
lwmutex->lock_var.read_sync();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (old_owner.data() == se32(lwmutex_dead))
|
||||
{
|
||||
// invalid or deleted mutex
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (old_owner.data() == se32(lwmutex_reserved))
|
||||
{
|
||||
// should be locked by the syscall
|
||||
const s32 res = _sys_lwmutex_trylock(lwmutex->sleep_queue);
|
||||
|
||||
if (res == CELL_OK)
|
||||
{
|
||||
// locking succeeded
|
||||
auto old = lwmutex->owner.exchange(tid);
|
||||
|
||||
if (old.data() != se32(lwmutex_reserved))
|
||||
{
|
||||
sysPrxForUser.Fatal("sys_lwmutex_trylock(lwmutex=*0x%x): locking failed (owner=0x%x)", lwmutex, old);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// locked by another thread
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
const be_t<u32> tid = be_t<u32>::make(CPU.GetId());
|
||||
|
||||
// check owner
|
||||
if (lwmutex->owner.read_relaxed() != tid)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
if (lwmutex->recursive_count.data())
|
||||
{
|
||||
// recursive unlocking succeeded
|
||||
lwmutex->recursive_count--;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// ensure that waiter is zero
|
||||
if (lwmutex->lock_var.compare_and_swap_test({ tid, lwmutex::zero }, { lwmutex::free, lwmutex::zero }))
|
||||
{
|
||||
// unlocking succeeded
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (lwmutex->attribute.data() & se32(SYS_SYNC_RETRY))
|
||||
{
|
||||
// TODO (protocol is ignored in current implementation)
|
||||
}
|
||||
|
||||
// set special value
|
||||
lwmutex->owner.exchange(lwmutex::reserved);
|
||||
|
||||
// call the syscall
|
||||
if (_sys_lwmutex_unlock(lwmutex->sleep_queue) == CELL_ESRCH)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr)
|
||||
{
|
||||
sysPrxForUser.Warning("sys_lwcond_create(lwcond=*0x%x, lwmutex=*0x%x, attr=*0x%x)", lwcond, lwmutex, attr);
|
||||
|
||||
std::shared_ptr<lwcond_t> cond(new lwcond_t(attr->name_u64));
|
||||
|
||||
lwcond->lwcond_queue = Emu.GetIdManager().GetNewID(cond, TYPE_LWCOND);
|
||||
lwcond->lwmutex = lwmutex;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwcond_destroy(lwcond=*0x%x)", lwcond);
|
||||
|
||||
const s32 res = _sys_lwcond_destroy(lwcond->lwcond_queue);
|
||||
|
||||
if (res == CELL_OK)
|
||||
{
|
||||
lwcond->lwcond_queue = lwmutex_dead;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwcond_signal(lwcond=*0x%x)", lwcond);
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
|
||||
if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY))
|
||||
{
|
||||
// TODO (protocol ignored)
|
||||
//return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2);
|
||||
}
|
||||
|
||||
if (lwmutex->owner.read_relaxed() == CPU.GetId())
|
||||
{
|
||||
// if owns the mutex
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 1))
|
||||
{
|
||||
lwmutex->all_info--;
|
||||
|
||||
return res == CELL_EPERM ? CELL_OK : res;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (s32 res = sys_lwmutex_trylock(CPU, lwmutex))
|
||||
{
|
||||
// if locking failed
|
||||
|
||||
if (res != CELL_EBUSY)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2);
|
||||
}
|
||||
|
||||
// if locking succeeded
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 3))
|
||||
{
|
||||
lwmutex->all_info--;
|
||||
|
||||
// unlock the lightweight mutex
|
||||
sys_lwmutex_unlock(CPU, lwmutex);
|
||||
|
||||
return res == CELL_ENOENT ? CELL_OK : res;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwcond_signal_all(lwcond=*0x%x)", lwcond);
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
|
||||
if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY))
|
||||
{
|
||||
// TODO (protocol ignored)
|
||||
//return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2);
|
||||
}
|
||||
|
||||
if (lwmutex->owner.read_relaxed() == CPU.GetId())
|
||||
{
|
||||
// if owns the mutex, call the syscall
|
||||
const s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1);
|
||||
|
||||
if (res <= 0)
|
||||
{
|
||||
// return error or CELL_OK
|
||||
return res;
|
||||
}
|
||||
|
||||
lwmutex->all_info += res;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (s32 res = sys_lwmutex_trylock(CPU, lwmutex))
|
||||
{
|
||||
// if locking failed
|
||||
|
||||
if (res != CELL_EBUSY)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2);
|
||||
}
|
||||
|
||||
// if locking succeeded, call the syscall
|
||||
s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
lwmutex->all_info += res;
|
||||
|
||||
res = CELL_OK;
|
||||
}
|
||||
|
||||
// unlock mutex
|
||||
sys_lwmutex_unlock(CPU, lwmutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwcond_signal_to(lwcond=*0x%x, ppu_thread_id=%d)", lwcond, ppu_thread_id);
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
|
||||
if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY))
|
||||
{
|
||||
// TODO (protocol ignored)
|
||||
//return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2);
|
||||
}
|
||||
|
||||
if (lwmutex->owner.read_relaxed() == CPU.GetId())
|
||||
{
|
||||
// if owns the mutex
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 1))
|
||||
{
|
||||
lwmutex->all_info--;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (s32 res = sys_lwmutex_trylock(CPU, lwmutex))
|
||||
{
|
||||
// if locking failed
|
||||
|
||||
if (res != CELL_EBUSY)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2);
|
||||
}
|
||||
|
||||
// if locking succeeded
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 3))
|
||||
{
|
||||
lwmutex->all_info--;
|
||||
|
||||
// unlock the lightweight mutex
|
||||
sys_lwmutex_unlock(CPU, lwmutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
|
||||
{
|
||||
sysPrxForUser.Log("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout);
|
||||
|
||||
const be_t<u32> tid = be_t<u32>::make(CPU.GetId());
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
|
||||
if (lwmutex->owner.read_relaxed() != tid)
|
||||
{
|
||||
// if not owner of the mutex
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
// save old recursive value
|
||||
const be_t<u32> recursive_value = lwmutex->recursive_count;
|
||||
|
||||
// set special value
|
||||
lwmutex->owner.write_relaxed(lwmutex::reserved);
|
||||
lwmutex->recursive_count = 0;
|
||||
|
||||
// call the syscall
|
||||
s32 res = _sys_lwcond_queue_wait(lwcond->lwcond_queue, lwmutex->sleep_queue, timeout);
|
||||
|
||||
if (res == CELL_OK || res == CELL_ESRCH)
|
||||
{
|
||||
if (res == CELL_OK)
|
||||
{
|
||||
lwmutex->all_info--;
|
||||
}
|
||||
|
||||
// restore owner and recursive value
|
||||
const auto old = lwmutex->owner.exchange(tid);
|
||||
lwmutex->recursive_count = recursive_value;
|
||||
|
||||
if (old.data() != se32(lwmutex_reserved))
|
||||
{
|
||||
sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): locking failed (lwmutex->owner=0x%x)", lwcond, old);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
if (res == CELL_EBUSY || res == CELL_ETIMEDOUT)
|
||||
{
|
||||
const s32 res2 = sys_lwmutex_lock(CPU, lwmutex, 0);
|
||||
|
||||
if (res2 == CELL_OK)
|
||||
{
|
||||
// if successfully locked, restore recursive value
|
||||
lwmutex->recursive_count = recursive_value;
|
||||
|
||||
return res == CELL_EBUSY ? CELL_OK : res;
|
||||
}
|
||||
|
||||
return res2;
|
||||
}
|
||||
|
||||
if (res == CELL_EDEADLK)
|
||||
{
|
||||
// restore owner and recursive value
|
||||
const auto old = lwmutex->owner.exchange(tid);
|
||||
lwmutex->recursive_count = recursive_value;
|
||||
|
||||
if (old.data() != se32(lwmutex_reserved))
|
||||
{
|
||||
sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): locking failed after timeout (lwmutex->owner=0x%x)", lwcond, old);
|
||||
}
|
||||
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
|
||||
sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): unexpected syscall result (0x%x)", lwcond, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string ps3_fmt(PPUThread& context, vm::ptr<const char> fmt, u32 g_count, u32 f_count, u32 v_count)
|
||||
{
|
||||
std::string result;
|
||||
@ -575,6 +1119,54 @@ s32 sys_process_get_paramsfo(vm::ptr<char> buffer)
|
||||
return _sys_process_get_paramsfo(buffer);
|
||||
}
|
||||
|
||||
void sys_spinlock_initialize(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_initialize(lock=*0x%x)", lock);
|
||||
|
||||
// prx: set 0 and sync
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
}
|
||||
|
||||
void sys_spinlock_lock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_lock(lock=*0x%x)", lock);
|
||||
|
||||
// prx: exchange with 0xabadcafe, repeat until exchanged with 0
|
||||
while (lock->exchange(be_t<u32>::make(0xabadcafe)).data())
|
||||
{
|
||||
g_sys_spinlock_wm.wait_op(lock.addr(), [lock](){ return lock->read_relaxed().data() == 0; });
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sysPrxForUser.Warning("sys_spinlock_lock(lock=*0x%x) aborted", lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 sys_spinlock_trylock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_trylock(lock=*0x%x)", lock);
|
||||
|
||||
// prx: exchange with 0xabadcafe, translate exchanged value
|
||||
if (lock->exchange(be_t<u32>::make(0xabadcafe)).data())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_spinlock_unlock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sysPrxForUser.Log("sys_spinlock_unlock(lock=*0x%x)", lock);
|
||||
|
||||
// prx: sync and set 0
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
|
||||
g_sys_spinlock_wm.notify(lock.addr());
|
||||
}
|
||||
|
||||
Module sysPrxForUser("sysPrxForUser", []()
|
||||
{
|
||||
g_tls_start = 0;
|
||||
@ -599,6 +1191,13 @@ Module sysPrxForUser("sysPrxForUser", []()
|
||||
REG_FUNC(sysPrxForUser, sys_lwmutex_trylock);
|
||||
REG_FUNC(sysPrxForUser, sys_lwmutex_unlock);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_create);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_destroy);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_signal);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_signal_all);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_signal_to);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_wait);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_time_get_system_time);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_process_exit);
|
||||
@ -645,13 +1244,6 @@ Module sysPrxForUser("sysPrxForUser", []()
|
||||
REG_FUNC(sysPrxForUser, sys_raw_spu_load);
|
||||
REG_FUNC(sysPrxForUser, sys_raw_spu_image_load);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_create);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_destroy);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_signal);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_signal_all);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_signal_to);
|
||||
REG_FUNC(sysPrxForUser, sys_lwcond_wait);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_get_random_number);
|
||||
|
||||
REG_FUNC(sysPrxForUser, sys_spinlock_initialize);
|
||||
|
@ -22,5 +22,24 @@ extern vm::ptr<spu_printf_cb_t> spu_printf_dgcb;
|
||||
extern vm::ptr<spu_printf_cb_t> spu_printf_atcb;
|
||||
extern vm::ptr<spu_printf_cb_t> spu_printf_dtcb;
|
||||
|
||||
// SysCalls
|
||||
// Functions
|
||||
vm::ptr<void> _sys_memset(vm::ptr<void> dst, s32 value, u32 size);
|
||||
|
||||
struct sys_lwmutex_t;
|
||||
struct sys_lwmutex_attribute_t;
|
||||
|
||||
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
|
||||
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
|
||||
struct sys_lwcond_t;
|
||||
struct sys_lwcond_attribute_t;
|
||||
|
||||
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr);
|
||||
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id);
|
||||
s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);
|
||||
|
@ -40,10 +40,10 @@ std::string SyncPrimManager::GetSyncPrimName(u32 id, IDType type)
|
||||
{
|
||||
case TYPE_LWCOND:
|
||||
{
|
||||
std::shared_ptr<Lwcond> lw;
|
||||
std::shared_ptr<lwcond_t> lw;
|
||||
if (Emu.GetIdManager().GetIDData(id, lw))
|
||||
{
|
||||
return std::string((const char*)&lw->queue.name, 8);
|
||||
return std::string((const char*)&lw->name, 8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "lv2/cellFs.h"
|
||||
#include "lv2/sleep_queue.h"
|
||||
#include "lv2/sys_lwmutex.h"
|
||||
#include "lv2/sys_lwcond.h"
|
||||
#include "lv2/sys_mutex.h"
|
||||
#include "lv2/sys_cond.h"
|
||||
#include "lv2/sys_event.h"
|
||||
@ -108,7 +109,7 @@ const ppu_func_caller sc_table[1024] =
|
||||
bind_func(sys_timer_create), //70 (0x046)
|
||||
bind_func(sys_timer_destroy), //71 (0x047)
|
||||
bind_func(sys_timer_get_information), //72 (0x048)
|
||||
bind_func(sys_timer_start), //73 (0x049)
|
||||
bind_func(_sys_timer_start), //73 (0x049)
|
||||
bind_func(sys_timer_stop), //74 (0x04A)
|
||||
bind_func(sys_timer_connect_event_queue), //75 (0x04B)
|
||||
bind_func(sys_timer_disconnect_event_queue), //76 (0x04C)
|
||||
@ -124,17 +125,17 @@ const ppu_func_caller sc_table[1024] =
|
||||
bind_func(sys_event_flag_trywait), //86 (0x056)
|
||||
bind_func(sys_event_flag_set), //87 (0x057)
|
||||
bind_func(sys_interrupt_thread_eoi), //88 (0x058)
|
||||
bind_func(_sys_interrupt_thread_disestablish), //89 (0x059)
|
||||
bind_func(_sys_interrupt_thread_disestablish), //89 (0x059)
|
||||
bind_func(sys_semaphore_create), //90 (0x05A)
|
||||
bind_func(sys_semaphore_destroy), //91 (0x05B)
|
||||
bind_func(sys_semaphore_wait), //92 (0x05C)
|
||||
bind_func(sys_semaphore_trywait), //93 (0x05D)
|
||||
bind_func(sys_semaphore_post), //94 (0x05E)
|
||||
null_func,//bind_func(_sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create
|
||||
null_func,//bind_func(_sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy
|
||||
null_func,//bind_func(_sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock
|
||||
null_func,//bind_func(_sys_lwmutex_???lock), //98 (0x062) // internal, used by sys_lwmutex_unlock
|
||||
null_func,//bind_func(_sys_lwmutex_???lock), //99 (0x063) // internal, used by sys_lwmutex_trylock
|
||||
bind_func(_sys_lwmutex_create), //95 (0x05F)
|
||||
bind_func(_sys_lwmutex_destroy), //96 (0x060)
|
||||
bind_func(_sys_lwmutex_lock), //97 (0x061)
|
||||
bind_func(_sys_lwmutex_unlock), //98 (0x062)
|
||||
bind_func(_sys_lwmutex_trylock), //99 (0x063)
|
||||
bind_func(sys_mutex_create), //100 (0x064)
|
||||
bind_func(sys_mutex_destroy), //101 (0x065)
|
||||
bind_func(sys_mutex_lock), //102 (0x066)
|
||||
@ -146,12 +147,12 @@ const ppu_func_caller sc_table[1024] =
|
||||
bind_func(sys_cond_signal), //108 (0x06C)
|
||||
bind_func(sys_cond_signal_all), //109 (0x06D)
|
||||
bind_func(sys_cond_signal_to), //110 (0x06E)
|
||||
null_func,//bind_func(_sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create
|
||||
null_func,//bind_func(_sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy
|
||||
null_func,//bind_func(_sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait
|
||||
bind_func(_sys_lwcond_create), //111 (0x06F)
|
||||
bind_func(_sys_lwcond_destroy), //112 (0x070)
|
||||
bind_func(_sys_lwcond_queue_wait), //113 (0x071)
|
||||
bind_func(sys_semaphore_get_value), //114 (0x072)
|
||||
null_func,//bind_func(sys_semaphore_...) //115 (0x073) // internal, used by sys_lwcond_signal, sys_lwcond_signal_to
|
||||
null_func,//bind_func(sys_semaphore_...) //116 (0x074) // internal, used by sys_lwcond_signal_all
|
||||
bind_func(_sys_lwcond_signal), //115 (0x073)
|
||||
bind_func(_sys_lwcond_signal_all), //116 (0x074)
|
||||
null_func,//bind_func(sys_semaphore_...) //117 (0x075) // internal, used by sys_lwmutex_unlock
|
||||
bind_func(sys_event_flag_clear), //118 (0x076)
|
||||
null_func,//bind_func(sys_event_...) //119 (0x077) ROOT
|
||||
|
@ -131,9 +131,6 @@ s32 cellFsRead(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<be_t<u64>> nread)
|
||||
if (!Emu.GetIdManager().GetIDData(fd, file))
|
||||
return CELL_ESRCH;
|
||||
|
||||
if (nbytes != (u32)nbytes)
|
||||
return CELL_ENOMEM;
|
||||
|
||||
// TODO: checks
|
||||
|
||||
const u64 res = nbytes ? file->Read(buf.get_ptr(), nbytes) : 0;
|
||||
@ -150,8 +147,6 @@ s32 cellFsWrite(u32 fd, vm::ptr<const void> buf, u64 nbytes, vm::ptr<u64> nwrite
|
||||
std::shared_ptr<vfsStream> file;
|
||||
if (!Emu.GetIdManager().GetIDData(fd, file)) return CELL_ESRCH;
|
||||
|
||||
if (nbytes != (u32)nbytes) return CELL_ENOMEM;
|
||||
|
||||
// TODO: checks
|
||||
|
||||
const u64 res = nbytes ? file->Write(buf.get_ptr(), nbytes) : 0;
|
||||
@ -165,7 +160,7 @@ s32 cellFsClose(u32 fd)
|
||||
{
|
||||
sys_fs.Warning("cellFsClose(fd=0x%x)", fd);
|
||||
|
||||
if (!Emu.GetIdManager().RemoveID(fd))
|
||||
if (!Emu.GetIdManager().RemoveID<vfsStream>(fd))
|
||||
return CELL_ESRCH;
|
||||
|
||||
return CELL_OK;
|
||||
@ -214,7 +209,7 @@ s32 cellFsClosedir(u32 fd)
|
||||
{
|
||||
sys_fs.Warning("cellFsClosedir(fd=0x%x)", fd);
|
||||
|
||||
if (!Emu.GetIdManager().RemoveID(fd))
|
||||
if (!Emu.GetIdManager().RemoveID<vfsDirBase>(fd))
|
||||
return CELL_ESRCH;
|
||||
|
||||
return CELL_OK;
|
||||
|
@ -125,7 +125,7 @@ u32 sleep_queue_t::signal(u32 protocol)
|
||||
if (m_waiting.size())
|
||||
{
|
||||
res = m_waiting[0];
|
||||
if (!Emu.GetIdManager().CheckID(res))
|
||||
if (!Emu.GetIdManager().CheckID<CPUThread>(res))
|
||||
{
|
||||
LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(SYS_SYNC_FIFO) failed: invalid thread (%d)", m_name.c_str(), res);
|
||||
Emu.Pause();
|
||||
|
@ -67,7 +67,7 @@ s32 sys_cond_destroy(u32 cond_id)
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(cond_id);
|
||||
Emu.GetIdManager().RemoveID<cond_t>(cond_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -89,7 +89,7 @@ s32 sys_cond_signal(u32 cond_id)
|
||||
{
|
||||
cond->signaled++;
|
||||
cond->waiters--;
|
||||
cond->mutex->cv.notify_one();
|
||||
cond->cv.notify_one();
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -111,7 +111,7 @@ s32 sys_cond_signal_all(u32 cond_id)
|
||||
if (cond->waiters)
|
||||
{
|
||||
cond->signaled += cond->waiters.exchange(0);
|
||||
cond->mutex->cv.notify_all();
|
||||
cond->cv.notify_all();
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -130,7 +130,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!Emu.GetIdManager().CheckID(thread_id))
|
||||
if (!Emu.GetIdManager().CheckID<CPUThread>(thread_id))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
@ -142,7 +142,8 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
||||
|
||||
cond->signaled++;
|
||||
cond->waiters--;
|
||||
cond->mutex->cv.notify_one();
|
||||
cond->cv.notify_one();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -173,16 +174,23 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
|
||||
|
||||
// unlock mutex
|
||||
cond->mutex->owner.reset();
|
||||
cond->mutex->cv.notify_one();
|
||||
|
||||
// not sure whether the recursive value is precisely saved
|
||||
// save recursive value
|
||||
const u32 recursive_value = cond->mutex->recursive_count.exchange(0);
|
||||
|
||||
while (!cond->mutex->owner.expired() || !cond->signaled)
|
||||
{
|
||||
if (!cond->signaled && timeout && get_system_time() - start_time > timeout)
|
||||
const bool is_timedout = timeout && get_system_time() - start_time > timeout;
|
||||
|
||||
// check timeout only if no thread signaled (the flaw of avoiding sleep queue)
|
||||
if (is_timedout && cond->mutex->owner.expired() && !cond->signaled)
|
||||
{
|
||||
// TODO: mutex not locked, timeout is possible only when signaled == 0
|
||||
// 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);
|
||||
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
|
||||
@ -192,14 +200,14 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
cond->mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||
// wait on appropriate condition variable
|
||||
(cond->signaled || is_timedout ? cond->mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
// restore mutex owner
|
||||
// reown the mutex and restore its recursive value
|
||||
cond->mutex->owner = thread;
|
||||
cond->mutex->recursive_count = recursive_value;
|
||||
|
||||
cond->signaled--; assert(cond->signaled >= 0);
|
||||
cond->signaled--;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -20,15 +20,17 @@ struct cond_t
|
||||
const u64 name;
|
||||
const std::shared_ptr<mutex_t> mutex; // associated mutex
|
||||
|
||||
// TODO: use sleep queue
|
||||
std::atomic<u32> signaled;
|
||||
|
||||
// TODO: use sleep queue, possibly remove condition variable
|
||||
std::condition_variable cv;
|
||||
std::atomic<s32> waiters;
|
||||
std::atomic<s32> signaled;
|
||||
|
||||
cond_t(std::shared_ptr<mutex_t>& mutex, u64 name)
|
||||
: mutex(mutex)
|
||||
, name(name)
|
||||
, waiters(0)
|
||||
, signaled(0)
|
||||
, waiters(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -100,7 +100,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
|
||||
}
|
||||
|
||||
Emu.GetEventManager().UnregisterKey(queue->key);
|
||||
Emu.GetIdManager().RemoveID(equeue_id);
|
||||
Emu.GetIdManager().RemoveID<event_queue_t>(equeue_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -274,7 +274,7 @@ s32 sys_event_port_destroy(u32 eport_id)
|
||||
return CELL_EISCONN;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(eport_id);
|
||||
Emu.GetIdManager().RemoveID<event_port_t>(eport_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ s32 sys_event_flag_destroy(u32 id)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(id);
|
||||
Emu.GetIdManager().RemoveID<event_flag_t>(id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ struct sys_event_flag_attr
|
||||
|
||||
struct event_flag_t
|
||||
{
|
||||
std::atomic<u64> flags;
|
||||
|
||||
const u32 protocol;
|
||||
const s32 type;
|
||||
const u64 name;
|
||||
|
||||
std::atomic<u64> flags;
|
||||
|
||||
// TODO: use sleep queue, possibly remove condition variable
|
||||
std::condition_variable cv;
|
||||
std::atomic<s32> waiters;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/SysCalls/Modules/sysPrxForUser.h"
|
||||
#include "sleep_queue.h"
|
||||
#include "sys_time.h"
|
||||
#include "sys_lwmutex.h"
|
||||
@ -12,220 +13,229 @@
|
||||
|
||||
SysCallBase sys_lwcond("sys_lwcond");
|
||||
|
||||
s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64)
|
||||
void lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name)
|
||||
{
|
||||
const u32 addr = vm::get_addr(&lwmutex);
|
||||
std::shared_ptr<lwcond_t> cond(new lwcond_t(name));
|
||||
|
||||
std::shared_ptr<Lwcond> lw(new Lwcond(name_u64, addr));
|
||||
lwcond.lwcond_queue = Emu.GetIdManager().GetNewID(cond, TYPE_LWCOND);
|
||||
}
|
||||
|
||||
const u32 id = Emu.GetIdManager().GetNewID(lw, TYPE_LWCOND);
|
||||
s32 _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5)
|
||||
{
|
||||
sys_lwcond.Warning("_sys_lwcond_create(lwcond_id=*0x%x, lwmutex_id=%d, control=*0x%x, name=0x%llx, arg5=0x%x)", lwcond_id, lwmutex_id, control, name, arg5);
|
||||
|
||||
lw->queue.set_full_name(fmt::Format("Lwcond(%d, addr=0x%x)", id, lw->addr));
|
||||
lwcond.lwmutex.set(addr);
|
||||
lwcond.lwcond_queue = id;
|
||||
std::shared_ptr<lwcond_t> cond(new lwcond_t(name));
|
||||
|
||||
*lwcond_id = Emu.GetIdManager().GetNewID(cond, TYPE_LWCOND);
|
||||
|
||||
sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), addr, id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr)
|
||||
s32 _sys_lwcond_destroy(u32 lwcond_id)
|
||||
{
|
||||
sys_lwcond.Log("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)",
|
||||
lwcond.addr(), lwmutex.addr(), attr.addr());
|
||||
sys_lwcond.Warning("_sys_lwcond_destroy(lwcond_id=%d)", lwcond_id);
|
||||
|
||||
return lwcond_create(*lwcond, *lwmutex, attr->name_u64);
|
||||
}
|
||||
LV2_LOCK;
|
||||
|
||||
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.addr());
|
||||
|
||||
u32 id = lwcond->lwcond_queue;
|
||||
|
||||
std::shared_ptr<Lwcond> lw;
|
||||
if (!Emu.GetIdManager().GetIDData(id, lw))
|
||||
std::shared_ptr<lwcond_t> cond;
|
||||
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (lw->queue.count()) // TODO: safely make object unusable
|
||||
if (cond->waiters)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(id);
|
||||
Emu.GetIdManager().RemoveID<lwcond_t>(lwcond_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal(vm::ptr<sys_lwcond_t> lwcond)
|
||||
s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mode)
|
||||
{
|
||||
sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.addr());
|
||||
sys_lwcond.Log("_sys_lwcond_signal(lwcond_id=%d, lwmutex_id=%d, ppu_thread_id=%d, mode=%d)", lwcond_id, lwmutex_id, ppu_thread_id, mode);
|
||||
|
||||
std::shared_ptr<Lwcond> lw;
|
||||
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lwcond_t> cond;
|
||||
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
auto mutex = lwcond->lwmutex.to_le();
|
||||
|
||||
if (u32 target = lw->queue.signal(mutex->attribute))
|
||||
std::shared_ptr<lwmutex_t> mutex;
|
||||
if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
// ppu_thread_id is ignored in current implementation
|
||||
|
||||
if (mode != 1 && mode != 2 && mode != 3)
|
||||
{
|
||||
sys_lwcond.Error("_sys_lwcond_signal(%d): invalid mode (%d)", lwcond_id, mode);
|
||||
}
|
||||
|
||||
if (~ppu_thread_id)
|
||||
{
|
||||
sys_lwcond.Todo("_sys_lwcond_signal(%d): ppu_thread_id (%d)", lwcond_id, ppu_thread_id);
|
||||
}
|
||||
|
||||
if (mode == 1)
|
||||
{
|
||||
// mode 1: lightweight mutex was initially owned by the calling thread
|
||||
|
||||
if (!cond->waiters)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
cond->signaled1++;
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
// mode 2: lightweight mutex was not owned by the calling thread and waiter hasn't been increased
|
||||
|
||||
if (!cond->waiters)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_signal(id=%d) aborted", (u32)lwcond->lwcond_queue);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
cond->signaled2++;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal_all(vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.addr());
|
||||
|
||||
std::shared_ptr<Lwcond> lw;
|
||||
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
||||
else
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
// in mode 3, lightweight mutex was forcefully owned by the calling thread
|
||||
|
||||
auto mutex = lwcond->lwmutex.to_le();
|
||||
|
||||
while (u32 target = lw->queue.signal(mutex->attribute))
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
if (!cond->waiters)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue);
|
||||
return CELL_OK;
|
||||
return ~ppu_thread_id ? CELL_ENOENT : CELL_EPERM;
|
||||
}
|
||||
|
||||
cond->signaled1++;
|
||||
}
|
||||
|
||||
cond->waiters--;
|
||||
cond->cv.notify_one();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode)
|
||||
{
|
||||
sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.addr(), ppu_thread_id);
|
||||
sys_lwcond.Log("_sys_lwcond_signal_all(lwcond_id=%d, lwmutex_id=%d, mode=%d)", lwcond_id, lwmutex_id, mode);
|
||||
|
||||
std::shared_ptr<Lwcond> lw;
|
||||
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lwcond_t> cond;
|
||||
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!Emu.GetIdManager().CheckID(ppu_thread_id))
|
||||
std::shared_ptr<lwmutex_t> mutex;
|
||||
if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!lw->queue.signal_selected(ppu_thread_id))
|
||||
if (mode != 1 && mode != 2)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
sys_lwcond.Error("_sys_lwcond_signal_all(%d): invalid mode (%d)", lwcond_id, mode);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
const s32 count = cond->waiters.exchange(0);
|
||||
cond->cv.notify_all();
|
||||
|
||||
if (mode == 1)
|
||||
{
|
||||
// in mode 1, lightweight mutex was initially owned by the calling thread
|
||||
|
||||
cond->signaled1 += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// in mode 2, lightweight mutex was not owned by the calling thread and waiter hasn't been increased
|
||||
|
||||
cond->signaled2 += count;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
|
||||
s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout)
|
||||
{
|
||||
sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout);
|
||||
sys_lwcond.Log("_sys_lwcond_queue_wait(lwcond_id=%d, lwmutex_id=%d, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout);
|
||||
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
std::shared_ptr<Lwcond> lw;
|
||||
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lwcond_t> cond;
|
||||
if (!Emu.GetIdManager().GetIDData(lwcond_id, cond))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
auto mutex = lwcond->lwmutex.to_le();
|
||||
u32 tid_le = CPU.GetId();
|
||||
auto tid = be_t<u32>::make(tid_le);
|
||||
|
||||
std::shared_ptr<sleep_queue_t> sq;
|
||||
if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq))
|
||||
std::shared_ptr<lwmutex_t> mutex;
|
||||
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)",
|
||||
(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (mutex->owner.read_sync() != tid)
|
||||
// finalize unlocking the mutex
|
||||
mutex->signaled++;
|
||||
mutex->cv.notify_one();
|
||||
|
||||
// protocol is ignored in current implementation
|
||||
cond->waiters++; assert(cond->waiters > 0);
|
||||
|
||||
while (!(cond->signaled1 && mutex->signaled) && !cond->signaled2)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
const bool is_timedout = timeout && get_system_time() - start_time > timeout;
|
||||
|
||||
lw->queue.push(tid_le, mutex->attribute);
|
||||
|
||||
auto old_recursive = mutex->recursive_count.read_relaxed();
|
||||
mutex->recursive_count.exchange(be_t<u32>::make(0));
|
||||
|
||||
auto target = be_t<u32>::make(sq->signal(mutex->attribute));
|
||||
if (!mutex->owner.compare_and_swap_test(tid, target))
|
||||
{
|
||||
assert(!"sys_lwcond_wait(): mutex unlocking failed");
|
||||
}
|
||||
|
||||
bool signaled = false;
|
||||
while (true)
|
||||
{
|
||||
if ((signaled = signaled || lw->queue.pop(tid, mutex->attribute))) // check signaled threads
|
||||
// check timeout only if no thread signaled in mode 1 (the flaw of avoiding sleep queue)
|
||||
if (is_timedout && !cond->signaled1)
|
||||
{
|
||||
s32 res = mutex->lock(tid, timeout ? get_system_time() - start_time : 0); // this is bad
|
||||
if (res == CELL_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// cancel waiting
|
||||
cond->waiters--; assert(cond->waiters >= 0);
|
||||
|
||||
switch (res)
|
||||
if (mutex->signaled)
|
||||
{
|
||||
case static_cast<int>(CELL_EDEADLK):
|
||||
{
|
||||
sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue);
|
||||
return CELL_OK; // mutex not locked (but already locked in the incorrect way)
|
||||
}
|
||||
case static_cast<int>(CELL_ESRCH):
|
||||
{
|
||||
sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex not found (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
|
||||
return CELL_ESRCH; // mutex not locked
|
||||
}
|
||||
case static_cast<int>(CELL_ETIMEDOUT):
|
||||
{
|
||||
return CELL_ETIMEDOUT; // mutex not locked
|
||||
}
|
||||
case static_cast<int>(CELL_EINVAL):
|
||||
{
|
||||
sys_lwcond.Error("sys_lwcond_wait(id=%d): invalid associated mutex (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
|
||||
return CELL_EINVAL; // mutex not locked
|
||||
}
|
||||
default:
|
||||
{
|
||||
sys_lwcond.Error("sys_lwcond_wait(id=%d): mutex->lock() returned 0x%x", (u32)lwcond->lwcond_queue, res);
|
||||
return CELL_EINVAL; // mutex not locked
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex->signaled--;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
|
||||
if (timeout && get_system_time() - start_time > timeout)
|
||||
{
|
||||
if (!lw->queue.invalidate(tid_le, mutex->attribute))
|
||||
{
|
||||
assert(!"sys_lwcond_wait() failed (timeout)");
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
return CELL_ETIMEDOUT; // mutex not locked
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
|
||||
sys_lwcond.Warning("_sys_lwcond_queue_wait(lwcond_id=%d) aborted", lwcond_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
(cond->signaled1 ? mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
mutex->recursive_count.exchange(old_recursive);
|
||||
return CELL_OK;
|
||||
if (cond->signaled1 && mutex->signaled)
|
||||
{
|
||||
mutex->signaled--;
|
||||
cond->signaled1--;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
cond->signaled2--;
|
||||
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
}
|
||||
|
@ -14,31 +14,37 @@ struct sys_lwcond_attribute_t
|
||||
struct sys_lwcond_t
|
||||
{
|
||||
vm::bptr<sys_lwmutex_t> lwmutex;
|
||||
be_t<u32> lwcond_queue;
|
||||
be_t<u32> lwcond_queue; // lwcond pseudo-id
|
||||
};
|
||||
|
||||
struct Lwcond
|
||||
struct lwcond_t
|
||||
{
|
||||
sleep_queue_t queue;
|
||||
const u64 name;
|
||||
|
||||
const u32 addr;
|
||||
std::atomic<u32> signaled1; // mode 1 signals
|
||||
std::atomic<u32> signaled2; // mode 2 signals
|
||||
|
||||
Lwcond(u64 name, u32 addr)
|
||||
: queue(name)
|
||||
, addr(addr)
|
||||
// TODO: use sleep queue
|
||||
std::condition_variable cv;
|
||||
std::atomic<s32> waiters;
|
||||
|
||||
lwcond_t(u64 name)
|
||||
: name(name)
|
||||
, signaled1(0)
|
||||
, signaled2(0)
|
||||
, waiters(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Aux
|
||||
s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64);
|
||||
void lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name);
|
||||
|
||||
class PPUThread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr);
|
||||
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal(vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_all(vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id);
|
||||
s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);
|
||||
s32 _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5);
|
||||
s32 _sys_lwcond_destroy(u32 lwcond_id);
|
||||
s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mode);
|
||||
s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode);
|
||||
s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout);
|
||||
|
@ -12,210 +12,144 @@
|
||||
|
||||
SysCallBase sys_lwmutex("sys_lwmutex");
|
||||
|
||||
s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64)
|
||||
void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name)
|
||||
{
|
||||
std::shared_ptr<sleep_queue_t> sq(new sleep_queue_t(name_u64));
|
||||
std::shared_ptr<lwmutex_t> mutex(new lwmutex_t(protocol, name));
|
||||
|
||||
lwmutex.owner.write_relaxed(be_t<u32>::make(0));
|
||||
lwmutex.waiter.write_relaxed(be_t<u32>::make(~0));
|
||||
lwmutex.attribute = protocol | recursive;
|
||||
lwmutex.recursive_count.write_relaxed(be_t<u32>::make(0));
|
||||
u32 sq_id = Emu.GetIdManager().GetNewID(sq, TYPE_LWMUTEX);
|
||||
lwmutex.sleep_queue = sq_id;
|
||||
sq->set_full_name(fmt::Format("Lwmutex(%d, addr=0x%x)", sq_id, vm::get_addr(&lwmutex)));
|
||||
lwmutex.lock_var.write_relaxed({ lwmutex::free, lwmutex::zero });
|
||||
lwmutex.attribute = protocol | (recursive ? SYS_SYNC_RECURSIVE : SYS_SYNC_NOT_RECURSIVE);
|
||||
lwmutex.recursive_count = 0;
|
||||
lwmutex.sleep_queue = Emu.GetIdManager().GetNewID(mutex, TYPE_LWMUTEX);
|
||||
}
|
||||
|
||||
s32 _sys_lwmutex_create(vm::ptr<u32> lwmutex_id, u32 protocol, vm::ptr<sys_lwmutex_t> control, u32 arg4, u64 name, u32 arg6)
|
||||
{
|
||||
sys_lwmutex.Warning("_sys_lwmutex_create(lwmutex_id=*0x%x, protocol=0x%x, control=*0x%x, arg4=0x%x, name=0x%llx, arg6=0x%x)", lwmutex_id, protocol, control, arg4, name, arg6);
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case SYS_SYNC_FIFO: break;
|
||||
case SYS_SYNC_RETRY: break;
|
||||
case SYS_SYNC_PRIORITY: break;
|
||||
default: sys_lwmutex.Error("_sys_lwmutex_create(): invalid protocol (0x%x)", protocol); return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (arg4 != 0x80000001 || arg6)
|
||||
{
|
||||
sys_lwmutex.Error("_sys_lwmutex_create(): unknown parameters (arg4=0x%x, arg6=0x%x)", arg4, arg6);
|
||||
}
|
||||
|
||||
std::shared_ptr<lwmutex_t> mutex(new lwmutex_t(protocol, name));
|
||||
|
||||
*lwmutex_id = Emu.GetIdManager().GetNewID(mutex, TYPE_LWMUTEX);
|
||||
|
||||
// passing be_t<u32> (test)
|
||||
sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", std::string((const char*)&name_u64, 8).c_str(), lwmutex.attribute, sq_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
|
||||
s32 _sys_lwmutex_destroy(u32 lwmutex_id)
|
||||
{
|
||||
sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr());
|
||||
sys_lwmutex.Warning("_sys_lwmutex_destroy(lwmutex_id=%d)", lwmutex_id);
|
||||
|
||||
switch (attr->recursive.data())
|
||||
{
|
||||
case se32(SYS_SYNC_RECURSIVE): break;
|
||||
case se32(SYS_SYNC_NOT_RECURSIVE): break;
|
||||
default: sys_lwmutex.Error("Unknown recursive attribute (0x%x)", attr->recursive); return CELL_EINVAL;
|
||||
}
|
||||
LV2_LOCK;
|
||||
|
||||
switch (attr->protocol.data())
|
||||
{
|
||||
case se32(SYS_SYNC_PRIORITY): break;
|
||||
case se32(SYS_SYNC_RETRY): break;
|
||||
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwmutex.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL;
|
||||
case se32(SYS_SYNC_FIFO): break;
|
||||
default: sys_lwmutex.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL;
|
||||
}
|
||||
|
||||
return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64);
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr());
|
||||
|
||||
u32 sq_id = lwmutex->sleep_queue;
|
||||
if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH;
|
||||
|
||||
if (s32 res = lwmutex->trylock(be_t<u32>::make(~0)))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// try to make it unable to lock
|
||||
lwmutex->all_info() = 0;
|
||||
lwmutex->attribute = 0xDEADBEEF;
|
||||
lwmutex->sleep_queue = 0;
|
||||
Emu.GetIdManager().RemoveID(sq_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
{
|
||||
sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout);
|
||||
|
||||
return lwmutex->lock(be_t<u32>::make(CPU.GetId()), timeout);
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr());
|
||||
|
||||
return lwmutex->trylock(be_t<u32>::make(CPU.GetId()));
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr());
|
||||
|
||||
return lwmutex->unlock(be_t<u32>::make(CPU.GetId()));
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_t::trylock(be_t<u32> tid)
|
||||
{
|
||||
if (attribute.data() == se32(0xDEADBEEF))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!Emu.GetIdManager().CheckID(sleep_queue))
|
||||
std::shared_ptr<lwmutex_t> mutex;
|
||||
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
const be_t<u32> old_owner = owner.read_sync();
|
||||
|
||||
if (old_owner == tid)
|
||||
{
|
||||
if (attribute.data() & se32(SYS_SYNC_RECURSIVE))
|
||||
{
|
||||
auto rv = recursive_count.read_relaxed();
|
||||
if (!~(rv++).data())
|
||||
{
|
||||
return CELL_EKRESOURCE;
|
||||
}
|
||||
|
||||
recursive_count.exchange(rv);
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!owner.compare_and_swap_test(be_t<u32>::make(0), tid))
|
||||
if (mutex->waiters)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
recursive_count.exchange(be_t<u32>::make(1));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_t::unlock(be_t<u32> tid)
|
||||
{
|
||||
if (owner.read_sync() != tid)
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
auto rv = recursive_count.read_relaxed();
|
||||
if (!rv.data() || (rv.data() != se32(1) && (attribute.data() & se32(SYS_SYNC_NOT_RECURSIVE))))
|
||||
{
|
||||
sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)rv);
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
rv--;
|
||||
recursive_count.exchange(rv);
|
||||
if (!rv.data())
|
||||
{
|
||||
std::shared_ptr<sleep_queue_t> sq;
|
||||
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!owner.compare_and_swap_test(tid, be_t<u32>::make(sq->signal(attribute))))
|
||||
{
|
||||
assert(!"sys_lwmutex_t::unlock() failed");
|
||||
}
|
||||
}
|
||||
Emu.GetIdManager().RemoveID<lwmutex_t>(lwmutex_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout)
|
||||
s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout)
|
||||
{
|
||||
sys_lwmutex.Log("_sys_lwmutex_lock(lwmutex_id=%d, timeout=0x%llx)", lwmutex_id, timeout);
|
||||
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
switch (s32 res = trylock(tid))
|
||||
{
|
||||
case static_cast<s32>(CELL_EBUSY): break;
|
||||
default: return res;
|
||||
}
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<sleep_queue_t> sq;
|
||||
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
|
||||
std::shared_ptr<lwmutex_t> mutex;
|
||||
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
sq->push(tid, attribute);
|
||||
// protocol is ignored in current implementation
|
||||
mutex->waiters++; assert(mutex->waiters > 0);
|
||||
|
||||
while (true)
|
||||
while (!mutex->signaled)
|
||||
{
|
||||
auto old_owner = owner.compare_and_swap(be_t<u32>::make(0), tid);
|
||||
if (!old_owner.data() || old_owner == tid)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
|
||||
if (timeout && get_system_time() - start_time > timeout)
|
||||
{
|
||||
if (!sq->invalidate(tid, attribute))
|
||||
{
|
||||
assert(!"sys_lwmutex_t::lock() failed (timeout)");
|
||||
}
|
||||
mutex->waiters--; assert(mutex->waiters >= 0);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sys_lwmutex.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue);
|
||||
sys_lwmutex.Warning("_sys_lwmutex_lock(lwmutex_id=%d) aborted", lwmutex_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sq->invalidate(tid, attribute) && !sq->pop(tid, attribute))
|
||||
{
|
||||
assert(!"sys_lwmutex_t::lock() failed (locking)");
|
||||
mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
recursive_count.exchange(be_t<u32>::make(1));
|
||||
|
||||
mutex->signaled--;
|
||||
|
||||
mutex->waiters--; assert(mutex->waiters >= 0);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_lwmutex_trylock(u32 lwmutex_id)
|
||||
{
|
||||
sys_lwmutex.Log("_sys_lwmutex_trylock(lwmutex_id=%d)", lwmutex_id);
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lwmutex_t> mutex;
|
||||
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (mutex->waiters || !mutex->signaled)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
mutex->signaled--;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_lwmutex_unlock(u32 lwmutex_id)
|
||||
{
|
||||
sys_lwmutex.Log("_sys_lwmutex_unlock(lwmutex_id=%d)", lwmutex_id);
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lwmutex_t> mutex;
|
||||
if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (mutex->signaled)
|
||||
{
|
||||
sys_lwmutex.Fatal("_sys_lwmutex_unlock(lwmutex_id=%d): already signaled", lwmutex_id);
|
||||
}
|
||||
|
||||
mutex->signaled++;
|
||||
mutex->cv.notify_one();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ struct sys_lwmutex_attribute_t
|
||||
{
|
||||
be_t<u32> protocol;
|
||||
be_t<u32> recursive;
|
||||
|
||||
union
|
||||
{
|
||||
char name[8];
|
||||
@ -11,33 +12,89 @@ struct sys_lwmutex_attribute_t
|
||||
};
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
lwmutex_zero = 0u,
|
||||
lwmutex_free = 0u - 1u,
|
||||
lwmutex_dead = 0u - 2u,
|
||||
lwmutex_reserved = 0u - 3u,
|
||||
};
|
||||
|
||||
namespace lwmutex
|
||||
{
|
||||
template<u32 _value>
|
||||
struct const_be_u32_t
|
||||
{
|
||||
static const u32 value = _value;
|
||||
|
||||
operator const be_t<u32>() const
|
||||
{
|
||||
return be_t<u32>::make(value);
|
||||
}
|
||||
};
|
||||
|
||||
static const_be_u32_t<lwmutex_zero> zero;
|
||||
static const_be_u32_t<lwmutex_free> free;
|
||||
static const_be_u32_t<lwmutex_dead> dead;
|
||||
static const_be_u32_t<lwmutex_reserved> reserved;
|
||||
}
|
||||
|
||||
struct sys_lwmutex_t
|
||||
{
|
||||
atomic_t<u32> owner;
|
||||
atomic_t<u32> waiter; // currently not used
|
||||
be_t<u32> attribute;
|
||||
atomic_t<u32> recursive_count;
|
||||
be_t<u32> sleep_queue;
|
||||
be_t<u32> pad;
|
||||
|
||||
u64& all_info()
|
||||
struct sync_var_t
|
||||
{
|
||||
return *(reinterpret_cast<u64*>(this));
|
||||
}
|
||||
be_t<u32> owner;
|
||||
be_t<u32> waiter;
|
||||
};
|
||||
|
||||
s32 trylock(be_t<u32> tid);
|
||||
s32 unlock(be_t<u32> tid);
|
||||
s32 lock(be_t<u32> tid, u64 timeout);
|
||||
union
|
||||
{
|
||||
atomic_t<sync_var_t> lock_var;
|
||||
|
||||
struct
|
||||
{
|
||||
atomic_t<u32> owner;
|
||||
atomic_t<u32> waiter;
|
||||
};
|
||||
|
||||
atomic_t<u64> all_info;
|
||||
};
|
||||
|
||||
be_t<u32> attribute;
|
||||
be_t<u32> recursive_count;
|
||||
be_t<u32> sleep_queue; // lwmutex pseudo-id
|
||||
be_t<u32> pad;
|
||||
};
|
||||
|
||||
struct lwmutex_t
|
||||
{
|
||||
const u32 protocol;
|
||||
const u64 name;
|
||||
|
||||
// this object is not truly a mutex and its syscall names are wrong, it's probabably sleep queue or something
|
||||
std::atomic<u32> signaled;
|
||||
|
||||
// TODO: use sleep queue, possibly remove condition variable
|
||||
std::condition_variable cv;
|
||||
std::atomic<s32> waiters;
|
||||
|
||||
lwmutex_t(u32 protocol, u64 name)
|
||||
: protocol(protocol)
|
||||
, name(name)
|
||||
, signaled(0)
|
||||
, waiters(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Aux
|
||||
s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64);
|
||||
void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name);
|
||||
|
||||
class PPUThread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
|
||||
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 _sys_lwmutex_create(vm::ptr<u32> lwmutex_id, u32 protocol, vm::ptr<sys_lwmutex_t> control, u32 arg4, u64 name, u32 arg6);
|
||||
s32 _sys_lwmutex_destroy(u32 lwmutex_id);
|
||||
s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout);
|
||||
s32 _sys_lwmutex_trylock(u32 lwmutex_id);
|
||||
s32 _sys_lwmutex_unlock(u32 lwmutex_id);
|
||||
|
@ -141,7 +141,7 @@ s32 sys_memory_container_destroy(u32 cid)
|
||||
|
||||
// Release the allocated memory and remove the ID.
|
||||
Memory.Free(ct->addr);
|
||||
Emu.GetIdManager().RemoveID(cid);
|
||||
Emu.GetIdManager().RemoveID<MemoryContainerInfo>(cid);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ s32 sys_mmapper_allocate_memory(u32 size, u64 flags, vm::ptr<u32> mem_id)
|
||||
|
||||
// Generate a new mem ID.
|
||||
std::shared_ptr<mmapper_info> info(new mmapper_info(size, flags));
|
||||
*mem_id = Emu.GetIdManager().GetNewID(info);
|
||||
*mem_id = Emu.GetIdManager().GetNewID(info, TYPE_MEM);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -147,7 +147,7 @@ s32 sys_mmapper_free_memory(u32 mem_id)
|
||||
return CELL_ESRCH;
|
||||
|
||||
// Release the allocated memory and remove the ID.
|
||||
Emu.GetIdManager().RemoveID(mem_id);
|
||||
Emu.GetIdManager().RemoveID<mmapper_info>(mem_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ s32 sys_mutex_destroy(u32 mutex_id)
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(mutex_id);
|
||||
Emu.GetIdManager().RemoveID<mutex_t>(mutex_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -110,10 +110,7 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
|
||||
return CELL_EKRESOURCE;
|
||||
}
|
||||
|
||||
if (!mutex->recursive_count++)
|
||||
{
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
mutex->recursive_count++;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -142,7 +139,6 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
|
||||
}
|
||||
|
||||
mutex->owner = thread;
|
||||
mutex->recursive_count = 1;
|
||||
mutex->waiters--; assert(mutex->waiters >= 0);
|
||||
|
||||
return CELL_OK;
|
||||
@ -172,10 +168,7 @@ s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id)
|
||||
return CELL_EKRESOURCE;
|
||||
}
|
||||
|
||||
if (!mutex->recursive_count++)
|
||||
{
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
mutex->recursive_count++;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -189,7 +182,6 @@ s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id)
|
||||
}
|
||||
|
||||
mutex->owner = thread;
|
||||
mutex->recursive_count = 1;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -214,12 +206,16 @@ s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id)
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
if (!mutex->recursive_count || (!mutex->recursive && mutex->recursive_count != 1))
|
||||
if (mutex->recursive_count)
|
||||
{
|
||||
throw __FUNCTION__;
|
||||
if (!mutex->recursive)
|
||||
{
|
||||
throw __FUNCTION__;
|
||||
}
|
||||
|
||||
mutex->recursive_count--;
|
||||
}
|
||||
|
||||
if (!--mutex->recursive_count)
|
||||
else
|
||||
{
|
||||
mutex->owner.reset();
|
||||
mutex->cv.notify_one();
|
||||
|
@ -198,11 +198,13 @@ s32 sys_ppu_thread_create(vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
std::mutex g_once_mutex;
|
||||
|
||||
void sys_ppu_thread_once(PPUThread& CPU, vm::ptr<atomic_t<u32>> once_ctrl, vm::ptr<void()> init)
|
||||
{
|
||||
sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl_addr=0x%x, init_addr=0x%x)", once_ctrl.addr(), init.addr());
|
||||
sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl=*0x%x, init=*0x%x)", once_ctrl, init);
|
||||
|
||||
LV2_LOCK;
|
||||
std::lock_guard<std::mutex> lock(g_once_mutex);
|
||||
|
||||
if (once_ctrl->compare_and_swap_test(be_t<u32>::make(SYS_PPU_THREAD_ONCE_INIT), be_t<u32>::make(SYS_PPU_THREAD_DONE_INIT)))
|
||||
{
|
||||
|
@ -8,17 +8,13 @@ enum : u32
|
||||
SYS_PPU_THREAD_DONE_INIT = 1,
|
||||
};
|
||||
|
||||
enum ppu_thread_flags : u64
|
||||
// PPU Thread Flags
|
||||
enum : u64
|
||||
{
|
||||
SYS_PPU_THREAD_CREATE_JOINABLE = 0x1,
|
||||
SYS_PPU_THREAD_CREATE_INTERRUPT = 0x2,
|
||||
};
|
||||
|
||||
enum stackSize
|
||||
{
|
||||
SYS_PPU_THREAD_STACK_MIN = 0x4000,
|
||||
};
|
||||
|
||||
// Aux
|
||||
u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool is_joinable, bool is_interrupt, std::string name, std::function<void(PPUThread&)> task = nullptr);
|
||||
|
||||
|
@ -101,7 +101,7 @@ s32 sys_prx_unload_module(s32 id, u64 flags, vm::ptr<sys_prx_unload_module_optio
|
||||
if (!Emu.GetIdManager().GetIDData(id, prx))
|
||||
return CELL_ESRCH;
|
||||
Memory.Free(prx->address);
|
||||
Emu.GetIdManager().RemoveID(id);
|
||||
Emu.GetIdManager().RemoveID<sys_prx_t>(id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ s32 sys_rwlock_destroy(u32 rw_lock_id)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(rw_lock_id);
|
||||
Emu.GetIdManager().RemoveID<rwlock_t>(rw_lock_id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ s32 sys_semaphore_destroy(u32 sem)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID(sem);
|
||||
Emu.GetIdManager().RemoveID<semaphore_t>(sem);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "sys_spinlock.h"
|
||||
|
||||
SysCallBase sys_spinlock("sys_spinlock");
|
||||
|
||||
void sys_spinlock_initialize(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sys_spinlock.Log("sys_spinlock_initialize(lock_addr=0x%x)", lock.addr());
|
||||
|
||||
// prx: set 0 and sync
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
}
|
||||
|
||||
void sys_spinlock_lock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sys_spinlock.Log("sys_spinlock_lock(lock_addr=0x%x)", lock.addr());
|
||||
|
||||
// prx: exchange with 0xabadcafe, repeat until exchanged with 0
|
||||
while (lock->exchange(be_t<u32>::make(0xabadcafe)).data())
|
||||
{
|
||||
while (lock->read_relaxed().data())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sys_spinlock.Warning("sys_spinlock_lock(0x%x) aborted", lock.addr());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 sys_spinlock_trylock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sys_spinlock.Log("sys_spinlock_trylock(lock_addr=0x%x)", lock.addr());
|
||||
|
||||
// prx: exchange with 0xabadcafe, translate exchanged value
|
||||
if (lock->exchange(be_t<u32>::make(0xabadcafe)).data())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_spinlock_unlock(vm::ptr<atomic_t<u32>> lock)
|
||||
{
|
||||
sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.addr());
|
||||
|
||||
// prx: sync and set 0
|
||||
lock->exchange(be_t<u32>::make(0));
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// SysCalls
|
||||
void sys_spinlock_initialize(vm::ptr<atomic_t<u32>> lock);
|
||||
void sys_spinlock_lock(vm::ptr<atomic_t<u32>> lock);
|
||||
s32 sys_spinlock_trylock(vm::ptr<atomic_t<u32>> lock);
|
||||
void sys_spinlock_unlock(vm::ptr<atomic_t<u32>> lock);
|
@ -272,7 +272,7 @@ s32 sys_spu_thread_group_destroy(u32 id)
|
||||
}
|
||||
|
||||
group->state = SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED; // hack
|
||||
Emu.GetIdManager().RemoveID(id);
|
||||
Emu.GetIdManager().RemoveID<spu_group_t>(id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -4,100 +4,218 @@
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include "Emu/Event.h"
|
||||
#include "Utilities/Thread.h"
|
||||
#include "sys_time.h"
|
||||
#include "sys_event.h"
|
||||
#include "sys_process.h"
|
||||
#include "sys_timer.h"
|
||||
|
||||
SysCallBase sys_timer("sys_timer");
|
||||
|
||||
s32 sys_timer_create(vm::ptr<u32> timer_id)
|
||||
{
|
||||
sys_timer.Warning("sys_timer_create(timer_id_addr=0x%x)", timer_id.addr());
|
||||
sys_timer.Warning("sys_timer_create(timer_id=*0x%x)", timer_id);
|
||||
|
||||
std::shared_ptr<lv2_timer_t> timer(new lv2_timer_t);
|
||||
|
||||
thread_t(fmt::format("Timer[%d] Thread", (*timer_id = Emu.GetIdManager().GetNewID(timer, TYPE_TIMER))), [timer]()
|
||||
{
|
||||
LV2_LOCK;
|
||||
|
||||
while (!timer.unique() && !Emu.IsStopped())
|
||||
{
|
||||
if (timer->state == SYS_TIMER_STATE_RUN)
|
||||
{
|
||||
if (get_system_time() >= timer->start)
|
||||
{
|
||||
std::shared_ptr<event_queue_t> queue = timer->port.lock();
|
||||
|
||||
if (queue)
|
||||
{
|
||||
queue->events.emplace_back(timer->source, timer->data1, timer->data2, timer->start);
|
||||
queue->cv.notify_one();
|
||||
}
|
||||
|
||||
if (timer->period && queue)
|
||||
{
|
||||
timer->start += timer->period; // set next expiration time
|
||||
|
||||
continue; // hack: check again
|
||||
}
|
||||
else
|
||||
{
|
||||
timer->state = SYS_TIMER_STATE_STOP; // stop if oneshot or the event port was disconnected (TODO: is it correct?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
}).detach();
|
||||
|
||||
std::shared_ptr<timer> timer_data(new timer);
|
||||
*timer_id = Emu.GetIdManager().GetNewID(timer_data, TYPE_TIMER);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_destroy(u32 timer_id)
|
||||
{
|
||||
sys_timer.Todo("sys_timer_destroy(timer_id=%d)", timer_id);
|
||||
sys_timer.Warning("sys_timer_destroy(timer_id=%d)", timer_id);
|
||||
|
||||
if(!Emu.GetIdManager().CheckID(timer_id)) return CELL_ESRCH;
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lv2_timer_t> timer;
|
||||
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!timer->port.expired())
|
||||
{
|
||||
return CELL_EISCONN;
|
||||
}
|
||||
|
||||
Emu.GetIdManager().RemoveID<lv2_timer_t>(timer_id);
|
||||
|
||||
Emu.GetIdManager().RemoveID(timer_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_get_information(u32 timer_id, vm::ptr<sys_timer_information_t> info)
|
||||
{
|
||||
sys_timer.Warning("sys_timer_get_information(timer_id=%d, info_addr=0x%x)", timer_id, info.addr());
|
||||
|
||||
std::shared_ptr<timer> timer_data = nullptr;
|
||||
if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH;
|
||||
sys_timer.Warning("sys_timer_get_information(timer_id=%d, info=*0x%x)", timer_id, info);
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lv2_timer_t> timer;
|
||||
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
info->next_expiration_time = timer->start;
|
||||
|
||||
info->period = timer->period;
|
||||
|
||||
info->timer_state = timer->state;
|
||||
|
||||
*info = timer_data->timer_information_t;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_start(u32 timer_id, s64 base_time, u64 period)
|
||||
s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period)
|
||||
{
|
||||
sys_timer.Warning("sys_timer_start_periodic_absolute(timer_id=%d, basetime=%lld, period=%lld)", timer_id, base_time, period);
|
||||
sys_timer.Warning("_sys_timer_start(timer_id=%d, base_time=0x%llx, period=0x%llx)", timer_id, base_time, period);
|
||||
|
||||
std::shared_ptr<timer> timer_data = nullptr;
|
||||
if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH;
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
if(timer_data->timer_information_t.timer_state != SYS_TIMER_STATE_STOP) return CELL_EBUSY;
|
||||
if(period < 100) return CELL_EINVAL;
|
||||
//TODO: if (timer is not connected to an event queue) return CELL_ENOTCONN;
|
||||
|
||||
timer_data->timer_information_t.next_expiration_time = base_time;
|
||||
timer_data->timer_information_t.period = period;
|
||||
timer_data->timer_information_t.timer_state = SYS_TIMER_STATE_RUN;
|
||||
//TODO: ?
|
||||
std::function<s32()> task(std::bind(sys_timer_stop, timer_id));
|
||||
std::thread([period, task]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(period));
|
||||
task();
|
||||
}).detach();
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lv2_timer_t> timer;
|
||||
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (timer->state != SYS_TIMER_STATE_STOP)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
if (!period)
|
||||
{
|
||||
// oneshot timer (TODO: what will happen if both args are 0?)
|
||||
|
||||
if (start_time >= base_time)
|
||||
{
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// periodic timer
|
||||
|
||||
if (period < 100)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer->port.expired())
|
||||
{
|
||||
return CELL_ENOTCONN;
|
||||
}
|
||||
|
||||
// sys_timer_start_periodic() will use current time (TODO: is it correct?)
|
||||
|
||||
timer->start = base_time ? base_time : start_time + period;
|
||||
timer->period = period;
|
||||
timer->state = SYS_TIMER_STATE_RUN;
|
||||
timer->cv.notify_one();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_stop(u32 timer_id)
|
||||
{
|
||||
sys_timer.Todo("sys_timer_stop()");
|
||||
sys_timer.Warning("sys_timer_stop()");
|
||||
|
||||
std::shared_ptr<timer> timer_data = nullptr;
|
||||
if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH;
|
||||
LV2_LOCK;
|
||||
|
||||
std::shared_ptr<lv2_timer_t> timer;
|
||||
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
timer->state = SYS_TIMER_STATE_STOP; // stop timer
|
||||
|
||||
timer_data->timer_information_t.timer_state = SYS_TIMER_STATE_STOP;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data1, u64 data2)
|
||||
{
|
||||
sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=0x%llx, data1=0x%llx, data2=0x%llx)",
|
||||
timer_id, queue_id, name, data1, data2);
|
||||
sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=0x%llx, data1=0x%llx, data2=0x%llx)", timer_id, queue_id, name, data1, data2);
|
||||
|
||||
std::shared_ptr<timer> timer_data = nullptr;
|
||||
std::shared_ptr<event_queue_t> equeue = nullptr;
|
||||
if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH;
|
||||
if(!Emu.GetIdManager().GetIDData(queue_id, equeue)) return CELL_ESRCH;
|
||||
LV2_LOCK;
|
||||
|
||||
//TODO: ?
|
||||
std::shared_ptr<lv2_timer_t> timer;
|
||||
std::shared_ptr<event_queue_t> queue;
|
||||
|
||||
if (!Emu.GetIdManager().GetIDData(timer_id, timer) || !Emu.GetIdManager().GetIDData(queue_id, queue))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!timer->port.expired())
|
||||
{
|
||||
return CELL_EISCONN;
|
||||
}
|
||||
|
||||
timer->port = queue; // connect event queue
|
||||
timer->source = name ? name : ((u64)process_getpid() << 32) | timer_id;
|
||||
timer->data1 = data1;
|
||||
timer->data2 = data2;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_disconnect_event_queue(u32 timer_id)
|
||||
{
|
||||
sys_timer.Todo("sys_timer_disconnect_event_queue(timer_id=%d)", timer_id);
|
||||
sys_timer.Warning("sys_timer_disconnect_event_queue(timer_id=%d)", timer_id);
|
||||
|
||||
std::shared_ptr<timer> timer_data = nullptr;
|
||||
if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH;
|
||||
LV2_LOCK;
|
||||
|
||||
//TODO: ?
|
||||
std::shared_ptr<lv2_timer_t> timer;
|
||||
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (timer->port.expired())
|
||||
{
|
||||
return CELL_ENOTCONN;
|
||||
}
|
||||
|
||||
timer->port.reset(); // disconnect event queue
|
||||
timer->state = SYS_TIMER_STATE_STOP; // stop timer
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -105,31 +223,55 @@ s32 sys_timer_disconnect_event_queue(u32 timer_id)
|
||||
s32 sys_timer_sleep(u32 sleep_time)
|
||||
{
|
||||
sys_timer.Log("sys_timer_sleep(sleep_time=%d)", sleep_time);
|
||||
for (u32 i = 0; i < sleep_time; i++)
|
||||
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
const u64 useconds = sleep_time * 1000000ull;
|
||||
|
||||
u64 passed;
|
||||
|
||||
while (useconds > (passed = get_system_time() - start_time) + 1000)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sys_timer.Warning("sys_timer_sleep(sleep_time=%d) aborted", sleep_time);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (useconds > passed)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(useconds - passed));
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_timer_usleep(u64 sleep_time)
|
||||
{
|
||||
sys_timer.Log("sys_timer_usleep(sleep_time=%lld)", sleep_time);
|
||||
if (sleep_time > 0xFFFFFFFFFFFF) sleep_time = 0xFFFFFFFFFFFF; //2^48-1
|
||||
for (u32 i = 0; i < sleep_time / 1000000; i++)
|
||||
sys_timer.Log("sys_timer_usleep(sleep_time=0x%llx)", sleep_time);
|
||||
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
u64 passed;
|
||||
|
||||
while (sleep_time > (passed = get_system_time() - start_time) + 1000)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
sys_timer.Warning("sys_timer_usleep(sleep_time=%lld) aborted", sleep_time);
|
||||
sys_timer.Warning("sys_timer_usleep(sleep_time=0x%llx) aborted", sleep_time);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(sleep_time % 1000000));
|
||||
|
||||
if (sleep_time > passed)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(sleep_time - passed));
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -1,28 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
enum
|
||||
// Timer State
|
||||
enum : u32
|
||||
{
|
||||
SYS_TIMER_STATE_STOP = 0x00U,
|
||||
SYS_TIMER_STATE_RUN = 0x01U,
|
||||
SYS_TIMER_STATE_STOP = 0,
|
||||
SYS_TIMER_STATE_RUN = 1,
|
||||
};
|
||||
|
||||
struct sys_timer_information_t
|
||||
{
|
||||
s64 next_expiration_time; //system_time_t
|
||||
u64 period; //usecond_t
|
||||
u32 timer_state;
|
||||
u32 pad;
|
||||
be_t<s64> next_expiration_time;
|
||||
be_t<u64> period;
|
||||
be_t<u32> timer_state;
|
||||
be_t<u32> pad;
|
||||
};
|
||||
|
||||
struct timer
|
||||
// "timer_t" conflicts with some definition
|
||||
struct lv2_timer_t
|
||||
{
|
||||
sys_timer_information_t timer_information_t;
|
||||
std::weak_ptr<event_queue_t> port; // event queue
|
||||
u64 source; // event source
|
||||
u64 data1; // event arg 1
|
||||
u64 data2; // event arg 2
|
||||
|
||||
u64 start; // next expiration time
|
||||
u64 period; // period (oneshot if 0)
|
||||
|
||||
std::atomic<u32> state; // timer state
|
||||
std::condition_variable cv;
|
||||
|
||||
lv2_timer_t()
|
||||
: start(0)
|
||||
, period(0)
|
||||
, state(SYS_TIMER_STATE_STOP)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
s32 sys_timer_create(vm::ptr<u32> timer_id);
|
||||
s32 sys_timer_destroy(u32 timer_id);
|
||||
s32 sys_timer_get_information(u32 timer_id, vm::ptr<sys_timer_information_t> info);
|
||||
s32 sys_timer_start(u32 timer_id, s64 basetime, u64 period);
|
||||
s32 _sys_timer_start(u32 timer_id, u64 basetime, u64 period); // basetime type changed from s64
|
||||
s32 sys_timer_stop(u32 timer_id);
|
||||
s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data1, u64 data2);
|
||||
s32 sys_timer_disconnect_event_queue(u32 timer_id);
|
||||
|
@ -194,7 +194,6 @@
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_rsx.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_rwlock.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_semaphore.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_spinlock.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_spu.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_time.cpp" />
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_timer.cpp" />
|
||||
@ -457,7 +456,6 @@
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_rsx.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_rwlock.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_semaphore.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_spinlock.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_spu.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_time.h" />
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_timer.h" />
|
||||
|
@ -512,9 +512,6 @@
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_rsx.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_spinlock.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\SysCalls\lv2\sys_ppu_thread.cpp">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClCompile>
|
||||
@ -1282,9 +1279,6 @@
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_rsx.h">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_spinlock.h">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\SysCalls\lv2\sys_ppu_thread.h">
|
||||
<Filter>Emu\SysCalls\lv2</Filter>
|
||||
</ClInclude>
|
||||
|
Loading…
x
Reference in New Issue
Block a user