PureBasic
https://www.purebasic.fr/french/

Besoin d'aide pour InterlockedIncrement64 en ASM
https://www.purebasic.fr/french/viewtopic.php?f=12&t=15746
Page 1 sur 1

Auteur:  nico [ Sam 09/Jan/2016 21:07 ]
Sujet du message:  Besoin d'aide pour InterlockedIncrement64 en ASM

Bonjour, pour les besoins des objects COM, il faut utiliser une fonction qui est InterlockedIncrement, cette fonction n'existe pas pour les OS x64, il faut la créer en assembleur, voici comment elle est définie, est t'il possible de le convertir pour purebasic?

Code:
#if !defined(_M_X64)
// When compiling for windows 32bit, the 8byte interlocked operations are not provided by microsoft
// (because they need at least i586 so its not generic enough.. ... )
forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp){
   _asm{
      lea esi,_cmp;
      lea edi,exch;
       
      mov eax,[esi];
      mov edx,4[esi];
      mov ebx,[edi];
      mov ecx,4[edi];
      mov esi,dest;
      
      lock CMPXCHG8B [esi];               
   }
}


forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend){
   __int64 old;
   do{
      old = *addend;
   }while(InterlockedCompareExchange64(addend, (old+1), old) != old);

   return (old + 1);
}



forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend){
   __int64 old;

   do{
      old = *addend;
   }while(InterlockedCompareExchange64(addend, (old-1), old) != old);

   return (old - 1);
}

