ICorProfilerInfo2::DoStackSnapshot, méthode

Parcourt les cadres managés sur la pile pour le thread spécifié et envoie des informations au profileur via un rappel.

Syntaxe

HRESULT DoStackSnapshot(  
    [in] ThreadID thread,  
    [in] StackSnapshotCallback *callback,  
    [in] ULONG32 infoFlags,  
    [in] void *clientData,  
    [in, size_is(contextSize), length_is(contextSize)] BYTE context[],  
    [in] ULONG32 contextSize);  

Paramètres

thread
[in] ID du thread cible.

La transmission de la valeur null dans thread génère un instantané du thread actuel. Si un ThreadID d’un autre thread est passé, le Common Language Runtime (CLR) suspend ce thread, effectue l’instantané et reprend.

callback
[in] Pointeur vers l’implémentation de la méthode StackSnapshotCallback, appelée par le CLR pour fournir au profileur des informations sur chaque cadre managé et chaque exécution de cadres non managés.

La méthode StackSnapshotCallback est implémentée par l’enregistreur du profileur.

infoFlags
[in] Valeur de l’énumération COR_PRF_SNAPSHOT_INFO qui spécifie la quantité de données à transmettre pour chaque cadre par StackSnapshotCallback.

clientData
[in] Pointeur vers les données clientes, qui est passé directement à la fonction de rappel StackSnapshotCallback.

context
[in] Pointeur vers une structure Win32 CONTEXT, qui est utilisée pour amorcer la procédure de pile. La structure Win32 CONTEXT contient des valeurs des registres d’UC et représente l’état de l’UC à un moment donné dans le temps.

La valeur initiale permet au CLR de déterminer où commencer la procédure de pile, si le haut de la pile est un code d’assistance non managé ; sinon, la valeur initiale est ignorée. Une valeur initiale doit être fournie pour une procédure asynchrone. Si vous effectuez un parcours synchrone, aucune valeur initiale n’est nécessaire.

Le paramètre context est valide uniquement si l’indicateur de COR_PRF_SNAPSHOT_CONTEXT a été passé dans le paramètre infoFlags.

contextSize
[in] Taille de la structure CONTEXT, référencée par le paramètre context.

Notes

La transmission de la valeur null pour thread génère un instantané du thread actuel. Les captures instantanées peuvent être prises d’autres threads uniquement si le thread cible est suspendu à ce moment.

Lorsque le profileur souhaite parcourir la pile, il appelle DoStackSnapshot. Avant que le CLR retourne à partir de cet appel, il appelle votre StackSnapshotCallback plusieurs fois, une fois pour chaque cadre managé (ou exécution de cadres non managés) sur la pile. Lorsque des cadres non managés sont rencontrés, vous devez les parcourir vous-même.

L’ordre dans lequel la pile est parcourue est l’inverse de la façon dont les cadres ont été poussés sur la pile : cadre feuille (dernier envoi) d’abord, cadre principal (premier envoi) en dernier.

Pour plus d’informations sur la façon de programmer le profileur pour parcourir les piles managées, consultez Parcours de la pile du profileur dans .NET Framework 2.0 : Notions de base et plus.

Un parcours de pile peut être synchrone ou asynchrone, comme expliqué dans les sections suivantes.

Parcours de pile synchrone

Un parcours de pile synchrone implique de parcourir la pile du thread actuel en réponse à un rappel. Il ne nécessite pas d’amorçage ou de suspension.

Vous effectuez un appel synchrone quand, en réponse à l’appel CLR de l’une des méthodes ICorProfilerCallback (ou ICorProfilerCallback2) de votre profileur, vous appelez DoStackSnapshot pour parcourir la pile du thread actuel. Cela est utile lorsque vous souhaitez voir à quoi ressemble la pile pour une notification comme ICorProfilerCallback::ObjectAllocated. Vous appelez simplement DoStackSnapshot à partir de votre méthode ICorProfilerCallback, en passant la valeur null dans les paramètres context et thread.

