#include "Spin.h"

 

 

void

AcquireQueuedSpinLock(PSPIN_LOCK_QUEUE pSpinLockQueue)

{

  _asm

  {

    push eax

    push ebx

    push ecx

    push edx

 

    mov edx, pSpinLockQueue       ; pSpinLockQueue_edx

    mov ecx, dword ptr [edx+4]    ; pSpinLock_ecx

   

    mov eax, edx                  ; pSpinLockQueueOld_eax = pSpinLockQueueOld_edx

    xchg edx, dword ptr [ecx]     ; pSpinLockQueue_edx <--> *(pSpinLock_ecx)                                 

    cmp edx, 0                    ; if(pSpinLockQueue_edx != 0)

    jne label_owned               ;    goto label_owned

                                  ;

                                  ; else

    or ecx, 2                     ; pSpinLock_ecx |= 2

    mov dword ptr [eax+4], ecx    ; *(&pSpinLockQueue_eax->Lock) = pSpinLock_ecx

    jmp l_r                       ; return

 

label_owned:

    or ecx, 1                     ; pSpinLock_ecx |= 1

    mov dword ptr [eax+4], ecx    ; *(&pSpinLockQueue_eax->Lock) = pSpinLock_ecx

    mov dword ptr [edx], eax      ; pSpinLockQueue_edx->Next = &pSpinLockQueue_eax

label_test:                       ;

    test dword ptr [eax+4], 1     ; while( *(&pSpinLockQueue_eax->Lock) & 1 )

    je l_r                        ;

    pause                         ;

    jmp label_test                ;

 

l_r:

    pop edx

    pop ecx

    pop ebx

    pop eax

    jmp label_ret

  }

label_ret:

    return;

}

 

void

ReleaseQueuedSpinLock(PSPIN_LOCK_QUEUE pSpinLockQueue)

{

  _asm

  {

    push eax

    push ebx

    push ecx

    push edx

 

    mov eax, pSpinLockQueue                   ; PSPIN_LOCK_QUEUE pSpinLockQueue_eax          

    mov ebx, dword ptr [eax]                  ; PSPIN_LOCK_QUEUE ebx = pSpinLockQueueNext = pSpinLockQueue->Next

    mov ecx, dword ptr [eax+4]                ; PSPIN_LOCK ecx = pSpinLock = pSpinLockQueue->Lock

    test ebx, ebx                             ; 

    btr ecx, 1                                ; bit test and reset

                                              ; (ecx & 1) -> CF flag

                                              ; clear bit 1

                                              ; pSpinLock & 0xFFFFFFFE

                                              ; pSpinLock & ~0x1

    mov dword ptr [eax+4], ecx                ; pSpinLockQueue->Lock = pSpinLock

    jne l_1                                   ; if( pSpinLockQueueNext != 0 )

                                              ;   goto l_1

    push eax

    lock cmpxchg dword ptr [ecx], ebx         ; if( *(pSpinLock) == pSpinLockQueueNext )

                                              ;   *(pSpinLock) = pSpinLockQueueNext;

                                              ;    <ZF is set>

                                              ;    goto l_2;

                                              ; else

                                              ;   pSpinLockQueueNext = *(pSpinLock);

    pop eax                                   ;   return;

    jne l_2

    jmp la_ret

 

l_1:

    xor dword ptr [ebx+4], 3                  ; pSpinLockQueueNext->Lock ^= 3

    mov dword ptr [eax], 0                    ; pSpinLockQueue->Next = 0

    jmp la_ret                                ; return

 

l_2:

    mov ebx, dword ptr [eax]                 ; pSpinLockQueueNext = pSpinLockQueue->Next

    test ebx, eax                            ; if( pSpinLockQueueNext == NULL)

    jne l_1                                  ;    goto l_1;

   

    pause                                    ; else

    jmp l_2                                  ;    goto l_2;

 

la_ret:

    pop edx

    pop ecx

    pop ebx

    pop eax

    jmp l_ret

  }

l_ret:

  return;

}

 

 

 

 

VOID

AcquireSpinLock(IN PSPIN_LOCK SpinLock)

{

  _asm

  {

           ;lea ecx, [ebp+8]

           mov ecx, SpinLock

label1:

           ; test and set SpinLock, in multiprocessor environment

           ; lock insures that the processor has exclusive use of

           ; any shared memory while the signal is asserted

           lock bts dword ptr[ecx], 0   

          

           ; SpinLock owned, wait

           jc label2

 

           ; OK, acquired          

           ;ret

           jmp ll_ret;

 

label2:

           ; was cleared?

           test dword ptr[ecx], 1

          

           ; yes, SpinLock is free

           jz label1

 

           ; no

           pause

           jmp label2

  }

ll_ret:

  return;

}

 

 

 

VOID

ReleaseSpinLock(IN PSPIN_LOCK SpinLock)

{

  _asm

  {

           mov ecx, SpinLock

           lock and dword ptr[ecx], 0

  }

 

  return;

}