Passing a pointer from C to assembly

I want to use the assembly language implementation "_test_and_set lock" with the atomic swap assembly instruction in my C / C ++ program.

class LockImpl 
{
  public:
  static void lockResource(DWORD resourceLock )
  {
    __asm 
    {
      InUseLoop:  mov     eax, 0;0=In Use
                  xchg    eax, resourceLock
                  cmp     eax, 0
                  je      InUseLoop
    }

  }

  static void unLockResource(DWORD resourceLock )
  {
    __asm 
    {
      mov resourceLock , 1 
    }   

  }
};

This works, but there is an error.

The problem is that I want to pass DWORD * resourceLock instead of DWORD resourceLock.

So, the question is how to pass the pointer from C / C ++ to the assembly and return it.?

Thank you in advance.

Regards, -Jay.

PS this is done in order to avoid switching context between user space and kernel space.

+5
source share
7 answers

, ( ), DWORD.

Visual ++. : , , .

Windows, API ( InterlockedExchange).

: CAF, lock xchg , xchg BusLock.

, , xchg. BusLock . ( ), backoffs ( ) . , , .

class LockImpl
{
    // This is a simple SpinLock
    //  0 - in use / busy
    //  1 - free / available
public:
    static void lockResource(volatile DWORD &resourceLock )
    {
        __asm 
        {
            mov     ebx, resourceLock
InUseLoop:
            mov     eax, 0           ;0=In Use
            xchg    eax, [ebx]
            cmp     eax, 0
            je      InUseLoop
        }

    }

    static void lockResource_FasterVersion(DWORD &resourceLock )
    {
        __asm 
        {
            mov     ebx, resourceLock
InUseLoop:
            mov     eax, [ebx]    ;// Read without BusLock 
            cmp     eax, 0
            je      InUseLoop     ;// Retry Read if Busy

            mov     eax, 0
            xchg    eax, [ebx]    ;// XCHG with BusLock
            cmp     eax, 0
            je      InUseLoop     ;// Retry if Busy
        }
    }

    static void unLockResource(volatile DWORD &resourceLock)
    {
        __asm 
        {
            mov     ebx, resourceLock
            mov     [ebx], 1 
        }       

    }
};

// A little testing code here
volatile DWORD aaa=1;
void test()
{
 LockImpl::lockResource(aaa);
 LockImpl::unLockResource(aaa);
}
+1

Windows, . API , , , .

, , , , , , , , ​​ .

, .

+6

: volatile DWORD *resourceLock , resourceLock, :

mov ecx, dword ptr [resourceLock]
xchg eax, dword ptr [ecx]

mov ecx, dword ptr [resourceLock]
lock mov dword ptr [ecx], 1

, :

  • , Windows, Linux. , MSVC - gcc- Linux ( , Intel AT & T). gcc Windows; (. mingw gcc Windows).

  • , . , .

  • x86 - mfence .


, , , , , , , API- . pthreads Linux.

+4

-, MSVC ++.

, intrinsics , : MS x64.

, , .

+3

- :

volatile LONG resourceLock = 1;

if(InterlockedCompareExchange(&resourceLock, 0, 1) == 1) {
    // success!
    // do something, and then
    resourceLock = 1;
} else {
    // failed, try again later
}

. InterlockedCompareExchange.

+1

, , .

:

static void unLockResource(DWORD resourceLock )
{
  resourceLock = 0;
  return;
}

, . , resourceLock, . .

0

, , , ASM, .

Many other answers cast doubt on the wisdom of using ASM in general and mentioned that either internal calls or C OS calls should be used. The following also works and is a version of my ASM answer in C ++. It has an ASM snippet in it that should only be used if your platform does not support InterlockedExchange ().

class LockImpl
{
    // This is a simple SpinLock
    //  0 - in use / busy
    //  1 - free / available
public:
#if 1
    static DWORD MyInterlockedExchange(volatile DWORD *variable,DWORD newval)
    {
        // InterlockedExchange() uses LONG / He wants to use DWORD
        return((DWORD)InterlockedExchange(
            (volatile LONG *)variable,(LONG)newval));
    }
#else
    // You can use this if you don't have InterlockedExchange()
    // on your platform. Otherwise no ASM is required.
    static DWORD MyInterlockedExchange(volatile DWORD *variable,DWORD newval)
    {
        DWORD old;
        __asm 
        {
            mov     ebx, variable
            mov     eax, newval
            xchg    eax, [ebx]  ;// XCHG with BusLock
            mov     old, eax
        }
        return(old);
    }
#endif
    static void lockResource(volatile DWORD &resourceLock )
    {
        DWORD oldval;
        do 
        {
            while(0==resourceLock)
            {
                // Could have a yield, spin count, exponential 
                // backoff, OS CS fallback, etc. here
            }
            oldval=MyInterlockedExchange(&resourceLock,0);
        } while (0==oldval);
    }
    static void unLockResource(volatile DWORD &resourceLock)
    {
        // _ReadWriteBarrier() is a VC++ intrinsic that generates
        // no instructions / only prevents compiler reordering.
        // GCC uses __sync_synchronize() or __asm__ ( :::"memory" )
        _ReadWriteBarrier();
        resourceLock=1;
    }
};
-1
source

All Articles