- Rewrite Executive Interlocked Functions to actually work as supposed and also immensly increase their speed, most notably on non-SMP machines: * The functions now disable interrupts as they should. This is a core functionality of the ExInterlocked functions which we did not do. * The functions now preserve EFLAGS as they should. This is another core functionality and point of ExInterlocked functions, which we did not do. * Use KiAcquire/ReleaseSpinlock equivalents instead of going through HAL. Also make them macros which can be later used in other assembly files. * Write optimized versions for non-SMP machines. Namely, the spinlock macros are coded to be no-ops on UP machines, since they are not needed. * Write all functions in assembly, so we can cleanly optimize them and properly restore/save EFLAGS and use CLI. - Use the right interlocked macro in guarded mutex implementation. - Fix export of Exi386InterlockedExchangeUlong - Use documented EFLAGS definition instead of hard-coded value in some interlocked functions. Modified: trunk/reactos/include/ndk/asm.h Added: trunk/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S Modified: trunk/reactos/ntoskrnl/ex/i386/interlck_asm.S Deleted: trunk/reactos/ntoskrnl/ex/interlck.c Deleted: trunk/reactos/ntoskrnl/ex/list.c Deleted: trunk/reactos/ntoskrnl/ex/synch.c Modified: trunk/reactos/ntoskrnl/ke/gmutex.c Modified: trunk/reactos/ntoskrnl/ntoskrnl.def Modified: trunk/reactos/ntoskrnl/ntoskrnl.xml _____
Modified: trunk/reactos/include/ndk/asm.h --- trunk/reactos/include/ndk/asm.h 2005-12-30 23:50:05 UTC (rev 20473) +++ trunk/reactos/include/ndk/asm.h 2005-12-30 23:53:13 UTC (rev 20474) @@ -289,6 +289,9 @@
#define EFLAGS_ALIGN_CHECK 0x40000 #define EFLAGS_VIF 0x80000 #define EFLAGS_VIP 0x100000 +#define EFLAG_SIGN 0x8000 +#define EFLAG_ZERO 0x4000 +#define EFLAG_SELECT (EFLAG_SIGN | EFLAG_ZERO)
// // CR0 _____
Added: trunk/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S --- trunk/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S 2005-12-30 23:50:05 UTC (rev 20473) +++ trunk/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S 2005-12-30 23:53:13 UTC (rev 20474) @@ -0,0 +1,701 @@
+/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ex/i386/fastinterlck_asm.S + * PURPOSE: FASTCALL Interlocked Functions + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ******************************************************************/ +#include <ndk/asm.h> +.intel_syntax noprefix + +//#define CONFIG_SMP + +#ifdef CONFIG_SMP +#define LOCK lock +#define ACQUIRE_SPINLOCK(x, y) \ + lock bts dword ptr [x], 0; \ + jb y +#define RELEASE_SPINLOCK(x) mov byte ptr [x], 0 +#define SPIN_ON_LOCK(x, y) \ +1: \ + test dword ptr [x], 1; \ + jz y; \ + pause; \ + jmp 1b +#else +#define LOCK +#define ACQUIRE_SPINLOCK(x, y) +#define RELEASE_SPINLOCK(x) +#endif + +/* FUNCTIONS ****************************************************************/ + +/* + * NOTE: These functions must obey the following rules: + * - Acquire locks only on MP systems. + * - Be safe at HIGH_LEVEL (no paged access). + * - Preserve flags. + * - Disable interrups. + */ + +/*VOID + *FASTCALL + *ExInterlockedAddLargeStatistic(IN PLARGE_INTEGER Addend, + * IN ULONG Increment) + */ +.global @ExInterlockedAddLargeStatistic@8 +@ExInterlockedAddLargeStatistic@8: + +#ifdef CONFIG_SMP + /* Do the addition */ + lock add [ecx], edx + + /* Check for carry bit and return */ + jb 1f + ret + +1: + /* Add carry */ + lock adc dword ptr [ecx+4], 0 +#else + /* Do the addition and add the carry */ + add dword ptr [ecx], edx + adc dword ptr [ecx+4], 0 +#endif + /* Return */ + ret + +/*ULONG + *FASTCALL + *ExfInterlockedAddUlong(IN PULONG Addend, + * IN ULONG Increment, + * IN PKSPIN_LOCK Lock) + */ +.global @ExfInterlockedAddUlong@12 +@ExfInterlockedAddUlong@12: + + /* Save flags */ + pushfd + +#ifdef CONFIG_SMP + /* Get lock address */ + mov eax, [esp+8] +.start1: +#endif + /* Disable interrupts */ + cli + + /* Acquire lock */ + ACQUIRE_SPINLOCK(eax, .spin1) + + /* Do the add */ + mov eax, [ecx] + add [ecx], edx + +#ifdef CONFIG_SMP + /* Get spinlock address and release it */ + mov edx, [esp+8] + RELEASE_SPINLOCK(edx) +#endif + + /* Restore flags and return */ + popfd + ret 4 + +#ifdef CONFIG_SMP +.spin1: + /* Restore flags and spin */ + popfd + pushfd + SPIN_ON_LOCK(eax, .start1) +#endif + +/*PLIST_ENTRY + *FASTCALL + *ExfInterlockedInsertHeadList(IN PLIST_ENTRY ListHead, + * IN PLIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global @ExfInterlockedInsertHeadList@12 +@ExfInterlockedInsertHeadList@12: + +#ifdef CONFIG_SMP + /* Save lock address */ + push esi + mov esi, [esp+8] +#endif + + /* Save flags and disable interrupts */ + pushfd +.start2: + cli + + /* Acquire lock */ + ACQUIRE_SPINLOCK(esi, .spin2) + + /* Get list pointer */ + mov eax, [ecx] + + /* Do the insert */ + mov [edx], eax + mov [edx+4], ecx + mov [ecx], edx + mov [eax+4], edx + + /* Release lock and restore flags */ + RELEASE_SPINLOCK(esi) + popfd + +#ifdef CONFIG_SMP + pop esi +#endif + + /* Check if list was empty */ + xor eax, ecx + jz 2f + + /* Return list pointer */ + xor eax, ecx +2: + ret 4 + +#ifdef CONFIG_SMP +.spin2: + popfd + pushfd + SPIN_ON_LOCK(esi, .start2) +#endif + +/*PLIST_ENTRY + *NTAPI + *ExfInterlockedInsertTailList(IN PLIST_ENTRY ListHead, + * IN PLIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global @ExfInterlockedInsertTailList@12 +@ExfInterlockedInsertTailList@12: + +#ifdef CONFIG_SMP + /* Save lock address */ + push esi + mov esi, [esp+8] +#endif + + /* Save flags and disable interrupts */ + pushfd +.start3: + cli + + /* Acquire lock */ + ACQUIRE_SPINLOCK(esi, .spin3) + + /* Get list pointer */ + mov eax, [ecx+4] + + /* Do the insert */ + mov [edx], ecx + mov [edx+4], eax + mov [ecx+4], edx + mov [eax], edx + + /* Release lock and restore flags */ + RELEASE_SPINLOCK(esi) + popfd + +#ifdef CONFIG_SMP + pop esi +#endif + + /* Check if list was empty */ + xor eax, ecx + jz 2f + + /* Return list pointer */ + xor eax, ecx +2: + ret 4 + +#ifdef CONFIG_SMP +.spin3: + popfd + pushfd + SPIN_ON_LOCK(esi, .start3) +#endif + +/*PLIST_ENTRY + *FASTCALL + *ExfInterlockedRemoveHeadList(IN PLIST_ENTRY ListHead, + * IN PKSPIN_LOCK Lock) + */ +.global @ExfInterlockedRemoveHeadList@8 +@ExfInterlockedRemoveHeadList@8: + + /* Save flags and disable interrupts */ +.start4: + pushfd + cli + ACQUIRE_SPINLOCK(edx, .spin4) + + /* Get list pointer */ + mov eax, [ecx] + + /* Check if it's empty */ + cmp eax, ecx + je 2f + + /* Get the next entry and do the deletion*/ +#ifdef CONFIG_SMP + push ebx + mov ebx, [eax] + mov [ecx], ebx + mov [ebx+4], ecx +#else + mov edx, [eax] + mov [ecx], edx + mov [edx+4], ecx +#endif + + /* Release lock */ +#ifdef CONFIG_SMP + RELEASE_SPINLOCK(edx) + pop ebx +#endif + + /* Restore flags */ + popfd + + /* Return */ + ret + +2: + /* Release lock */ + RELEASE_SPINLOCK(edx) + + /* Restore flags */ + popfd + + /* Return empty list */ + xor eax, eax + ret + +#ifdef CONFIG_SMP +.spin4: + popfd + SPIN_ON_LOCK(edx, .start4) +#endif + +/*PSINGLE_LIST_ENTRY + *FASTCALL + *ExfInterlockedPopEntryList(IN PSINGLE_LIST_ENTRY ListHead, + * IN PKSPIN_LOCK Lock) + */ +.global @ExfInterlockedPopEntryList@8 +@ExfInterlockedPopEntryList@8: + + /* Save flags and disable interrupts */ +.start5: + pushfd + cli + ACQUIRE_SPINLOCK(edx, .spin5) + + /* Get list pointer */ + mov eax, [ecx] + + /* Check if it's empty */ + or eax, eax + je 3f + + /* Get next entry and do deletion */ +#ifdef CONFIG_SMP + push edx +#endif + mov edx, [eax] + mov [ecx], edx +#ifdef CONFIG_SMP + pop edx +#endif + +2: + /* Release lock */ + RELEASE_SPINLOCK(edx) + + /* Restore flags */ + popfd + + /* Return */ + ret + +3: + /* Return empty list */ + xor eax, eax + jmp 2b + +#ifdef CONFIG_SMP +.spin5: + popfd + SPIN_ON_LOCK(edx, .start5) +#endif + +/*PSINGLE_LIST_ENTRY + *NTAPI + *ExfInterlockedPushEntryList(IN PSINGLE_LIST_ENTRY ListHead, + * IN PSINGLE_LIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global @ExfInterlockedPushEntryList@12 +@ExfInterlockedPushEntryList@12: + + /* Save flags */ + pushfd + + /* Save lock pointer */ +#ifdef CONFIG_SMP + push edx + mov edx, [esp+12] +#endif + + /* Disable interrupts */ +.start6: + cli +#ifdef CONFIG_SMP + ACQUIRE_SPINLOCK(edx, .spin6) + pop edx +#endif + + /* Get list pointer */ + mov eax, [ecx] + + /* Do push */ + mov [edx], eax + mov [ecx], edx + + /* Release lock */ +#ifdef CONFIG_SMP + mov edx, [esp+8] + RELEASE_SPINLOCK(edx) +#endif + + /* Restore flags */ + popfd + + /* Return */ + ret 4 + +#ifdef CONFIG_SMP +.spin6: + pop edx + popfd + pushfd + push edx + mov edx, [esp+12] + SPIN_ON_LOCK(edx, .start6) +#endif + +/*PSINGLE_LIST_ENTRY + *NTAPI + *ExInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead, + * IN PKSPIN_LOCK Lock) + */ +.global @ExInterlockedPopEntrySList@8 +.global @InterlockedPopEntrySList@4 +@ExInterlockedPopEntrySList@8: +@InterlockedPopEntrySList@4: + + /* Save registers */ + push ebx + push ebp + + /* Pointer to list */ + mov ebp, ecx + + /* Get sequence number and link pointer */ + mov edx, [ebp+4] + mov eax, [ebp] + +1: + /* Check if the list is empty */ + or eax, eax + jz 2f + + /* Copy sequence number and adjust it */ + lea ecx, [edx-1] + + /* Get next pointer and do the exchange */ + mov ebx, [eax] + LOCK cmpxchg8b qword ptr [ebp] + jnz 1b + + /* Restore registers and return */ +2: + pop ebp + pop ebx + ret + +/*PSINGLE_LIST_ENTRY + *NTAPI + *ExInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead, + * IN PSINGLE_LIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global @ExInterlockedPushEntrySList@12 +@ExInterlockedPushEntrySList@12: + + /* So we can fall through below */ + pop [esp] + +.global @InterlockedPushEntrySList@8 +@InterlockedPushEntrySList@8: + + /* Save registers */ + push ebx + push ebp + + /* Pointer to list */ + mov ebp, ecx + mov ebx, edx + + /* Get sequence number and link pointer */ + mov edx, [ebp+4] + mov eax, [ebp] + +1: + /* Set link pointer */ + mov [ebx], eax + + /* Copy sequence number and adjust it */ + lea ecx, [edx+0x10001] + + /* Do the exchange */ + LOCK cmpxchg8b qword ptr [ebp] + jnz 1b + + /* Restore registers and return */ +2: + pop ebp + pop ebx + ret + +/*PSINGLE_LIST_ENTRY + *NTAPI + *ExInterlockedFlushSList(IN PSINGLE_LIST_ENTRY ListHead) + */ +.global @ExInterlockedFlushSList@4 +@ExInterlockedFlushSList@4: + + /* Save registers */ + push ebx + push ebp + + /* Clear ebx */ + xor ebx, ebx + + /* Pointer to list */ + mov ebp, ecx + + /* Get sequence number and link pointer */ + mov edx, [ebp+4] + mov eax, [ebp] + +1: + /* Check if the list is empty */ + or eax, eax + jz 2f + + /* Clear sequence and pointer */ + mov ecx, edx + mov cx, bx + + /* Do the exchange */ + LOCK cmpxchg8b qword ptr [ebp] + jnz 1b + + /* Restore registers and return */ +2: + pop ebp + pop ebx + ret + +/*INTERLOCKED_RESULT + *FASTCALL + *Exfi386InterlockedIncrementLong(IN PLONG Addend) + */ +.global @Exfi386InterlockedIncrementLong@4 +@Exfi386InterlockedIncrementLong@4: + + /* Do the op */ + LOCK add dword ptr [ecx], 1 + + /* Return */ + lahf + and eax, EFLAG_SELECT + ret + +/*INTERLOCKED_RESULT + *FASTCALL + *Exfi386InterlockedDecrementLong(IN PLONG Addend) + */ +.global @Exfi386InterlockedDecrementLong@4 +@Exfi386InterlockedDecrementLong@4: + + /* Do the op */ + LOCK sub dword ptr [ecx], 1 + + /* Return */ + lahf + and eax, EFLAG_SELECT + ret + +/*ULONG + *FASTCALL + *Exfi386InterlockedExchangeUlong(IN PULONG Taget, + * IN ULONG Value) + */ +.global @Exfi386InterlockedExchangeUlong@8 +.global @InterlockedExchange@8 +@InterlockedExchange@8: +@Exfi386InterlockedExchangeUlong@8: + +#ifdef CONFIG_SMP + /* On MP, do the exchange */ + xchg [ecx], edx + mov eax, edx +#else + /* On UP, use cmpxchg */ + mov eax, [ecx] +1: + cmpxchg [ecx], edx + jnz 1b +#endif + + /* Return */ + ret + +/*ULONG + *FASTCALL + *InterlockedIncrement(IN PLONG Addend) + */ +.global @InterlockedIncrement@4 +@InterlockedIncrement@4: + + /* Do the op */ + mov eax, 1 + LOCK xadd dword ptr [ecx], eax + + /* Return */ + inc eax + ret + +/*ULONG + *FASTCALL + *InterlockedDecrement(IN PLONG Addend) + */ +.global @InterlockedDecrement@4 +@InterlockedDecrement@4: + + /* Do the op */ + mov eax, -1 + LOCK xadd dword ptr [ecx], eax + + /* Return */ + dec eax + ret + +/*PVOID + *FASTCALL + *InterlockedCompareExchange(IN OUT PVOID *Destination, + * IN PVOID Exchange, + * IN PVOID Comperand) + */ +.global @InterlockedCompareExchange@12 +@InterlockedCompareExchange@12: + + /* Get comperand */ + mov eax, [esp+4] + + /* Do the op */ + LOCK cmpxchg dword ptr [ecx], edx + + /* Return */ + ret + +/*PVOID + *FASTCALL + *ExfInterlockedCompareExchange64(IN PLONGLONG Destination, + * IN PLONGLONG Exchange, + * IN PLONGLONG Comperand) + */ +.global @ExfInterlockedCompareExchange64@12 +@ExfInterlockedCompareExchange64@12: + + /* Save registers */ + push ebp + push ebp + + /* Get desination pointer, exchange value and comperand value/address */ + mov ebp, ecx + mov ebx, [edx] + mov ecx, [edx+4] + mov edx, [esp+12] + mov eax, [edx] + mov edx, [edx+4] + + /* Do the op */ + LOCK cmpxchg8b qword ptr [ebp] + + /* Restore volatiles */ + pop ebp + pop ebx + + /* Return */ + ret 4 + +/*PVOID + *FASTCALL + *ExfInterlockedCompareExchange64(IN PLONGLONG Destination, + * IN PLONGLONG Exchange, + * IN PLONGLONG Comperand, + * IN PKSPIN_LOCK Lock) + */ +.global @ExInterlockedCompareExchange64@16 +@ExInterlockedCompareExchange64@16: + + /* Save registers */ + push ebp + push ebp + + /* Get desination pointer, exchange value and comperand value/address */ + mov ebp, ecx + mov ebx, [edx] + mov ecx, [edx+4] + mov edx, [esp+12] + mov eax, [edx] + mov edx, [edx+4] + + /* Do the op */ + LOCK cmpxchg8b qword ptr [ebp] + + /* Restore volatiles */ + pop ebp + pop ebx + + /* Return */ + ret 8 + +/*PVOID + *FASTCALL + *InterlockedExchangeAdd(IN OUT PLONG Addend, + * IN LONG Increment) + */ +.global @InterlockedExchangeAdd@8 +@InterlockedExchangeAdd@8: + + /* Do the op */ + LOCK xadd dword ptr [ecx], edx + + /* Return */ + mov eax, edx + ret + +/* EOF */ _____
Modified: trunk/reactos/ntoskrnl/ex/i386/interlck_asm.S --- trunk/reactos/ntoskrnl/ex/i386/interlck_asm.S 2005-12-30 23:50:05 UTC (rev 20473) +++ trunk/reactos/ntoskrnl/ex/i386/interlck_asm.S 2005-12-30 23:53:13 UTC (rev 20474) @@ -1,112 +1,583 @@
-/* $Id: interlck.c 15557 2005-05-28 07:26:38Z hbirr $ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ex/i386/interlck.c - * PURPOSE: No purpose listed. - * - * PROGRAMMERS: No programmer listed. + * FILE: ntoskrnl/ex/i386/interlck_asm.S + * PURPOSE: STDCALL Interlocked Functions + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ + +/* INCLUDES ******************************************************************/ +#include <ndk/asm.h> +.intel_syntax noprefix
+//#define CONFIG_SMP + #ifdef CONFIG_SMP #define LOCK lock +#define ACQUIRE_SPINLOCK(x, y) \ + lock bts dword ptr [x], 0; \ + jb y +#define RELEASE_SPINLOCK(x) mov byte ptr [x], 0 +#define SPIN_ON_LOCK(x, y) \ +1: \ + test dword ptr [x], 1; \ + jz y; \ + pause; \ + jmp 1b #else #define LOCK +#define ACQUIRE_SPINLOCK(x, y) +#define RELEASE_SPINLOCK(x) #endif
-.global @Exfi386InterlockedIncrementLong@4 -@Exfi386InterlockedIncrementLong@4: - LOCK - addl $1,(%ecx) - lahf - andl $0xC000, %eax - ret +/* FUNCTIONS ****************************************************************/
-.global @Exfi386InterlockedDecrementLong@4 -@Exfi386InterlockedDecrementLong@4: - LOCK - subl $1,(%ecx) - lahf - andl $0xC000, %eax - ret +/* + * NOTE: These functions must obey the following rules: + * - Acquire locks only on MP systems. + * - Be safe at HIGH_LEVEL (no paged access). + * - Preserve flags. + * - Disable interrups. + */
-.global @Exfi386InterlockedExchangeUlong@8 -@Exfi386InterlockedExchangeUlong@8: - LOCK - xchgl %edx,(%ecx) - movl %edx,%eax - ret +/*PLIST_ENTRY + *NTAPI + *ExInterlockedAddLargeInteger(IN PLIST_ENTRY ListHead, + * IN PLIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global _ExInterlockedAddLargeInteger@16 +_ExInterlockedAddLargeInteger@16:
+ /* Prepare stack frame */ + push ebp + mov ebp, esp + sub esp, 8 + + /* Save lock pointer */ +#ifdef CONFIG_SMP + mov eax, [ebp+20] +#endif + + /* Save flags and disable interrupts */ +.start1: + pushfd + cli + + /* Acquire lock */ + ACQUIRE_SPINLOCK(eax, .spin1) + + /* Do the calculation */ + mov eax, [ebp+8] + mov ecx, [eax] + mov edx, [eax+4] + + /* Save result */ + mov [ebp-8], ecx + mov [ebp-4], edx + + /* Add increment */ + add ecx, [ebp+12] + adc edx, [ebp+16] + + /* Save result */ + mov [eax], ecx + mov [eax+4], edx + + /* Release lock */ +#ifdef CONFIG_SMP + mov eax, [ebp+20] + RELEASE_SPINLOCK(eax) +#endif + + /* Restore flags */ + popfd + + /* Restore frame and return values */ + mov eax, [ebp-8] + mov edx, [ebp-4] + mov esp, ebp + pop ebp + ret 16 + +#ifdef CONFIG_SMP +.spin1: + popfd + SPIN_ON_LOCK(eax, .start1) +#endif + +/*PLIST_ENTRY + *NTAPI + *ExInterlockedInsertHeadList(IN PLIST_ENTRY ListHead, + * IN PLIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global _ExInterlockedAddUlong@12 +_ExInterlockedAddUlong@12: + + /* Save flags and disable interrupts */ + pushfd + + /* Get lock address */ +#ifdef CONFIG_SMP + mov edx, [ebp+16] +#endif +.start2: + cli + + /* Acquire lock */ + ACQUIRE_SPINLOCK(edx, .spin2) + + /* Do the calculation */ + mov ecx, [esp+8] +#ifdef CONFIG_SMP + mov eax, [ecx] + add eax, [esp+12] + + /* Save result */ + mov [ecx], eax +#else + + /* Do the calculation */ + mov edx, [ecx] + mov eax, edx + add edx, [esp+12] + + /* Save result */ + mov [ecx], edx +#endif + + /* Release lock, restore flags and return */ +#ifdef CONFIG_SMP + sub eax, [esp+12] + RELEASE_SPINLOCK(edx) +#endif + popfd + ret 12 + +#ifdef CONFIG_SMP +.spin2: + popfd + pushfd + SPIN_ON_LOCK(eax, .start2) +#endif + +/*PLIST_ENTRY + *NTAPI + *ExInterlockedInsertHeadList(IN PLIST_ENTRY ListHead, + * IN PLIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global _ExInterlockedInsertHeadList@12 +_ExInterlockedInsertHeadList@12: + + /* Save lock pointer */ +#ifdef CONFIG_SMP + mov edx, [esp+12] +#endif + + /* Save flags and disable interrupts */ +.start3: + pushfd + cli + ACQUIRE_SPINLOCK(edx, .spin3) + + /* Get list pointers */ + mov eax, [esp+8] + mov ecx, [esp+12] + mov edx, [eax] + + /* Do the insert */ + mov [ecx], edx + mov [ecx+4], eax + mov [eax], ecx + mov [edx+4], ecx + + /* Release lock */ +#ifdef CONFIG_SMP + mov ecx, [esp+16] + RELEASE_SPINLOCK(ecx) +#endif + + /* Restore flags */ + popfd + + /* check if the list was empty and return NULL */ + xor eax, edx + jz 2f + + /* Return pointer */ + mov eax, edx + +2: + ret 12 + +#ifdef CONFIG_SMP +.spin3: + popfd + SPIN_ON_LOCK(edx, .start3) +#endif + +/*PLIST_ENTRY + *NTAPI + *ExInterlockedInsertTailList(IN PLIST_ENTRY ListHead, + * IN PLIST_ENTRY ListEntry, + * IN PKSPIN_LOCK Lock) + */ +.global _ExInterlockedInsertTailList@12 +_ExInterlockedInsertTailList@12: + + /* Save lock pointer */ +#ifdef CONFIG_SMP + mov edx, [esp+12] +#endif + + /* Save flags and disable interrupts */ +.start4: + pushfd + cli + ACQUIRE_SPINLOCK(edx, .spin4) + + /* Get list pointers */ + mov eax, [esp+8] + mov ecx, [esp+12] + mov edx, [eax+4] + + /* Do the insert */ + mov [ecx], eax + mov [ecx+4], edx + mov [eax+4], ecx [truncated at 1000 lines; 1285 more skipped]