Page 1 sur 1
Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : sam. 09/janv./2016 21:07
par nico
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 : Tout sélectionner
#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);
}
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : sam. 09/janv./2016 23:29
par nico
j'ai fait ça, est-ce que c'est bon?
Code : Tout sélectionner
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
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : dim. 10/janv./2016 0:37
par Ar-S
Je voudrai bien t'aider mais c'est au delà de mes compétences..
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : dim. 10/janv./2016 11:27
par nico
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.
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : dim. 10/janv./2016 11:54
par Anonyme2
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
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : dim. 10/janv./2016 12:24
par nico
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/viewtop ... it=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 : Tout sélectionner
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
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : dim. 10/janv./2016 18:50
par Anonyme2
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 ?
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : dim. 10/janv./2016 19:06
par nico
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
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : dim. 10/janv./2016 19:50
par nico
Finalement, je vais utiliser InterlockedCompareExchange et faire un repeat until comme dans l'exemple, cela me paraît plus sécurisé.
Code : Tout sélectionner
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
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : lun. 11/janv./2016 14:47
par Shadow
Et bien, ça vole haut
A quoi ça sert en gros ?
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : lun. 11/janv./2016 19:14
par nico
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à.
Re: Besoin d'aide pour InterlockedIncrement64 en ASM
Publié : lun. 11/janv./2016 23:35
par nico
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.