Partager via


ICorProfilerInfo2::DoStackSnapshot, méthode

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

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.

    Le fait de passer null dans thread produit un instantané du thread actuel. Si un ThreadID d'un autre thread est passé, le Common Language Runtime (CLR) suspend ce thread, exécute l'instantané, et reprend l'exécution.

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

    La méthode StackSnapshotCallback est implémentée par le writer de profileur.

  • infoFlags
    [in] Valeur de l'énumération COR_PRF_SNAPSHOT_INFO qui spécifie la quantité de données à renvoyer pour chaque frame par StackSnapshotCallback.

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

  • context
    [in] Pointeur vers une structure CONTEXT Win32 qui est utilisée pour donner une valeur de départ au parcours de pile. La structure CONTEXT Win32 contient des valeurs des registres de l'UC et représente l'état de l'UC à un moment donné.

    La valeur de départ aide le CLR à déterminer où commencer le parcours de pile, si le haut de la pile est du code de fonction d'assistance non managé ; sinon, la valeur de départ est ignorée. Une valeur de départ doit être fournie pour un parcours asynchrone. Si vous effectuez un parcours synchrone, aucune valeur de départ n'est nécessaire.

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

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

Notes

Le fait de passer null pour thread produit un instantané du thread actuel. Il est possible de prendre des instantanés d'autres threads uniquement si le thread cible est suspendu à ce moment-là.

Lorsque le profileur souhaite parcourir la pile, il appelle DoStackSnapshot. Avant le retour, CLR appelle StackSnapshotCallback à plusieurs reprises, une fois pour chaque frame managé (ou exécution de frames non managés) sur la pile. Lorsque des frames non managés sont rencontrés, vous devez vous-même les parcourir.

L'ordre dans lequel la pile est parcourue est inversé par rapport à l'ordre dans lequel les frames ont fait l'objet d'un push sur la pile : le frame terminal (dernier push) en premier, le frame principal (premier push) en dernier.

Pour plus d'informations sur la programmation du profileur pour parcourir des piles managées, consultez Profiler Stack Walking in the .NET Framework 2.0: Basics and Beyond dans MSDN Library.

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

Parcours de pile synchrone

Un parcours de pile synchrone implique le parcours de la pile du thread actuel en réponse à un rappel. Il ne requiert pas la définition d'une valeur de départ ou une interruption.

Vous effectuez un appel synchrone lorsque, en réponse à l'appel de l'une des méthodes ICorProfilerCallback (ou ICorProfilerCallback2) de votre profileur par le CLR, vous appelez DoStackSnapshot pour parcourir la pile du thread actuel. Cela est utile lorsque vous souhaitez voir à quoi ressemble la pile lors d'une notification telle que ICorProfilerCallback::ObjectAllocated. Il vous suffit d'appeler DoStackSnapshot à partir de votre méthode ICorProfilerCallback, en passant null dans les paramètres context et thread.

Parcours de pile asynchrone

Un parcours de pile asynchrone implique de parcourir la pile d'un autre thread ou de parcourir la pile du thread actuel, non pas en réponse à un rappel, mais en détournant le pointeur d'instruction du thread actuel. Un parcours asynchrone requiert une valeur de départ si le haut de la pile correspond à du code non managé qui ne fait pas partie d'un appel de code non managé (PInvoke) ou d'un appel COM, mais du code de la fonction d'assistance dans le CLR lui-même. Par exemple, du code qui exécute la compilation JIT ou le garbage collection correspond à du code de la fonction d'assistance.

Pour obtenir une valeur de départ, suspendez le thread cible directement et parcourez sa pile vous-même, jusqu'à ce que vous trouviez le frame managé le plus haut. Une fois le thread cible suspendu, obtenez le contexte de registre en cours du thread cible. Ensuite, déterminez si le contexte de registre pointe vers du code non managé en appelant ICorProfilerInfo::GetFunctionFromIP : s'il retourne un FunctionID égal à zéro, le frame correspond à du code non managé. Maintenant, parcourez la pile jusqu'au premier frame managé, puis calculez le contexte de valeur de départ d'après le contexte de registre pour ce frame.

Appelez DoStackSnapshot avec votre contexte de valeur de départ pour commencer le parcours de pile asynchrone. Si vous ne fournissez pas de valeur de départ, DoStackSnapshot peut ignorer les frames managés en haut de la pile, et vous donnera par conséquent un parcours de pile incomplet. Si vous fournissez une valeur de départ, elle doit pointer vers du code compilé juste-à-temps ou du code généré par le générateur d'images natives (Ngen.exe) ; sinon, DoStackSnapshot retourne le code d'échec CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX.

Les parcours de pile asynchrones peuvent facilement provoquer des interblocages ou des violations d'accès, sauf si vous suivez ces instructions :

  • Lorsque vous suspendez des threads directement, souvenez-vous que seul un thread n'ayant jamais exécuté de code managé peut suspendre un autre thread.

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

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

Il y a également un risque d'interblocage si vous appelez DoStackSnapshot à partir d'un thread que votre profileur a créé afin que vous puissiez parcourir la pile depuis un thread cible séparé. La première fois que le thread que vous avez créé entre certaines méthodes ICorProfilerInfo* (notamment DoStackSnapshot), le CLR exécute une initialisation par thread et spécifique au CLR sur ce thread. Si votre profileur a interrompu le thread cible dont vous essayez de parcourir la pile, et si ce thread cible a déjà possédé un verrouillage nécessaire pour l'exécution cette initialisation par thread, un interblocage se produira. Pour éviter cet interblocage, faites un appel initial à DoStackSnapshot depuis votre thread créé par le profileur pour parcourir un thread cible distinct, mais n'interrompez pas le thread cible au préalable. Cet appel initial garantit que l'initialisation par thread peut se dérouler sans interblocage. Si DoStackSnapshot réussit et signale au moins une frame, après ce point, ce thread créé par le profileur sera sécurisé pour interrompre tout thread cible et appel DoStackSnapshot pouvant accompagner la pile de ce thread cible.

Configuration requise

Plateformes : consultez Configuration requise du .NET Framework.

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

Bibliothèque : CorGuids.lib

Versions du .NET Framework : 4, 3.5 SP1, 3.5, 3.0 SP1, 3.0, 2.0 SP1, 2.0

Voir aussi

Référence

ICorProfilerInfo, interface

ICorProfilerInfo2, interface