[Kernel] Implement ExAcquireReadWriteLockExclusive, ExReleaseReadWriteLock.
This commit is contained in:
parent
c98f6af1d8
commit
3baf668055
|
@ -373,8 +373,7 @@ void KeInitializeEvent(pointer_t<X_KEVENT> event_ptr, dword_t event_type,
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(KeInitializeEvent, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(KeInitializeEvent, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t KeSetEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
uint32_t keSetEvent(X_KEVENT* event_ptr, uint32_t increment, uint32_t wait) {
|
||||||
dword_t wait) {
|
|
||||||
auto ev = XObject::GetNativeObject<XEvent>(kernel_state(), event_ptr);
|
auto ev = XObject::GetNativeObject<XEvent>(kernel_state(), event_ptr);
|
||||||
if (!ev) {
|
if (!ev) {
|
||||||
assert_always();
|
assert_always();
|
||||||
|
@ -383,6 +382,11 @@ dword_result_t KeSetEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
||||||
|
|
||||||
return ev->Set(increment, !!wait);
|
return ev->Set(increment, !!wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t KeSetEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
||||||
|
dword_t wait) {
|
||||||
|
return keSetEvent(event_ptr, increment, wait);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency);
|
DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency);
|
||||||
|
|
||||||
dword_result_t KePulseEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
dword_result_t KePulseEvent(pointer_t<X_KEVENT> event_ptr, dword_t increment,
|
||||||
|
@ -508,9 +512,8 @@ void KeInitializeSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr, dword_t count,
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(KeInitializeSemaphore, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(KeInitializeSemaphore, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t KeReleaseSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr,
|
uint32_t keReleaseSemaphore(X_KSEMAPHORE* semaphore_ptr, uint32_t increment,
|
||||||
dword_t increment, dword_t adjustment,
|
uint32_t adjustment, uint32_t wait) {
|
||||||
dword_t wait) {
|
|
||||||
auto sem =
|
auto sem =
|
||||||
XObject::GetNativeObject<XSemaphore>(kernel_state(), semaphore_ptr);
|
XObject::GetNativeObject<XSemaphore>(kernel_state(), semaphore_ptr);
|
||||||
if (!sem) {
|
if (!sem) {
|
||||||
|
@ -523,6 +526,12 @@ dword_result_t KeReleaseSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr,
|
||||||
|
|
||||||
return sem->ReleaseSemaphore(adjustment);
|
return sem->ReleaseSemaphore(adjustment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t KeReleaseSemaphore(pointer_t<X_KSEMAPHORE> semaphore_ptr,
|
||||||
|
dword_t increment, dword_t adjustment,
|
||||||
|
dword_t wait) {
|
||||||
|
return keReleaseSemaphore(semaphore_ptr, increment, adjustment, wait);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(KeReleaseSemaphore, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(KeReleaseSemaphore, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t NtCreateSemaphore(lpdword_t handle_ptr,
|
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);
|
DECLARE_XBOXKRNL_EXPORT1(NtCancelTimer, kThreading, kImplemented);
|
||||||
|
|
||||||
dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason,
|
uint32_t keWaitForSingleObject(void* object_ptr, uint32_t wait_reason,
|
||||||
dword_t processor_mode, dword_t alertable,
|
uint32_t processor_mode, uint32_t alertable,
|
||||||
lpqword_t timeout_ptr) {
|
uint64_t* timeout) {
|
||||||
auto object = XObject::GetNativeObject<XObject>(kernel_state(), object_ptr);
|
auto object = XObject::GetNativeObject<XObject>(kernel_state(), object_ptr);
|
||||||
|
|
||||||
if (!object) {
|
if (!object) {
|
||||||
|
@ -730,12 +739,19 @@ dword_result_t KeWaitForSingleObject(lpvoid_t object_ptr, dword_t wait_reason,
|
||||||
return X_STATUS_ABANDONED_WAIT_0;
|
return X_STATUS_ABANDONED_WAIT_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t timeout = timeout_ptr ? static_cast<uint64_t>(*timeout_ptr) : 0u;
|
X_STATUS result =
|
||||||
X_STATUS result = object->Wait(wait_reason, processor_mode, alertable,
|
object->Wait(wait_reason, processor_mode, alertable, timeout);
|
||||||
timeout_ptr ? &timeout : nullptr);
|
|
||||||
|
|
||||||
return result;
|
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<uint64_t>(*timeout_ptr) : 0u;
|
||||||
|
return keWaitForSingleObject(object_ptr, wait_reason, processor_mode,
|
||||||
|
alertable, &timeout);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT3(KeWaitForSingleObject, kThreading, kImplemented,
|
DECLARE_XBOXKRNL_EXPORT3(KeWaitForSingleObject, kThreading, kImplemented,
|
||||||
kBlocking, kHighFrequency);
|
kBlocking, kHighFrequency);
|
||||||
|
|
||||||
|
@ -844,13 +860,12 @@ dword_result_t NtSignalAndWaitForSingleObjectEx(dword_t signal_handle,
|
||||||
DECLARE_XBOXKRNL_EXPORT3(NtSignalAndWaitForSingleObjectEx, kThreading,
|
DECLARE_XBOXKRNL_EXPORT3(NtSignalAndWaitForSingleObjectEx, kThreading,
|
||||||
kImplemented, kBlocking, kHighFrequency);
|
kImplemented, kBlocking, kHighFrequency);
|
||||||
|
|
||||||
dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) {
|
uint32_t keKfAcquireSpinLock(uint32_t* lock) {
|
||||||
// XELOGD(
|
// XELOGD(
|
||||||
// "KfAcquireSpinLock(%.8X)",
|
// "KfAcquireSpinLock(%.8X)",
|
||||||
// lock_ptr);
|
// lock_ptr);
|
||||||
|
|
||||||
// Lock.
|
// Lock.
|
||||||
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
|
||||||
while (!xe::atomic_cas(0, 1, lock)) {
|
while (!xe::atomic_cas(0, 1, lock)) {
|
||||||
// Spin!
|
// Spin!
|
||||||
// TODO(benvanik): error on deadlock?
|
// TODO(benvanik): error on deadlock?
|
||||||
|
@ -863,18 +878,27 @@ dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) {
|
||||||
|
|
||||||
return old_irql;
|
return old_irql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dword_result_t KfAcquireSpinLock(lpdword_t lock_ptr) {
|
||||||
|
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
||||||
|
return keKfAcquireSpinLock(lock);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT3(KfAcquireSpinLock, kThreading, kImplemented, kBlocking,
|
DECLARE_XBOXKRNL_EXPORT3(KfAcquireSpinLock, kThreading, kImplemented, kBlocking,
|
||||||
kHighFrequency);
|
kHighFrequency);
|
||||||
|
|
||||||
void KfReleaseSpinLock(lpdword_t lock_ptr, dword_t old_irql) {
|
void keKfReleaseSpinLock(uint32_t* lock, dword_t old_irql) {
|
||||||
// Restore IRQL.
|
// Restore IRQL.
|
||||||
XThread* thread = XThread::GetCurrentThread();
|
XThread* thread = XThread::GetCurrentThread();
|
||||||
thread->LowerIrql(old_irql);
|
thread->LowerIrql(old_irql);
|
||||||
|
|
||||||
// Unlock.
|
// Unlock.
|
||||||
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
|
||||||
xe::atomic_dec(lock);
|
xe::atomic_dec(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KfReleaseSpinLock(lpdword_t lock_ptr, dword_t old_irql) {
|
||||||
|
auto lock = reinterpret_cast<uint32_t*>(lock_ptr.host_address());
|
||||||
|
keKfReleaseSpinLock(lock, old_irql);
|
||||||
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT2(KfReleaseSpinLock, kThreading, kImplemented,
|
DECLARE_XBOXKRNL_EXPORT2(KfReleaseSpinLock, kThreading, kImplemented,
|
||||||
kHighFrequency);
|
kHighFrequency);
|
||||||
|
|
||||||
|
@ -1092,7 +1116,7 @@ struct X_ERWLOCK {
|
||||||
be<uint32_t> readers_entry_count; // 0xC
|
be<uint32_t> readers_entry_count; // 0xC
|
||||||
X_KEVENT writer_event; // 0x10
|
X_KEVENT writer_event; // 0x10
|
||||||
X_KSEMAPHORE reader_semaphore; // 0x20
|
X_KSEMAPHORE reader_semaphore; // 0x20
|
||||||
be<uint32_t> spin_lock; // 0x34
|
uint32_t spin_lock; // 0x34
|
||||||
};
|
};
|
||||||
|
|
||||||
void ExInitializeReadWriteLock(pointer_t<X_ERWLOCK> lock_ptr) {
|
void ExInitializeReadWriteLock(pointer_t<X_ERWLOCK> lock_ptr) {
|
||||||
|
@ -1105,6 +1129,51 @@ void ExInitializeReadWriteLock(pointer_t<X_ERWLOCK> lock_ptr) {
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(ExInitializeReadWriteLock, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(ExInitializeReadWriteLock, kThreading, kImplemented);
|
||||||
|
|
||||||
|
void ExAcquireReadWriteLockExclusive(pointer_t<X_ERWLOCK> 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<X_ERWLOCK> 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!
|
// NOTE: This function is very commonly inlined, and probably won't be called!
|
||||||
pointer_result_t InterlockedPushEntrySList(
|
pointer_result_t InterlockedPushEntrySList(
|
||||||
pointer_t<X_SLIST_HEADER> plist_ptr, pointer_t<X_SINGLE_LIST_ENTRY> entry) {
|
pointer_t<X_SLIST_HEADER> plist_ptr, pointer_t<X_SINGLE_LIST_ENTRY> entry) {
|
||||||
|
|
Loading…
Reference in New Issue