Skip to content

Commit

Permalink
The way to Unity, pt.2
Browse files Browse the repository at this point in the history
  • Loading branch information
polybiusproxy committed Dec 6, 2024
1 parent 6acfdd5 commit 4d30393
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 28 deletions.
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,10 @@ set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
src/core/libraries/gnmdriver/gnm_error.h
)

set(KERNEL_LIB src/core/libraries/kernel/threads/condvar.cpp
set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
src/core/libraries/kernel/sync/mutex.h
src/core/libraries/kernel/sync/semaphore.h
src/core/libraries/kernel/threads/condvar.cpp
src/core/libraries/kernel/threads/event_flag.cpp
src/core/libraries/kernel/threads/exception.cpp
src/core/libraries/kernel/threads/exception.h
Expand Down
2 changes: 0 additions & 2 deletions src/common/ntapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "ntapi.h"

NtClose_t NtClose = nullptr;
NtDelayExecution_t NtDelayExecution = nullptr;
NtSetInformationFile_t NtSetInformationFile = nullptr;
NtCreateThread_t NtCreateThread = nullptr;
NtTerminateThread_t NtTerminateThread = nullptr;
Expand All @@ -18,7 +17,6 @@ void Initialize() {

// http://stackoverflow.com/a/31411628/4725495
NtClose = (NtClose_t)GetProcAddress(nt_handle, "NtClose");
NtDelayExecution = (NtDelayExecution_t)GetProcAddress(nt_handle, "NtDelayExecution");
NtSetInformationFile =
(NtSetInformationFile_t)GetProcAddress(nt_handle, "NtSetInformationFile");
NtCreateThread = (NtCreateThread_t)GetProcAddress(nt_handle, "NtCreateThread");
Expand Down
9 changes: 3 additions & 6 deletions src/common/ntapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ typedef struct _TEB { /* win32/win64 */
#ifdef _WIN64
PVOID SystemReserved1[30]; /* /0190 */
#else
PVOID SystemReserved1[26]; /* 10c/ used for krnl386 private data in Wine */
PVOID SystemReserved1[26]; /* 10c/ */
#endif
char PlaceholderCompatibilityMode; /* 174/0280 */
BOOLEAN PlaceholderHydrationAlwaysExplicit; /* 175/0281 */
Expand All @@ -430,13 +430,13 @@ typedef struct _TEB { /* win32/win64 */
BYTE SpareBytes1[23]; /* 1b9/ */
ULONG TxFsContext; /* 1d0/ */
#endif
GDI_TEB_BATCH GdiTebBatch; /* 1d4/02f0 used for ntdll private data in Wine */
GDI_TEB_BATCH GdiTebBatch; /* 1d4/02f0 */
CLIENT_ID RealClientId; /* 6b4/07d8 */
HANDLE GdiCachedProcessHandle; /* 6bc/07e8 */
ULONG GdiClientPID; /* 6c0/07f0 */
ULONG GdiClientTID; /* 6c4/07f4 */
PVOID GdiThreadLocaleInfo; /* 6c8/07f8 */
ULONG_PTR Win32ClientInfo[62]; /* 6cc/0800 used for user32 private data in Wine */
ULONG_PTR Win32ClientInfo[62]; /* 6cc/0800 */
PVOID glDispatchTable[233]; /* 7c4/09f0 */
PVOID glReserved1[29]; /* b68/1138 */
PVOID glReserved2; /* bdc/1220 */
Expand Down Expand Up @@ -511,8 +511,6 @@ static_assert(offsetof(TEB, DeallocationStack) ==

typedef u64(__stdcall* NtClose_t)(HANDLE Handle);

typedef u64(__stdcall* NtDelayExecution_t)(BOOL Alertable, PLARGE_INTEGER DelayInterval);

typedef u64(__stdcall* NtSetInformationFile_t)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation, ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass);
Expand All @@ -525,7 +523,6 @@ typedef u64(__stdcall* NtCreateThread_t)(PHANDLE ThreadHandle, ACCESS_MASK Desir
typedef u64(__stdcall* NtTerminateThread_t)(HANDLE ThreadHandle, u64 ExitStatus);

extern NtClose_t NtClose;
extern NtDelayExecution_t NtDelayExecution;
extern NtSetInformationFile_t NtSetInformationFile;
extern NtCreateThread_t NtCreateThread;
extern NtTerminateThread_t NtTerminateThread;
Expand Down
14 changes: 13 additions & 1 deletion src/common/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ void SetCurrentThreadName(const char* name) {
SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
}

void SetThreadName(void* thread, const char* name) {
SetThreadDescription(thread, UTF8ToUTF16W(name).data());
}

#else // !MSVC_VER, so must be POSIX threads

// MinGW with the POSIX threading model does not support pthread_setname_np
Expand All @@ -170,11 +174,19 @@ void SetCurrentThreadName(const char* name) {
pthread_setname_np(pthread_self(), name);
#endif
}

void SetThreadName(void* thread, const char* name) {
// TODO
}
#endif

#if defined(_WIN32)
void SetCurrentThreadName(const char*) {
// Do Nothing on MingW
// Do Nothing on MinGW
}

void SetThreadName(void* thread, const char* name) {
// Do Nothing on MinGW
}
#endif

Expand Down
2 changes: 2 additions & 0 deletions src/common/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority);

void SetCurrentThreadName(const char* name);

void SetThreadName(void* thread, const char* name);

class AccurateTimer {
std::chrono::nanoseconds target_interval{};
std::chrono::nanoseconds total_wait{};
Expand Down
1 change: 1 addition & 0 deletions src/core/devices/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ s64 Logger::write(const void* buf, size_t nbytes) {
log(static_cast<const char*>(buf), nbytes);
return nbytes;
}

size_t Logger::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
for (int i = 0; i < iovcnt; i++) {
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
Expand Down
52 changes: 52 additions & 0 deletions src/core/libraries/kernel/sync/mutex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "mutex.h"

#include "common/assert.h"

namespace Libraries::Kernel {

TimedMutex::TimedMutex() {
#ifdef _WIN64
mtx = CreateMutex(nullptr, false, nullptr);
ASSERT(mtx);
#endif
}

TimedMutex::~TimedMutex() {
#ifdef _WIN64
CloseHandle(mtx);
#endif
}

void TimedMutex::lock() {
#ifdef _WIN64
for (;;) {
u64 res = WaitForSingleObjectEx(mtx, INFINITE, true);
if (res == WAIT_OBJECT_0) {
return;
}
}
#else
mtx.lock();
#endif
}

bool TimedMutex::try_lock() {
#ifdef _WIN64
return WaitForSingleObjectEx(mtx, 0, true) == WAIT_OBJECT_0;
#else
return mtx.try_lock();
#endif
}

void TimedMutex::unlock() {
#ifdef _WIN64
ReleaseMutex(mtx);
#else
mtx.unlock();
#endif
}

} // namespace Libraries::Kernel
80 changes: 80 additions & 0 deletions src/core/libraries/kernel/sync/mutex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <chrono>

#include "common/types.h"

#ifdef _WIN64
#include <windows.h>
#else
#include <mutex>
#endif

namespace Libraries::Kernel {

class TimedMutex {
public:
TimedMutex();
~TimedMutex();

void lock();
bool try_lock();

void unlock();

template <class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& rel_time) {
#ifdef _WIN64
constexpr auto zero = std::chrono::duration<Rep, Period>::zero();
const auto now = std::chrono::steady_clock::now();

decltype(now + rel_time) abs_time = now;
if (rel_time > zero) {
constexpr auto forever = (std::chrono::steady_clock::time_point::max)();
if (abs_time < forever - rel_time) {
abs_time += rel_time;
} else {
abs_time = forever;
}
}

return try_lock_until(abs_time);
#else
return mtx.try_lock_for(rel_time);
#endif
}

template <class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time) {
#ifdef _WIN64
for (;;) {
const auto now = Clock::now();
if (abs_time <= now) {
return false;
}

const auto rel_ms = std::chrono::ceil<std::chrono::milliseconds>(abs_time - now);
u64 res = WaitForSingleObjectEx(mtx, static_cast<u64>(rel_ms.count()), true);
if (res == WAIT_OBJECT_0) {
return true;
} else if (res == WAIT_TIMEOUT) {
return false;
}
}
#else
return mtx.try_lock_until(abs_time);
#endif
}

private:
#ifdef _WIN64
HANDLE mtx;
#else
std::timed_mutex mtx;
#endif
};

} // namespace Libraries::Kernel
Empty file.
117 changes: 117 additions & 0 deletions src/core/libraries/kernel/sync/semaphore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <atomic>
#include <chrono>

#include "common/assert.h"
#include "common/types.h"

#ifdef _WIN64
#include <windows.h>
#else
#include <semaphore>
#endif

namespace Libraries::Kernel {

template <s64 max>
class Semaphore {
public:
Semaphore(s32 initialCount)
#ifndef _WIN64
: sem{initialCount}
#endif
{
#ifdef _WIN64
sem = CreateSemaphore(nullptr, initialCount, max, nullptr);
ASSERT(sem);
#endif
}

~Semaphore() {
#ifdef _WIN64
CloseHandle(sem);
#endif
}

void release() {
#ifdef _WIN64
ReleaseSemaphore(sem, 1, nullptr);
#else
sem.release();
#endif
}

void acquire() {
#ifdef _WIN64
for (;;) {
u64 res = WaitForSingleObjectEx(sem, INFINITE, true);
if (res == WAIT_OBJECT_0) {
return;
}
}
#else
sem.acquire();
#endif
}

bool try_acquire() {
#ifdef _WIN64
return WaitForSingleObjectEx(sem, 0, true) == WAIT_OBJECT_0;
#else
return sem.try_acquire();
#endif
}

template <class Rep, class Period>
bool try_acquire_for(const std::chrono::duration<Rep, Period>& rel_time) {
#ifdef _WIN64
const auto rel_time_ms = std::chrono::ceil<std::chrono::milliseconds>(rel_time);
const u64 timeout_ms = static_cast<u64>(rel_time_ms.count());

if (timeout_ms == 0) {
return false;
}

return WaitForSingleObjectEx(sem, timeout_ms, true) == WAIT_OBJECT_0;
#else
return sem.try_acquire_for(rel_time);
#endif
}

template <class Clock, class Duration>
bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& abs_time) {
#ifdef _WIN64
const auto now = Clock::now();
if (now >= abs_time) {
return false;
}

const auto rel_time = std::chrono::ceil<std::chrono::milliseconds>(abs_time - now);
const u64 timeout_ms = static_cast<u64>(rel_time.count());
if (timeout_ms == 0) {
return false;
}

u64 res = WaitForSingleObjectEx(sem, static_cast<u64>(timeout_ms), true);
return res == WAIT_OBJECT_0;
#else
return sem.try_acquire_until(abs_time);
#endif
}

private:
#ifdef _WIN64
HANDLE sem;
#else
std::counting_semaphore<max> sem;
#endif
};

using BinarySemaphore = Semaphore<1>;
using CountingSemaphore = Semaphore<0x7FFFFFFF /*ORBIS_KERNEL_SEM_VALUE_MAX*/>;

} // namespace Libraries::Kernel
4 changes: 2 additions & 2 deletions src/core/libraries/kernel/threads/condvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ int PthreadCond::Signal() {
PthreadMutex* mp = td->mutex_obj;
has_user_waiters = SleepqRemove(sq, td);

std::binary_semaphore* waddr = nullptr;
BinarySemaphore* waddr = nullptr;
if (mp->m_owner == curthread) {
if (curthread->nwaiter_defer >= Pthread::MaxDeferWaiters) {
curthread->WakeAll();
Expand All @@ -211,7 +211,7 @@ int PthreadCond::Signal() {

struct BroadcastArg {
Pthread* curthread;
std::binary_semaphore* waddrs[Pthread::MaxDeferWaiters];
BinarySemaphore* waddrs[Pthread::MaxDeferWaiters];
int count;
};

Expand Down
1 change: 0 additions & 1 deletion src/core/libraries/kernel/threads/event_flag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ class EventFlagInternal {
}

m_bits |= bits;

m_cond_var.notify_all();
}

Expand Down
Loading

0 comments on commit 4d30393

Please sign in to comment.