From 3baf6680550ee30fbafa9c343475e9814d187ec7 Mon Sep 17 00:00:00 2001 From: gibbed Date: Sat, 24 Nov 2018 19:04:42 -0600 Subject: [PATCH] [Kernel] Implement ExAcquireReadWriteLockExclusive, ExReleaseReadWriteLock. --- .../kernel/xboxkrnl/xboxkrnl_threading.cc | 101 +++++++++++++++--- 1 file changed, 85 insertions(+), 16 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index 3a9d852b3..3a26b2ff1 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -373,8 +373,7 @@ void KeInitializeEvent(pointer_t event_ptr, dword_t event_type, } DECLARE_XBOXKRNL_EXPORT1(KeInitializeEvent, kThreading, kImplemented); -dword_result_t KeSetEvent(pointer_t event_ptr, dword_t increment, - dword_t wait) { +uint32_t keSetEvent(X_KEVENT* event_ptr, uint32_t increment, uint32_t wait) { auto ev = XObject::GetNativeObject(kernel_state(), event_ptr); if (!ev) { assert_always(); @@ -383,6 +382,11 @@ dword_result_t KeSetEvent(pointer_t event_ptr, dword_t increment, return ev->Set(increment, !!wait); } + +dword_result_t KeSetEvent(pointer_t event_ptr, dword_t increment, + dword_t wait) { + return keSetEvent(event_ptr, increment, wait); +} DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency); dword_result_t KePulseEvent(pointer_t event_ptr, dword_t increment, @@ -508,9 +512,8 @@ void KeInitializeSemaphore(pointer_t semaphore_ptr, dword_t count, } DECLARE_XBOXKRNL_EXPORT1(KeInitializeSemaphore, kThreading, kImplemented); -dword_result_t KeReleaseSemaphore(pointer_t semaphore_ptr, - dword_t increment, dword_t adjustment, - dword_t wait) { +uint32_t keReleaseSemaphore(X_KSEMAPHORE* semaphore_ptr, uint32_t increment, + uint32_t adjustment, uint32_t wait) { auto sem = XObject::GetNativeObject(kernel_state(), semaphore_ptr); if (!sem) { @@ -523,6 +526,12 @@ dword_result_t KeReleaseSemaphore(pointer_t semaphore_ptr, return sem->ReleaseSemaphore(adjustment); } + +dword_result_t KeReleaseSemaphore(pointer_t semaphore_ptr, + dword_t increment, dword_t adjustment, + dword_t wait) { + return keReleaseSemaphore(semaphore_ptr, increment, adjustment, wait); +} DECLARE_XBOXKRNL_EXPORT1(KeReleaseSemaphore, kThreading, kImplemented); dword_result_t NtCreateSemaphore(lpdword_t handle_ptr, @@ -719,9 +728,9 @@ dword_result_t NtCancelTimer(dword_t timer_handle, } DECLARE_XBOXKRNL_EXPORT1(NtCancelTimer, kThreading, kImplemented); -dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason, - dword_t processor_mode, dword_t alertable, - lpqword_t timeout_ptr) { +uint32_t keWaitForSingleObject(void* object_ptr, uint32_t wait_reason, + uint32_t processor_mode, uint32_t alertable, + uint64_t* timeout) { auto object = XObject::GetNativeObject(kernel_state(), object_ptr); if (!object) { @@ -730,12 +739,19 @@ dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason, return X_STATUS_ABANDONED_WAIT_0; } - uint64_t timeout = timeout_ptr ? static_cast(*timeout_ptr) : 0u; - X_STATUS result = object->Wait(wait_reason, processor_mode, alertable, - timeout_ptr ? &timeout : nullptr); + X_STATUS result = + object->Wait(wait_reason, processor_mode, alertable, timeout); return result; } + +dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason, + dword_t processor_mode, dword_t alertable, + lpqword_t timeout_ptr) { + uint64_t timeout = timeout_ptr ? static_cast(*timeout_ptr) : 0u; + return keWaitForSingleObject(object_ptr, wait_reason, processor_mode, + alertable, &timeout); +} DECLARE_XBOXKRNL_EXPORT3(KeWaitForSingleObject, kThreading, kImplemented, kBlocking, kHighFrequency); @@ -844,13 +860,12 @@ dword_result_t NtSignalAndWaitForSingleObjectEx(dword_t signal_handle, DECLARE_XBOXKRNL_EXPORT3(NtSignalAndWaitForSingleObjectEx, kThreading, kImplemented, kBlocking, kHighFrequency); -dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) { +uint32_t keKfAcquireSpinLock(uint32_t* lock) { // XELOGD( // "KfAcquireSpinLock(%.8X)", // lock_ptr); // Lock. - auto lock = reinterpret_cast(lock_ptr.host_address()); while (!xe::atomic_cas(0, 1, lock)) { // Spin! // TODO(benvanik): error on deadlock? @@ -863,18 +878,27 @@ dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) { return old_irql; } + +dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) { + auto lock = reinterpret_cast(lock_ptr.host_address()); + return keKfAcquireSpinLock(lock); +} DECLARE_XBOXKRNL_EXPORT3(KfAcquireSpinLock, kThreading, kImplemented, kBlocking, kHighFrequency); -void KfReleaseSpinLock(lpdword_t lock_ptr, dword_t old_irql) { +void keKfReleaseSpinLock(uint32_t* lock, dword_t old_irql) { // Restore IRQL. XThread* thread = XThread::GetCurrentThread(); thread->LowerIrql(old_irql); // Unlock. - auto lock = reinterpret_cast(lock_ptr.host_address()); xe::atomic_dec(lock); } + +void KfReleaseSpinLock(lpdword_t lock_ptr, dword_t old_irql) { + auto lock = reinterpret_cast(lock_ptr.host_address()); + keKfReleaseSpinLock(lock, old_irql); +} DECLARE_XBOXKRNL_EXPORT2(KfReleaseSpinLock, kThreading, kImplemented, kHighFrequency); @@ -1092,7 +1116,7 @@ struct X_ERWLOCK { be readers_entry_count; // 0xC X_KEVENT writer_event; // 0x10 X_KSEMAPHORE reader_semaphore; // 0x20 - be spin_lock; // 0x34 + uint32_t spin_lock; // 0x34 }; void ExInitializeReadWriteLock(pointer_t lock_ptr) { @@ -1105,6 +1129,51 @@ void ExInitializeReadWriteLock(pointer_t lock_ptr) { } DECLARE_XBOXKRNL_EXPORT1(ExInitializeReadWriteLock, kThreading, kImplemented); +void ExAcquireReadWriteLockExclusive(pointer_t lock_ptr) { + auto old_irql = keKfAcquireSpinLock(&lock_ptr->spin_lock); + lock_ptr->lock_count++; + keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql); + + if (!lock_ptr->lock_count) { + return; + } + + lock_ptr->writers_waiting_count++; + keWaitForSingleObject(&lock_ptr->writer_event, 0, 0, 0, nullptr); +} +DECLARE_XBOXKRNL_EXPORT4(ExAcquireReadWriteLockExclusive, kThreading, + kImplemented, kBlocking, kHighFrequency, kSketchy); + +void ExReleaseReadWriteLock(pointer_t lock_ptr) { + auto old_irql = keKfAcquireSpinLock(&lock_ptr->spin_lock); + lock_ptr->lock_count--; + + if (lock_ptr->lock_count < 0) { + keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql); + return; + } + + if (!lock_ptr->readers_entry_count) { + auto readers_waiting_count = lock_ptr->readers_waiting_count; + if (readers_waiting_count) { + lock_ptr->readers_waiting_count = 0; + lock_ptr->readers_entry_count = readers_waiting_count; + keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql); + keReleaseSemaphore(&lock_ptr->reader_semaphore, 1, readers_waiting_count, + 0); + return; + } + } + + auto count = lock_ptr->readers_entry_count--; + keKfReleaseSpinLock(&lock_ptr->spin_lock, old_irql); + if (!count) { + keSetEvent(&lock_ptr->writer_event, 1, 0); + } +} +DECLARE_XBOXKRNL_EXPORT2(ExReleaseReadWriteLock, kThreading, kImplemented, + kSketchy); + // NOTE: This function is very commonly inlined, and probably won't be called! pointer_result_t InterlockedPushEntrySList( pointer_t plist_ptr, pointer_t entry) {