sceKernelCreateEventFlag , sceKernelWaitEventFlag implementation
This commit is contained in:
parent
ae9a779369
commit
8bae44a90b
|
@ -102,6 +102,7 @@ set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
|
||||||
|
|
||||||
set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag.cpp
|
set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag.cpp
|
||||||
src/core/libraries/kernel/event_flag/event_flag.h
|
src/core/libraries/kernel/event_flag/event_flag.h
|
||||||
|
src/core/libraries/kernel/event_flag/event_flag_codes.h
|
||||||
src/core/libraries/kernel/event_flag/event_flag_obj.cpp
|
src/core/libraries/kernel/event_flag/event_flag_obj.cpp
|
||||||
src/core/libraries/kernel/event_flag/event_flag_obj.h
|
src/core/libraries/kernel/event_flag/event_flag_obj.h
|
||||||
src/core/libraries/kernel/cpu_management.cpp
|
src/core/libraries/kernel/cpu_management.cpp
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <common/assert.h>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
@ -10,7 +11,43 @@ namespace Libraries::Kernel {
|
||||||
int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char* pName, u32 attr,
|
int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char* pName, u32 attr,
|
||||||
u64 initPattern,
|
u64 initPattern,
|
||||||
const OrbisKernelEventFlagOptParam* pOptParam) {
|
const OrbisKernelEventFlagOptParam* pOptParam) {
|
||||||
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
LOG_INFO(Kernel_Event, "called name = {} attr = {:#x} initPattern = {:#x}", pName, attr,
|
||||||
|
initPattern);
|
||||||
|
if (ef == nullptr || pName == nullptr) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
if (pOptParam || !pName ||
|
||||||
|
attr > (ORBIS_KERNEL_EVF_ATTR_MULTI | ORBIS_KERNEL_EVF_ATTR_TH_PRIO)) {
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(pName) >= 32) {
|
||||||
|
return ORBIS_KERNEL_ERROR_ENAMETOOLONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool single = true;
|
||||||
|
bool fifo = true;
|
||||||
|
|
||||||
|
switch (attr) {
|
||||||
|
case 0x10:
|
||||||
|
case 0x11:
|
||||||
|
single = true;
|
||||||
|
fifo = true;
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
case 0x21:
|
||||||
|
single = false;
|
||||||
|
fifo = true;
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
single = false;
|
||||||
|
fifo = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
*ef = new EventFlagInternal(std::string(pName), single, fifo, initPattern);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) {
|
int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) {
|
||||||
|
@ -45,8 +82,46 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
||||||
}
|
}
|
||||||
int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
|
int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode,
|
||||||
u64* pResultPat, OrbisKernelUseconds* pTimeout) {
|
u64* pResultPat, OrbisKernelUseconds* pTimeout) {
|
||||||
LOG_ERROR(Kernel_Event, "(STUBBED) called");
|
LOG_INFO(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode);
|
||||||
return ORBIS_OK;
|
if (ef == nullptr) {
|
||||||
|
return ORBIS_KERNEL_ERROR_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitPattern == 0) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wait = 0;
|
||||||
|
int clear = 0;
|
||||||
|
switch (waitMode & 0xf) {
|
||||||
|
case 0x01:
|
||||||
|
wait = ORBIS_KERNEL_EVF_WAITMODE_AND;
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
wait = ORBIS_KERNEL_EVF_WAITMODE_OR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (waitMode & 0xf0) {
|
||||||
|
case 0x10:
|
||||||
|
clear = ORBIS_KERNEL_EVF_WAITMODE_CLEAR_ALL;
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
clear = ORBIS_KERNEL_EVF_WAITMODE_CLEAR_PAT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
clear = 0; // not clear
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = ef->Wait(bitPattern, wait, clear, pResultPat, pTimeout);
|
||||||
|
|
||||||
|
if (result != ORBIS_OK) {
|
||||||
|
LOG_ERROR(Kernel_Event, "returned {}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym) {
|
void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("PZku4ZrXJqg", "libkernel", 1, "libkernel", 1, 1, sceKernelCancelEventFlag);
|
LIB_FUNCTION("PZku4ZrXJqg", "libkernel", 1, "libkernel", 1, 1, sceKernelCancelEventFlag);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "event_flag_codes.h"
|
||||||
#include "event_flag_obj.h"
|
#include "event_flag_obj.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
|
@ -12,16 +13,6 @@ class SymbolsResolver;
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_FIFO = 0x01;
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_PRIO = 0x02;
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_ATTR_SINGLE = 0x10;
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_ATTR_MULTI = 0x20;
|
|
||||||
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_WAITMODE_AND = 0x01;
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_WAITMODE_OR = 0x02;
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_ALL = 0x10;
|
|
||||||
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_PAT = 0x20;
|
|
||||||
|
|
||||||
using OrbisKernelUseconds = u32;
|
using OrbisKernelUseconds = u32;
|
||||||
using OrbisKernelEventFlag = EventFlagInternal*;
|
using OrbisKernelEventFlag = EventFlagInternal*;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_FIFO = 0x01;
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_ATTR_TH_PRIO = 0x02;
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_ATTR_SINGLE = 0x10;
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_ATTR_MULTI = 0x20;
|
||||||
|
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_WAITMODE_AND = 0x01;
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_WAITMODE_OR = 0x02;
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_ALL = 0x10;
|
||||||
|
constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_PAT = 0x20;
|
|
@ -1,6 +1,72 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <core/libraries/error_codes.h>
|
||||||
#include "event_flag_obj.h"
|
#include "event_flag_obj.h"
|
||||||
|
|
||||||
namespace Libraries::Kernel {}
|
namespace Libraries::Kernel {
|
||||||
|
int EventFlagInternal::Wait(u64 bits, int wait_mode, int clear_mode, u64* result, u32* ptr_micros) {
|
||||||
|
std::unique_lock lock{m_mutex};
|
||||||
|
|
||||||
|
uint32_t micros = 0;
|
||||||
|
bool infinitely = true;
|
||||||
|
if (ptr_micros != nullptr) {
|
||||||
|
micros = *ptr_micros;
|
||||||
|
infinitely = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_single_thread && m_waiting_threads > 0) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const start = std::chrono::system_clock::now();
|
||||||
|
m_waiting_threads++;
|
||||||
|
auto waitFunc = [this, wait_mode, bits] {
|
||||||
|
return (m_status == Status::Canceled || m_status == Status::Deleted ||
|
||||||
|
(wait_mode == ORBIS_KERNEL_EVF_WAITMODE_AND && (m_bits & bits) == bits) ||
|
||||||
|
(wait_mode == ORBIS_KERNEL_EVF_WAITMODE_OR && (m_bits & bits) != 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (infinitely) {
|
||||||
|
m_cond_var.wait(lock, waitFunc);
|
||||||
|
} else {
|
||||||
|
if (!m_cond_var.wait_for(lock, std::chrono::microseconds(micros), waitFunc)) {
|
||||||
|
if (result != nullptr) {
|
||||||
|
*result = m_bits;
|
||||||
|
}
|
||||||
|
*ptr_micros = 0;
|
||||||
|
--m_waiting_threads;
|
||||||
|
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--m_waiting_threads;
|
||||||
|
if (result != nullptr) {
|
||||||
|
*result = m_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||||
|
std::chrono::system_clock::now() - start)
|
||||||
|
.count();
|
||||||
|
if (result != nullptr) {
|
||||||
|
*result = m_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr_micros != nullptr) {
|
||||||
|
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_status == Status::Canceled) {
|
||||||
|
return ORBIS_KERNEL_ERROR_ECANCELED;
|
||||||
|
} else if (m_status == Status::Deleted) {
|
||||||
|
return ORBIS_KERNEL_ERROR_EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear_mode == ORBIS_KERNEL_EVF_WAITMODE_CLEAR_ALL) {
|
||||||
|
m_bits = 0;
|
||||||
|
} else if (clear_mode == ORBIS_KERNEL_EVF_WAITMODE_CLEAR_PAT) {
|
||||||
|
m_bits &= ~bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
} // namespace Libraries::Kernel
|
|
@ -2,7 +2,30 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "event_flag_codes.h"
|
||||||
|
|
||||||
namespace Libraries::Kernel {
|
namespace Libraries::Kernel {
|
||||||
class EventFlagInternal {};
|
|
||||||
|
class EventFlagInternal {
|
||||||
|
public:
|
||||||
|
EventFlagInternal(const std::string& name, bool single, bool fifo, uint64_t bits)
|
||||||
|
: m_name(name), m_single_thread(single), m_fifo(fifo), m_bits(bits){};
|
||||||
|
|
||||||
|
int Wait(u64 bits, int wait_mode, int clear_mode, u64* result, u32* ptr_micros);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Status { Set, Canceled, Deleted };
|
||||||
|
|
||||||
|
std::mutex m_mutex;
|
||||||
|
std::condition_variable m_cond_var;
|
||||||
|
Status m_status = Status::Set;
|
||||||
|
int m_waiting_threads = 0;
|
||||||
|
std::string m_name;
|
||||||
|
bool m_single_thread = false;
|
||||||
|
bool m_fifo = false;
|
||||||
|
u64 m_bits = 0;
|
||||||
|
};
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
Loading…
Reference in New Issue