[PATCH 1/3] ntoskrnl.exe: Implement DPC-level queued spinlock functions.
Zebediah Figura
z.figura12 at gmail.com
Mon Jan 28 19:21:12 CST 2019
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 4 +-
dlls/ntoskrnl.exe/sync.c | 65 +++++++++++++++++++++++++++++
2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 33aa108cd7..3ee0e1f808 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -42,9 +42,9 @@
@ stdcall -norelay IofCallDriver(ptr ptr)
@ stdcall -norelay IofCompleteRequest(ptr long)
@ stdcall -norelay KeAcquireInStackQueuedSpinLock(ptr ptr)
-@ stub KeAcquireInStackQueuedSpinLockAtDpcLevel
+@ stdcall -norelay KeAcquireInStackQueuedSpinLockAtDpcLevel(ptr ptr)
@ stdcall -norelay KeReleaseInStackQueuedSpinLock(ptr)
-@ stub KeReleaseInStackQueuedSpinLockFromDpcLevel
+@ stdcall -norelay KeReleaseInStackQueuedSpinLockFromDpcLevel(ptr)
@ stub KeSetTimeUpdateNotifyRoutine
@ stub KefAcquireSpinLockAtDpcLevel
@ stub KefReleaseSpinLockFromDpcLevel
diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c
index 2a4685c5b3..4dc1fc3511 100644
--- a/dlls/ntoskrnl.exe/sync.c
+++ b/dlls/ntoskrnl.exe/sync.c
@@ -414,6 +414,71 @@ void WINAPI KeReleaseSpinLockFromDpcLevel( KSPIN_LOCK *lock )
InterlockedExchangePointer( (void **)lock, 0 );
}
+#define QUEUED_SPINLOCK_OWNED 0x2
+
+/***********************************************************************
+ * KeAcquireInStackQueuedSpinLockAtDpcLevel (NTOSKRNL.EXE.@)
+ */
+#ifdef DEFINE_FASTCALL2_ENTRYPOINT
+DEFINE_FASTCALL2_ENTRYPOINT( KeAcquireInStackQueuedSpinLockAtDpcLevel )
+void WINAPI DECLSPEC_HIDDEN __regs_KeAcquireInStackQueuedSpinLockAtDpcLevel( KSPIN_LOCK *lock, KLOCK_QUEUE_HANDLE *queue )
+#else
+void WINAPI KeAcquireInStackQueuedSpinLockAtDpcLevel( KSPIN_LOCK *lock, KLOCK_QUEUE_HANDLE *queue )
+#endif
+{
+ KSPIN_LOCK_QUEUE *tail;
+
+ TRACE("lock %p, queue %p.\n", lock, queue);
+
+ queue->LockQueue.Next = NULL;
+
+ if (!(tail = InterlockedExchangePointer( (void **)lock, &queue->LockQueue )))
+ queue->LockQueue.Lock = (KSPIN_LOCK *)((ULONG_PTR)lock | QUEUED_SPINLOCK_OWNED);
+ else
+ {
+ queue->LockQueue.Lock = lock;
+ InterlockedExchangePointer( (void **)&tail->Next, &queue->LockQueue );
+
+ while (!((ULONG_PTR)InterlockedCompareExchangePointer( (void **)&queue->LockQueue.Lock, 0, 0 )
+ & QUEUED_SPINLOCK_OWNED))
+ {
+ small_pause();
+ }
+ }
+}
+
+/***********************************************************************
+ * KeReleaseInStackQueuedSpinLockFromDpcLevel (NTOSKRNL.EXE.@)
+ */
+#ifdef DEFINE_FASTCALL1_ENTRYPOINT
+DEFINE_FASTCALL1_ENTRYPOINT( KeReleaseInStackQueuedSpinLockFromDpcLevel )
+void WINAPI DECLSPEC_HIDDEN __regs_KeReleaseInStackQueuedSpinLockFromDpcLevel( KLOCK_QUEUE_HANDLE *queue )
+#else
+void WINAPI KeReleaseInStackQueuedSpinLockFromDpcLevel( KLOCK_QUEUE_HANDLE *queue )
+#endif
+{
+ KSPIN_LOCK *lock = (KSPIN_LOCK *)((ULONG_PTR)queue->LockQueue.Lock & ~QUEUED_SPINLOCK_OWNED);
+ KSPIN_LOCK_QUEUE *next;
+
+ TRACE("lock %p, queue %p.\n", lock, queue);
+
+ queue->LockQueue.Lock = NULL;
+
+ if (!(next = queue->LockQueue.Next))
+ {
+ /* If we are truly the last in the queue, the lock will point to us. */
+ if (InterlockedCompareExchangePointer( (void **)lock, NULL, &queue->LockQueue ) == queue)
+ return;
+
+ /* Otherwise, someone just queued themselves, but hasn't yet set
+ * themselves as successor. Spin waiting for them to do so. */
+ while (!(next = queue->LockQueue.Next))
+ small_pause();
+ }
+
+ InterlockedExchangePointer( (void **)&next->Lock, (KSPIN_LOCK *)((ULONG_PTR)lock | QUEUED_SPINLOCK_OWNED) );
+}
+
#ifndef __i386__
/***********************************************************************
* KeReleaseSpinLock (NTOSKRNL.EXE.@)
--
2.20.1
More information about the wine-devel
mailing list