Auteur:  nico [ Sam 09/Jan/2016 23:29 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

j'ai fait ça, est-ce que c'est bon?

Code:
Procedure.i InterlockedCompareExchange64(*deste, exch.i, COMPare.i)
      !LEA r8, [p.v_COMPare]
      !LEA r9,[p.v_exch]
       
      !MOV rax,[r8]
      !MOV rcx,[r9]
      !MOV rdx,[p.p_deste]
      
      !LOCK CMPXCHG8B [rdx]      
EndProcedure
   
Procedure.i InterlockedIncrement64(*addend.integer)
  Protected old.integer
 
   Repeat
      old\i = *addend\i
   Until (InterlockedCompareExchange64(*addend, (old\i+1), old\i) <> old\i)

   ProcedureReturn (old\i + 1)
EndProcedure

Procedure.i InterlockedDecrement64(*addend.integer)
  Protected old.integer
 
   Repeat
      old\i = *addend\i
   Until (InterlockedCompareExchange64(*addend, (old\i+1), old\i) <> old\i)

   ProcedureReturn (old\i - 1)
EndProcedure

Auteur:  Ar-S [ Dim 10/Jan/2016 0:37 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Je voudrai bien t'aider mais c'est au delà de mes compétences..

Auteur:  nico [ Dim 10/Jan/2016 11:27 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

L'exemple est pour du 32 bit, il n'y a pas beaucoup d'instruction, je ne pense pas que ce soit compliqué à faire d'une façon ou d'une autre pour du 64 bit.

Auteur:  Anonyme2 [ Dim 10/Jan/2016 11:54 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Salut Nico,

je ne suis pas un gourou en C.

Ce que je pense avoir compris :

#if !defined(_M_X64)

veut dire que les procedures seront utilisées si le processeur _M_X64 n'est pas défini (< i586 ?)

Pour ce que je comprend, je pense qu'il faut laisser les registres 32 bits en asm.
Utiliser un compiler if qui génère le code à la compilation ou alors détecter le processeur et générer 2 procedures car les procedures en 64 bits existent.

InterlockedCompareExchange64
https://msdn.microsoft.com/fr-fr/librar ... 85%29.aspx

InterlockedIncrement64
https://msdn.microsoft.com/fr-fr/librar ... 85%29.aspx

Les utiliser en API si _M_X64 existe sinon le code asm (les 3 procedures)

CMPXCHG8B compare le contenu de EAX/EDX avec la mémoire 64 bit pointée par esi et echange le contenu si égal
si c'est égal, le drapeau ZF passe à 1, ECX/EBX est chargé et mis dans la mémoire pointée par esi.
Le drapeau ZF passe à 0 et le contenu de la mémoire 64 bit est chargé dans EDX/EAX

Auteur:  nico [ Dim 10/Jan/2016 12:24 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Salut Denis, sur le Forum En, Mistrel a sorti les procédure asm équivalente, je viens juste de le trouver, ici:
http://www.purebasic.fr/english/viewtopic.php?f=12&t=38024&hilit=cmpxchg

Cela te paraît correct, pas au niveau résultat car il est bon mais au niveau du code?
Est ce qu'il peut y avoir un conflit avec des threads pour les registres.
Dans les exemples que j'ai trouvé, il y avait un Do-While?

Code:
Procedure InterlockedExchange(*Destination.Integer, Value.i)
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
    !mov ecx,[p.p_Destination]
    !mov eax,[p.v_Value]
    !xchg [ecx],eax
  CompilerEndIf
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rcx,[p.p_Destination]
    !mov rax,[p.v_Value]
    !xchg [rcx],rax
  CompilerEndIf
  ProcedureReturn
EndProcedure

Procedure InterlockedCompareExchange(*Destination.Integer, Exchange.i, Comparand.i)
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
    !mov ecx,[p.p_Destination]
    !mov eax,[p.v_Comparand]
    !mov edx,[p.v_Exchange]
    !lock cmpxchg [ecx],edx
  CompilerEndIf
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rcx,[p.p_Destination]
    !mov rax,[p.v_Comparand]
    !mov rdx,[p.v_Exchange]
    !lock cmpxchg [rcx],rdx
  CompilerEndIf
  ProcedureReturn
EndProcedure


InterlockedExchange(@This,2)
Debug This

InterlockedCompareExchange(@This,4,1)
Debug This
InterlockedCompareExchange(@This,4,2)
Debug This

Auteur:  Anonyme2 [ Dim 10/Jan/2016 18:50 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Nico,

je ne pense pas que le code de Mistrel corresponde à l'exemple en C/asm de la procedure.

forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp) passe
des arguments en 64 bit sous compilation 32 alors que le code de Mistrel les passe en 32 bits

_M_X64 semblerais indiquer la plateforme 64 bit (sous réserve)
http://blogs.msdn.com/b/reiley/archive/ ... sited.aspx

Je pense qu'il faut donc modifier les arguments de la procédure pour passer du 64 bit en argument.

Des gourous en C ici pour confirmer ?

Auteur:  nico [ Dim 10/Jan/2016 19:06 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Je vois ce que tu veux dire mais sur le site MSDN, il y a bien plusieurs fonctions, dont une qui opère sur des variables 32 bit et une autre sur les variables 64 bit, donc je dirais que c'est bon; l'exemple que j'ai mis est peut être pour autre chose, voir ici:
https://msdn.microsoft.com/fr-fr/library/2ddez55b.aspx

Auteur:  nico [ Dim 10/Jan/2016 19:50 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Finalement, je vais utiliser InterlockedCompareExchange et faire un repeat until comme dans l'exemple, cela me paraît plus sécurisé.

Code:
Procedure InterlockedCompareExchange(*Destination.Integer, Exchange.i, Comparand.i)
  EnableASM
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x86
    !mov ecx,[p.p_Destination]
    !mov eax,[p.v_Comparand]
    !mov edx,[p.v_Exchange]
    !lock cmpxchg [ecx],edx
  CompilerEndIf
  CompilerIf #PB_Compiler_Processor=#PB_Processor_x64
    !mov rcx,[p.p_Destination]
    !mov rax,[p.v_Comparand]
    !mov rdx,[p.v_Exchange]
    !lock cmpxchg [rcx],rdx
  CompilerEndIf
  ProcedureReturn
  DisableASM
EndProcedure

Procedure.i AudioEndpointVolumeCallback_AddRef(*pObject.AudioEndpointVolumeCallback)
  Protected Ref.i
 
  Debug "AudioEndpointVolumeCallback_AddRef"
 
  Repeat
    Ref = *pObject\Refcount
    Until InterlockedCompareExchange(@*pObject\Refcount, Ref + 1, Ref) <> *pObject\Refcount
  Debug "*pObject\Refcount = " + Str(*pObject\Refcount)
 
  ProcedureReturn Ref + 1
EndProcedure

Procedure.i AudioEndpointVolumeCallback_Release(*pObject.AudioEndpointVolumeCallback)
  Protected Ref.i
 
  Debug "AudioEndpointVolumeCallback_Release"
 
  Repeat
    Ref = *pObject\Refcount
  Until InterlockedCompareExchange(@*pObject\Refcount, Ref - 1, Ref) <> *pObject\Refcount
 
  Debug "*pObject\Refcount = " + Str(*pObject\Refcount)
 
  If Ref -1 = 0
    AudioEndpointVolumeCallback\pAudioEndpointVolumeCallback = 0
    Debug "delete element --------------------------------"
    *pObject = 0
  EndIf
 
  ProcedureReturn Ref - 1
EndProcedure

Auteur:  Shadow [ Lun 11/Jan/2016 14:47 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Et bien, ça vole haut :?
A quoi ça sert en gros ?

Auteur:  nico [ Lun 11/Jan/2016 19:14 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Cette ligne là, !lock cmpxchg [rcx],rdx, compare le contenu de *Destination et Comparand et si c'est la même valeur, il met la valeur de Exchange dans Destination sinon l'opération n'est pas effectuée.

Dans un contexte Multithread, il faut s'assurer qu'un seul thread puisse modifier une valeur; par exemple dans un contexte d'interface com, il y a une fonction qui incrémente une valeur et l'autre qui l'a décrémente, les valeurs peuvent être fausses si les threads accèdent en même temps sur la variable.

L'élément Lock bloque l'exécution qui suit pour le thread qui l'exécute, donc un seul thread y a accès à la fois, c'est bien sauf qu'au moment de la lecture et au moment de l'écriture, il se passe un peu de temps. Lors de l'appel de la fonction InterlockedCompareExchange, *Destination et Comparand ont la même valeur, donc normalement l'opération se déroule avec succès, si il y a un problème (on lit la valeur, pendant ce temps un autre thread vient juste de l'incrémenter ce qui fait que la valeur contenu dans le pointeur *Destination a changé aussi, donc l'appel à InterlockedCompareExchange échoue, donc on refait un appel de cette fonction grâce au repeat until.

Bon je ne sais pas si c'est très clair, mais voilà.

Auteur:  nico [ Lun 11/Jan/2016 23:35 ]
Sujet du message:  Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Je viens de faire des tests avec des threads (pour vérifier le bon fonctionnement de ce code asm) et cela fonctionne rarement avec le debugger activé et rate quelque fois sans le debugger.

Je vais remettre un Mutex.

Page 1 sur 1 Heures au format UTC + 1 heure
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/