+
+/* This variable must be used in kernel mode to prevent the system from
+ bugchecking on non-present kernel memory. If this variable is set to TRUE
+ an exception needs to be dispatched. */
+BOOLEAN RtlpExpectSListFault;
+
+PSLIST_ENTRY
+NTAPI
+RtlInterlockedPushEntrySList(
+ _Inout_ PSLIST_HEADER SListHead,
+ _Inout_ __drv_aliasesMem PSLIST_ENTRY SListEntry)
+{
+ SLIST_HEADER OldHeader, NewHeader;
+ ULONGLONG Compare;
+
+ /* Read the header */
+ OldHeader = *SListHead;
+
+ do
+ {
+ /* Link the list entry */
+ SListEntry->Next = OldHeader.Next.Next;
+
+ /* Create a new header */
+ NewHeader = OldHeader;
+ NewHeader.Next.Next = SListEntry;
+ NewHeader.Depth++;
+ NewHeader.Sequence++;
+
+ /* Try to exchange atomically */
+ Compare = OldHeader.Alignment;
+ OldHeader.Alignment = InterlockedCompareExchange64((PLONGLONG)&SListHead->Alignment,
+ NewHeader.Alignment,
+ Compare);
+ }
+ while (OldHeader.Alignment != Compare);
+
+ /* Return the old first entry */
+ return OldHeader.Next.Next;
+}
+
+PSLIST_ENTRY
+NTAPI
+RtlInterlockedPopEntrySList(
+ _Inout_ PSLIST_HEADER SListHead)
+{
+ SLIST_HEADER OldHeader, NewHeader;
+ ULONGLONG Compare;
+
+restart:
+
+ /* Read the header */
+ OldHeader = *SListHead;
+
+ do
+ {
+ /* Check for empty list */
+ if (OldHeader.Next.Next == NULL)
+ {
+ return NULL;
+ }
+
+ /* Create a new header */
+ NewHeader = OldHeader;
+
+ /* HACK to let the kernel know that we are doing slist-magic */
+ RtlpExpectSListFault = TRUE;
+
+ /* Wrapped in SEH, since OldHeader.Next.Next can already be freed */
+ _SEH2_TRY
+ {
+ NewHeader.Next = *OldHeader.Next.Next;
+ }
+ _SEH2_EXCEPT((SListHead->Next.Next != OldHeader.Next.Next) ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ /* We got an exception and the list head changed.
+ Restart the whole operation. */
+ RtlpExpectSListFault = FALSE;
+ goto restart;
+ }
+ _SEH2_END;
+
+ /* We are done */
+ RtlpExpectSListFault = FALSE;
+
+ /* Adjust depth */
+ NewHeader.Depth--;
+
+ /* Try to exchange atomically */
+ Compare = OldHeader.Alignment;
+ OldHeader.Alignment = InterlockedCompareExchange64((PLONGLONG)SListHead->Alignment,
+ NewHeader.Alignment,
+ Compare);
+ }
+ while (OldHeader.Alignment != Compare);
+
+ return OldHeader.Next.Next;