Besoin d'aide pour InterlockedIncrement64 en ASM

Pour discuter de l'assembleur
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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);
}
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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 
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message par Ar-S »

Je voudrai bien t'aider mais c'est au delà de mes compétences..
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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.
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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 ?
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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
Shadow
Messages : 1373
Inscription : mer. 04/nov./2015 17:39

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message par Shadow »

Et bien, ça vole haut :?
A quoi ça sert en gros ?
Processeur: Intel Core I7-4790 - 4 Cœurs - 8 Thread: 3.60 Ghz.
Ram: 32 GB.
Disque: C: SDD 250 GB, D: 3 TB.
Vidéo: NVIDIA GeForce GTX 960: 2 GB DDR5.
Écran: Asus VX248 24 Pouces: 1920 x 1080.
Système: Windows 7 64 Bits.

PureBasic: 5.60 x64 Bits.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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à.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Besoin d'aide pour InterlockedIncrement64 en ASM

Message 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.
Répondre