InterlockedIncrement..., does anyone have one???

Bare metal programming in PureBasic, for experienced users
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

InterlockedIncrement..., does anyone have one???

Post by RichAlgeni »

Do any of the good people contributing to the Assembly forum have an InterlockedIncrement process they could share?

Certainly, it's easy to write with a mutex, but I believe the overhead involved is substantially more than what is needed to just lock a variable, increment it, assign it to another variable, unlock it, and have it go on its merry way.

Thanks!
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: InterlockedIncrement..., does anyone have one???

Post by idle »

you can do it via macros

assumes that you only use global vars

Code: Select all

nableASM 

Macro _gLockINC(var) 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    lock inc dword [v_#var]
  CompilerElse
    lock inc qword [v_#var]
  CompilerEndIf   
EndMacro

Macro _gLockDEC(var) 
 CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    lock dec dword [v_#var]
  CompilerElse
    lock dec qword [v_#var]
  CompilerEndIf   
EndMacro

Macro _gLockADD(var,vadd)
 CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    mov eax, vadd
    lock add dword [v_#var],eax
 CompilerElse
    mov rax,vadd
    lock add qword [v_#var],rax
 CompilerEndIf   
EndMacro

Macro _gLockSUB(var,vsub) 
 CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
   mov eax, vsub
   lock sub dword [v_#var],eax
 CompilerElse
   mov rax, vsub
   lock sub qword [v_#var],rax
 CompilerEndIf 
EndMacro

Macro _gLockXCHG(var,var1) 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    mov eax,var1
    xchg dword [v_#var],eax
    mov var1,eax
  CompilerElse 
    mov rax,var1
    xchg qword [v_#var],rax
    mov var1,rax
  CompilerEndIf 
EndMacro

Macro _gLockINCXCHG(var,var1) 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    lock inc dword [v_#var1]
    lock xchg eax, [v_#var1]
    mov var , eax
  CompilerElse 
    lock inc qword [v_#var1]
    lock xchg rax, [v_#var1]
    mov var , rax
  CompilerEndIf 
EndMacro

Macro SpinLock(var) 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
  !mov ecx,1
  !Spinlock#MacroExpandedCount:
  !xor eax,eax
  lock cmpxchg dword [v_#var],ecx 
  !jnz Spinlock#MacroExpandedCount
 CompilerElse 
  !mov rcx,1
  !Spinlock#MacroExpandedCount:
  !xor rax,rax
  lock cmpxchg qword [v_#var],rcx 
  !jnz Spinlock#MacroExpandedCount
 CompilerEndIf  
EndMacro 

Macro SpinUnlock(var)
  _gLockDEC(var) 
EndMacro   


Global a=0,b=2
_gLockINC(a)
Debug a 
_gLockADD(a,b)
Debug a 
_gLockSUB(a,b)
Debug a 
_gLockDEC(a)
Debug a 

Global lock

Procedure tSpin(v) 
   
  For a = 0 To 10 
     SpinLock(lock)
     Debug "thread " + Str(v)
     SpinUnlock(lock)  
     Delay(1)
  Next   
      
EndProcedure   

t1 = CreateThread(@tspin(),1)
t2 = CreateThread(@tspin(),2)

Delay(1000)


Global nextSocketToUse=1  

Procedure attach() 
  Protected useThisNumber 
  _gLockINCXCHG(useThisNumber,nextSocketToUse)
  Debug useThisNumber ;=2 
   
EndProcedure   

attach()

Windows 11, Manjaro, Raspberry Pi OS
Image
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: InterlockedIncrement..., does anyone have one???

Post by davido »

@idle,

This error occurred on my MacBook Pro:
OSX wrote:purebasic.asm:835: error: undefined symbol `@b’ (first use)
purebasic.asm:835: error: (for each undefined symbol is reported only once.)
DE AA EB
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: InterlockedIncrement..., does anyone have one???

Post by idle »

davido wrote:@idle,

This error occurred on my MacBook Pro:
OSX wrote:purebasic.asm:835: error: undefined symbol `@b’ (first use)
purebasic.asm:835: error: (for each undefined symbol is reported only once.)
Thanks, I did mention the spinlock won't work on osx as it's using fasm's anonymous labels

I've edited the post and updated it, so should work now :)
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: InterlockedIncrement..., does anyone have one???

Post by RichAlgeni »

Thank you Idle for your time and efforts with this. It is truly appreciated!

I'm not sure I explained myself clearly enough as to what I need this for. I have an IIS Extension dll process running inside, of course, Internet Information Server, the web server from Microsoft. When the Extension initially loads, the AttachProcess procedure creates a fixed number of client socket connections to a separate server process. The number of connections is limited to the numberConnections variable. As the sockets connect, they are set to an initial available state, by setting availabConnections(useThisNumber) = 0. As browsers connect to the IIS server, and request data, a thread will check for an available socket. If the socket is available, it will grab the socket, and request data. Basically, it looks like this:

Code: Select all

; AttachProcess...
    Global useConnectLock.i  = CreateMutex()

; thread procedure...
; now lock the mutex, and get the next socket to use

    Repeat
        attemptCount    + 1

        LockMutex(useConnectLock)
        nextSocketToUse + 1
        useThisNumber   = nextSocketToUse
        UnlockMutex(useConnectLock)

        useThisNumber   = Mod(useThisNumber, numberConnections)

        If  availabConnections(useThisNumber) = 0
            socketToUse = mappingConnections(useThisNumber)
            If socketToUse > 0
                availabConnections(useThisNumber) = 1
                Break
            EndIf
        Else
            Delay(10 * attemptCount)
        EndIf
    ForEver

; send request to server, read in returned data

; now release the socket we used

    availabConnections(useThisNumber) = 0
From what I have read, using a mutex for this is like using a sledgehammer to kill a mosquito. There must be a lightweight way to lock access to a global integer or address, increment it, assign the value to local variable, then release the lock. My concern is that the local variable must be assigned, before the lock is released, to keep from crashing by two threads attempting to use a single socket.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: InterlockedIncrement..., does anyone have one???

Post by davido »

@idle,

The following errors now occur:
OSX wrote:purebasic.asm:124: error: invalid size for operand 1
purebasic.asm:181: error: invalid size for operand 1
purebasic.asm:931: error: invalid size for operand 1
This is purely for your information should you find it useful.
It is not a request to you to put it right.
DE AA EB
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: InterlockedIncrement..., does anyone have one???

Post by idle »

RichAlgeni wrote:Thank you Idle for your time and efforts with this. It is truly appreciated!

I'm not sure I explained myself clearly enough as to what I need this for. I have an IIS Extension dll process running inside, of course, Internet Information Server, the web server from Microsoft. When the Extension initially loads, the AttachProcess procedure creates a fixed number of client socket connections to a separate server process. The number of connections is limited to the numberConnections variable. As the sockets connect, they are set to an initial available state, by setting availabConnections(useThisNumber) = 0. As browsers connect to the IIS server, and request data, a thread will check for an available socket. If the socket is available, it will grab the socket, and request data. Basically, it looks like this:

Code: Select all

; AttachProcess...
    Global useConnectLock.i  = CreateMutex()

; thread procedure...
; now lock the mutex, and get the next socket to use

    Repeat
        attemptCount    + 1

        LockMutex(useConnectLock)
        nextSocketToUse + 1
        useThisNumber   = nextSocketToUse
        UnlockMutex(useConnectLock)

        useThisNumber   = Mod(useThisNumber, numberConnections)

        If  availabConnections(useThisNumber) = 0
            socketToUse = mappingConnections(useThisNumber)
            If socketToUse > 0
                availabConnections(useThisNumber) = 1
                Break
            EndIf
        Else
            Delay(10 * attemptCount)
        EndIf
    ForEver

; send request to server, read in returned data

; now release the socket we used

    availabConnections(useThisNumber) = 0
From what I have read, using a mutex for this is like using a sledgehammer to kill a mosquito. There must be a lightweight way to lock access to a global integer or address, increment it, assign the value to local variable, then release the lock. My concern is that the local variable must be assigned, before the lock is released, to keep from crashing by two threads attempting to use a single socket.

I don't know what the best option is
PB mutex is a critical section so it's probably not that bad.
but if you have a thread pool maybe semaphores are a better option to use so the thread can sleep until a connection request is made
as for a spinlock it might be ok in this case but It depends on how fast it can be resolved as it'll just eat cycles

but if you just need an atomic inc and set maybe this will work

Code: Select all

Macro _gLockINCXCHG(var,var1) 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    lock inc dword [v_#var1]
    lock xchg eax, [v_#var1]
    mov var , eax
  CompilerElse 
    lock inc qword [v_#var1]
    lock xchg rax, [v_#var1]
    mov var , rax
  CompilerEndIf 
EndMacro

Global nextSocketToUse=1  

Procedure attach() 
  Protected useThisNumber 

  _gLockINCXCHG(useThisNumber,nextSocketToUse)
  Debug useThisNumber  
   
EndProcedure   

attach()



@davido

it'll be wanting me to specify the sizes as either a qword or dword
maybe wilbert can take a look since I don't have osx
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: InterlockedIncrement..., does anyone have one???

Post by RichAlgeni »

I'll try it out, thanks Idle!
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: InterlockedIncrement..., does anyone have one???

Post by davido »

@idle,

idle wrote: @davido

it'll be wanting me to specify the sizes as either a qword or dword
maybe wilbert can take a look since I don't have osx
Seems to work OK, now.
Debugger wrote:1
3
1
0
thread 1
thread 2
thread 2
thread 1
thread 1
thread 2
thread 1
thread 2
thread 1
thread 2
thread 1
thread 2
thread 2
thread 1
thread 2
thread 1
2
Excellent. Thank you.
DE AA EB
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: InterlockedIncrement..., does anyone have one???

Post by idle »

thanks for the debugging help.
Windows 11, Manjaro, Raspberry Pi OS
Image
Post Reply