It is currently Mon Sep 23, 2019 7:05 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Thu Mar 15, 2018 12:05 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Wed Sep 22, 2010 1:50 am
Posts: 796
Location: Bradenton, FL
For integers in Windows?

The intrinsic does not seem to work. The SDK kernel32.lib does not seem to export the function, and I cannot find it in kernel32.dll.

There is some assembler listed in other posts, but it does not appear to work.


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Thu Mar 15, 2018 7:07 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
Code:
Procedure.q AtomicIncrement64(*Var64)
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_Var64]
    !mov rax, 1
    !lock xadd [rdx], rax
    !add rax, 1
  CompilerElse
    ; store non-volatile registers
    !mov [esp - 4], ebx
    !mov [esp - 8], edi
    ; load 64 bit value into edx:eax
    !mov edi, [p.p_Var64]
    !mov eax, [edi]
    !mov edx, [edi + 4]
    ; 64 bit atomic increment
    !.l:
    !mov ebx, 1
    !mov ecx, 0
    !add ebx, eax
    !adc ecx, edx
    !lock cmpxchg8b [edi]
    !jnz .l
    !mov eax, ebx
    !mov edx, ecx
    ; restore non-volatile registers
    !mov edi, [esp - 8]
    !mov ebx, [esp - 4]
  CompilerEndIf 
  ProcedureReturn 
EndProcedure

Procedure.q AtomicDecrement64(*Var64)
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_Var64]
    !mov rax, -1
    !lock xadd [rdx], rax
    !add rax, -1
  CompilerElse
    ; store non-volatile registers
    !mov [esp - 4], ebx
    !mov [esp - 8], edi
    ; load 64 bit value into edx:eax
    !mov edi, [p.p_Var64]
    !mov eax, [edi]
    !mov edx, [edi + 4]
    ; 64 bit atomic decrement
    !.l:
    !mov ebx, -1
    !mov ecx, -1
    !add ebx, eax
    !adc ecx, edx
    !lock cmpxchg8b [edi]
    !jnz .l
    !mov eax, ebx
    !mov edx, ecx   
    ; restore non-volatile registers
    !mov edi, [esp - 8]
    !mov ebx, [esp - 4]
  CompilerEndIf
  ProcedureReturn   
EndProcedure


A.q = 5
For i = 1 To 10
  Debug AtomicIncrement64(@A)
Next


It's also possible to use one Add procedure and use -1 for decrement.
Code:
Procedure.q AtomicAdd64(*Var64, Value64.q)
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_Var64]
    !mov rax, [p.v_Value64]
    !lock xadd [rdx], rax
    !add rax, [p.v_Value64]
  CompilerElse
    ; store non-volatile registers
    !mov [esp - 4], ebx
    !mov [esp - 8], edi
    ; load 64 bit value into edx:eax
    !mov edi, [p.p_Var64]
    !mov eax, [edi]
    !mov edx, [edi + 4]
    ; 64 bit atomic add
    !.l:
    !mov ebx, [p.v_Value64]
    !mov ecx, [p.v_Value64 + 4]
    !add ebx, eax
    !adc ecx, edx
    !lock cmpxchg8b [edi]
    !jnz .l
    !mov eax, ebx
    !mov edx, ecx
    ; restore non-volatile registers
    !mov edi, [esp - 8]
    !mov ebx, [esp - 4]
  CompilerEndIf 
  ProcedureReturn 
EndProcedure


A.q = 5

For i = 1 To 10
  Debug AtomicAdd64(@A, -1)
Next

For i = 1 To 6
  Debug AtomicAdd64(@A, 1)
Next

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Thu Mar 15, 2018 11:20 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Wed Sep 22, 2010 1:50 am
Posts: 796
Location: Bradenton, FL
Always appreciate your assistance Wilbert!

You're work is most instructive and helpful!


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Fri Mar 16, 2018 2:20 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Wed Sep 22, 2010 1:50 am
Posts: 796
Location: Bradenton, FL
I'm sorry I have to ask this, but...

Could you write an Assembler process to force the variable (quad integer pointer) back to 0?

I am getting error C0000264, STATUS_RESOURCE_NOT_OWNED arbitrarily in this code:
Code:
    While Not TryAcquireSRWLockExclusive(*updateLock)
        Delay(20)
    Wend
   
    AddElement(updateMessageLog())
    updateMessageLog()\messageLogKey = *messageData\messageKey
    updateMessageLog()\messageLogTyp = #snpp
    updateMessageLog()\messageResult = result

    ReleaseSRWLockExclusive(*updateLock)

Which seems impossible as the pointer used in the lock is not accessed in any other part of the program.

My thought is that I could use it as my own lock process.


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Fri Mar 16, 2018 6:43 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
RichAlgeni wrote:
Could you write an Assembler process to force the variable (quad integer pointer) back to 0?

I'm not exactly sure if I understand what you want. :?
Do you want a procedure to set the value like the code below or do you need something else ?
Code:
Procedure.q AtomicSetValue64(*Var64, Value64.q)
  ; the return value is the old value of *Var64
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_Var64]
    !mov rax, [p.v_Value64]
    !lock xchg [rdx], rax
  CompilerElse
    ; store non-volatile registers
    !mov [esp - 4], ebx
    !mov [esp - 8], edi
    ; load current value into edx:eax
    !mov edi, [p.p_Var64]
    !mov eax, [edi]
    !mov edx, [edi + 4]
    ; 64 bit atomic exchange
    !.l:
    !mov ebx, [p.v_Value64]
    !mov ecx, [p.v_Value64 + 4]
    !lock cmpxchg8b [edi]
    !jnz .l
    ; restore non-volatile registers
    !mov edi, [esp - 8]
    !mov ebx, [esp - 4]
  CompilerEndIf 
  ProcedureReturn 