Parcours de pile asynchrone

Une procédure de pile asynchrone implique de parcourir la pile d’un thread différent ou de parcourir la pile du thread actuel, pas en réponse à un rappel, mais en détournant le pointeur d’instruction du thread actuel. Un parcours asynchrone nécessite une valeur initiale si le haut de la pile n’est pas du code managé qui ne fait pas partie d’un appel de plateforme (PInvoke) ou d’un appel COM, mais du code d’assistance dans le CLR lui-même. Par exemple, du code qui effectue une compilation juste-à-temps (JIT) ou un nettoyage de la mémoire est du code d’assistance.

Vous obtenez une valeur initiale en suspendant directement le thread cible et en parcourant vous-même sa pile, jusqu’à ce que vous trouviez le cadre managé le plus élevé. Une fois le thread cible suspendu, obtenez le contexte de registre actuel du thread cible. Ensuite, déterminez si le contexte du registre pointe vers du code non managé en appelant ICorProfilerInfo::GetFunctionFromIP ; s’il retourne un FunctionID égal à zéro, le cadre n’est pas managé. À présent, parcourez la pile jusqu’à atteindre le premier cadre managé, puis calculez le contexte de départ en fonction du contexte de registre pour ce cadre.

Appelez DoStackSnapshot avec votre contexte de départ pour commencer le parcours de pile asynchrone. Si vous ne fournissez pas de valeur initiale, DoStackSnapshot peut ignorer les cadres managés en haut de la pile et, par conséquent, vous donner un parcours de pile incomplet. Si vous fournissez une valeur initiale, elle doit pointer vers le code généré par JIT ou Native Image Generator (Ngen.exe) ; sinon DoStackSnapshot retourne le code d’échec CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX.

Les parcours de pile asynchrones peuvent facilement provoquer des blocages ou des violations d’accès si vous ne suivez pas ces instructions :

  • Lorsque vous suspendez directement des threads, n’oubliez pas que seul un thread qui n’a jamais exécuté de code managé peut suspendre un autre thread.

  • Bloquez toujours votre rappel ICorProfilerCallback::ThreadDestroyed jusqu’à ce que le parcours de pile de ce thread soit terminée.

  • Ne maintenez pas un verrou pendant que votre profileur appelle une fonction CLR qui peut déclencher un nettoyage de la mémoire. Autrement dit, ne maintenez pas un verrou si le thread propriétaire peut effectuer un appel qui déclenche un nettoyage de la mémoire.

Il existe également un risque d’interblocage si vous appelez DoStackSnapshot à partir d’un thread que votre profileur a créé afin de pouvoir parcourir la pile d’un thread cible distinct. La première fois que le thread que vous avez créé entre dans certaines méthodes ICorProfilerInfo* (y compris DoStackSnapshot), le CLR effectue une initialisation spécifique au CLR par thread sur ce thread. Si votre profileur a suspendu le thread cible que vous essayez de parcourir et si ce thread cible est arrivé à posséder un verrou nécessaire pour effectuer cette initialisation par thread, un interblocage se produit. Pour éviter ce blocage, effectuez un appel initial à DoStackSnapshot partir de votre thread créé par le profileur pour parcourir un thread cible distinct, mais ne suspendez pas le thread cible en premier. Cet appel initial garantit que l’initialisation par thread peut se terminer sans interblocage. Si DoStackSnapshot réussit et signale au moins un cadre, après ce stade, il est sûr que ce thread créé par le profileur suspend tout thread cible et appelle DoStackSnapshot pour parcourir la pile de ce thread cible.

Spécifications

Plateformes : Consultez Configuration requise.

En-tête : CorProf.idl, CorProf.h

Bibliothèque : CorGuids.lib

Versions de .NET Framework : Disponible depuis la version 2.0

Voir aussi