/*========================================================================== * * Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved. * * File: dnslist.cpp * Content: DirectPlay implementations of OS SLIST functions * * History: * Date By Reason * ==== == ====== * 10/30/2001 masonb Created * 11/07/2001 vanceo Added InterlockedPushListSList and made DNInitializeSListHead return value on Win64 * ***************************************************************************/ #include "dncmni.h" // // We build separate NT and 9x binaries, but even in the NT binary we can't be sure the system has the // SLIST functions available since they weren't on Win2k. The only place we can be sure that the SLIST // functions are available is on 64-bit NT platforms. // // Single thread builds don't need interlocked operations, so we don't include use the assembly here. // #ifndef DPNBUILD_ONLYONETHREAD #if defined(_X86_) __declspec(naked) DNSLIST_ENTRY* WINAPI DNInterlockedPopEntrySList(DNSLIST_HEADER * ListHead) { __asm { push ebx push ebp mov ebp, dword ptr [esp+0x0C] ; Place ListHead in ebp mov edx, dword ptr [ebp+0x04] ; Place Depth and Sequence into edx mov eax, dword ptr [ebp+0x00] ; Place Next into eax redo: or eax, eax ; Test eax against zero jz done ; If 0 return lea ecx, dword ptr [edx-01] ; ecx = ((Sequence << 16) | Depth) - 1, Depth goes down by one mov ebx, dword ptr [eax] ; Move Next->Next into ebx #ifdef DPNBUILD_ONLYONEPROCESSOR cmpxchg8b qword ptr [ebp] ; Exchange Next out in favor of Next->Next along with Depth and Sequence values #else // ! DPNBUILD_ONLYONEPROCESSOR lock cmpxchg8b qword ptr [ebp] ; Exchange Next out in favor of Next->Next along with Depth and Sequence values #endif // ! DPNBUILD_ONLYONEPROCESSOR jne redo done: pop ebp pop ebx #ifdef WINCE ret #else // !WINCE ret 4 #endif // WINCE } } __declspec(naked) DNSLIST_ENTRY* WINAPI DNInterlockedPushEntrySList(DNSLIST_HEADER * ListHead, DNSLIST_ENTRY * ListEntry) { __asm { push ebx push ebp mov ebp, dword ptr [esp+0x0C] ; Place ListHead in ebp mov ebx, dword ptr [esp+0x10] ; Place ListEntry in ebx mov edx, dword ptr [ebp+0x04] ; put ListHead Depth and Sequence into edx mov eax, dword ptr [ebp+0x00] ; put ListHead->Next into eax redo: mov dword ptr [ebx], eax ; set ListEntry->Next to ListHead->Next lea ecx, dword ptr [edx+0x00010001] ; add 1 to the Depth and Sequence #ifdef DPNBUILD_ONLYONEPROCESSOR cmpxchg8b qword ptr [ebp] ; atomically exchange ListHead with ListEntry if ListHead hasn't changed #else // ! DPNBUILD_ONLYONEPROCESSOR lock cmpxchg8b qword ptr [ebp] ; atomically exchange ListHead with ListEntry if ListHead hasn't changed #endif // ! DPNBUILD_ONLYONEPROCESSOR jne redo ; if the compare failed, try again pop ebp pop ebx #ifdef WINCE ret #else // !WINCE ret 8 #endif // WINCE } } __declspec(naked) DNSLIST_ENTRY* WINAPI DNInterlockedFlushSList(DNSLIST_HEADER * ListHead) { __asm { push ebx push ebp xor ebx, ebx ; Zero out ebx mov ebp, dword ptr [esp+0x0C] ; Place ListHead in ebp mov edx, dword ptr [ebp+0x04] ; Place Depth and Sequence into edx mov eax, dword ptr [ebp+0x00] ; Place Next into eax redo: or eax, eax ; Test eax against zero jz done ; If 0 return mov ecx, edx ; Place Depth and Sequence into ecx mov cx, bx ; Zero out Depth #ifdef DPNBUILD_ONLYONEPROCESSOR cmpxchg8b qword ptr [ebp] ; atomically exchange ListHead with ListEntry if ListHead hasn't changed #else // ! DPNBUILD_ONLYONEPROCESSOR lock cmpxchg8b qword ptr [ebp] ; atomically exchange ListHead with ListEntry if ListHead hasn't changed #endif // ! DPNBUILD_ONLYONEPROCESSOR jne redo ; if the compare failed, try again done: pop ebp pop ebx #ifdef WINCE ret #else // !WINCE ret 4 #endif // WINCE } } __declspec(naked) DNSLIST_ENTRY* WINAPI DNInterlockedPushListSList(DNSLIST_HEADER * ListHead, DNSLIST_ENTRY * List, DNSLIST_ENTRY * ListEnd, USHORT Count) { __asm { push ebx ; save nonvolatile registers push ebp ; mov ebp, dword ptr [esp+0x0C] ; save ListHead address mov ebx, dword ptr [esp+0x10] ; save List address mov edx,[ebp] + 4 ; get current sequence number mov eax,[ebp] + 0 ; get current next link Epshl10: mov ecx, [esp+0x14] ; Fetch address of ListEnd mov [ecx], eax ; Store new forward pointer in tail entry lea ecx, [edx+0x010000] ; increment sequence number add ecx, [esp+0x18] ; Add in new count to create correct depth #ifdef DPNBUILD_ONLYONEPROCESSOR cmpxchg8b qword ptr [ebp] ; compare and exchange #else // ! DPNBUILD_ONLYONEPROCESSOR lock cmpxchg8b qword ptr [ebp] ; compare and exchange #endif // ! DPNBUILD_ONLYONEPROCESSOR jnz short Epshl10 ; if z clear, exchange failed pop ebp ; restore nonvolatile registers pop ebx ; #ifdef WINCE ret #else // !WINCE ret 16 #endif // WINCE } } #elif defined(_ARM_) || defined(_AMD64_) || defined(_IA64_) // For now, ARM, IA64 and AMD64 do not have assembly versions of these, and it's important to // note that while our custom implementation *is* interlocked on those platforms, it is *not* atomic. // This means that the list won't get corrupted, but the items will not be transferred from the // source list to the target list in a single interlocked operation. Additionally, the items from the // source list will be added in reverse order. DNSLIST_ENTRY* WINAPI DNInterlockedPushListSList(DNSLIST_HEADER * ListHead, DNSLIST_ENTRY * List, DNSLIST_ENTRY * ListEnd, USHORT Count) { DNSLIST_ENTRY* pslEntryCurrent; DNSLIST_ENTRY* pslEntryNext; DNSLIST_ENTRY* pslEntryReturn = NULL; pslEntryCurrent = List; do { pslEntryNext = pslEntryCurrent->Next; DNSLIST_ENTRY* pslEntryTemp = DNInterlockedPushEntrySList(ListHead, pslEntryCurrent); if (pslEntryReturn == NULL) { pslEntryReturn = pslEntryTemp; } pslEntryCurrent = pslEntryNext; } while (pslEntryCurrent != NULL); return pslEntryReturn; } #else #error ("No other platform known") #endif // Platform #endif // ! DPNBUILD_ONLYONETHREAD