EndProcedure

Procedure.q AtomicAdd64(*Var64, Value64.q)
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_Var64]
    !mov rax, [p.v_Value64]
    !lock xadd [rdx], rax
    !add rax, [p.v_Value64]
  CompilerElse
    ; store non-volatile registers
    !mov [esp - 4], ebx
    !mov [esp - 8], edi
    ; load current value into edx:eax
    !mov edi, [p.p_Var64]
    !mov eax, [edi]
    !mov edx, [edi + 4]
    ; 64 bit atomic add
    !.l:
    !mov ebx, [p.v_Value64]
    !mov ecx, [p.v_Value64 + 4]
    !add ebx, eax
    !adc ecx, edx
    !lock cmpxchg8b [edi]
    !jnz .l
    !mov eax, ebx
    !mov edx, ecx
    ; restore non-volatile registers
    !mov edi, [esp - 8]
    !mov ebx, [esp - 4]
  CompilerEndIf 
  ProcedureReturn 
EndProcedure


A.q = 5

For i = 1 To 10
  Debug AtomicAdd64(@A, 1)
Next

AtomicSetValue64(@A, 0)

For i = 1 To 10
  Debug AtomicAdd64(@A, -1)
Next

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Fri Mar 16, 2018 3:23 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Wed Sep 22, 2010 1:50 am
Posts: 796
Location: Bradenton, FL
Let me explain my thought process, and see if it makes sense to you.

1. The initial value of the Global integer will be 0.

2. Threads created will use AtomicIncrement64() to increment the value, when work is required.

3. Only when the integer returned to a thread is 1 will the thread be considered to be granted access to a locked resource.

4. Any other value returned (2, 3, etc.) and the thread will wait a period of time, then proceed to step 2.

5. The thread that does the work will use AtomicSetValue64() to set the value of the integer back to 0 when the work is complete, indicating that the resource is unlocked and available to another thread to process work needed on the resource.

6. The thread that did the work will proceed to step 2.


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Fri Mar 16, 2018 4:45 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
Sounds logical :)

You could also consider a toggle bit; not sure what would work best.
Code:
Procedure AtomicBitSet(*Mem, BitIdx.a = 0)
  ; the return value is the old bit value
  !movzx eax, byte [p.v_BitIdx]
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_Mem]
    !lock bts [rdx], eax
  CompilerElse
    !mov edx, [p.p_Mem]
    !lock bts [edx], eax
  CompilerEndIf
  !setc al
  ProcedureReturn 
EndProcedure

Procedure AtomicBitReset(*Mem, BitIdx.a = 0)
  ; the return value is the old bit value
  !movzx eax, byte [p.v_BitIdx]
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov rdx, [p.p_Mem]
    !lock btr [rdx], eax
  CompilerElse
    !mov edx, [p.p_Mem]
    !lock btr [edx], eax
  CompilerEndIf 
  !setc al
  ProcedureReturn 
EndProcedure



Global Flags = 0

Procedure MyThreadProc(Value)
  Repeat
    While AtomicBitSet(@Flags)
      Delay(20)
    Wend
    For i = 1 To 10
      Debug "Thread "+Str(Value)+" : "+Str(i)
      Delay(100) 
    Next
    AtomicBitReset(@Flags)
    Delay(100) 
  ForEver 
EndProcedure

CreateThread(@MyThreadProc(), 1)
CreateThread(@MyThreadProc(), 2)

Delay(10000)

AtomicBitSet sets bit 0 of the Flags value always to 1.
If it previously was 0, you can proceed. If not, you can consider it locked.
At the end of the procedure you can reset the bit to indicate it is no longer locked.

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Fri Mar 16, 2018 10:50 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Wed Sep 22, 2010 1:50 am
Posts: 796
Location: Bradenton, FL
Ok, so we check the returned value, to see if the bit was changed by AtomicBitSet().

If it was, we are free to proceed with the locked resource.

Brilliant! Thanks so much Wilbert!!!


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Sat Mar 17, 2018 6:54 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 3443
Location: Netherlands
RichAlgeni wrote:
Ok, so we check the returned value, to see if the bit was changed by AtomicBitSet().

If it was, we are free to proceed with the locked resource.

Yes, if it previously was 0, it has changed from 0 to 1 so a lock was acquired. :)
If you need to protect different resources, you can use a different bit index value.
With a quad value, you can protect 64 different resources.
The procedure itself supports a bit index from 0 - 255. If you want to use bit index 64 - 255, you can do it like this.
Code:
Global *LockBits = AllocateMemory(32); allocate 256 bits

AtomicBitSet(*LockBits, 200)
AtomicBitReset(*LockBits, 200)

_________________
macOS 10.14 Mojave, PB 5.62 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Does anyone have a 64 bit atomic increment decrement?
PostPosted: Sat Mar 17, 2018 8:49 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Wed Sep 22, 2010 1:50 am
Posts: 796
Location: Bradenton, FL
Brilliant! Thanks so much Wil!!!

I have 9 Windows Services programs that I am going to replace Slim Reader Writer with this.

I had high hopes for SRW. I don't understand how it could randomly fail like that.

So be it!

Thanks again!

Rich


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye