Método ICorProfilerInfo2::DoStackSnapshot

Percorre os quadros gerenciados na pilha do thread especificado e envia informações ao criador de perfil por meio de um retorno de chamada.

Sintaxe

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);  

Parâmetros

thread
[in] A ID do thread de destino.

Se você transmitir nulo em thread, isso vai gerar um instantâneo do thread atual. Se uma ThreadID de um thread diferente for transmitida, o CLR (Common Language Runtime) suspenderá esse thread, executará o instantâneo e será retomado.

callback
[in] Um ponteiro para a implementação do método StackSnapshotCallback, que é chamado pelo CLR para fornecer ao criador de perfil informações sobre cada quadro gerenciado e cada execução de quadros não gerenciados.

O método StackSnapshotCallback é implementado pelo gravador do criador de perfil.

infoFlags
[in] Um valor da enumeração COR_PRF_SNAPSHOT_INFO, que especifica o volume de dados a ser transmitido novamente para cada quadro por StackSnapshotCallback.

clientData
[in] Um ponteiro para os dados do cliente, que são transmitidos diretamente para a função de retorno de chamada StackSnapshotCallback.

context
[in] Um ponteiro para uma estrutura Win32 CONTEXT, que é usada para propagar a movimentação de pilha. A estrutura Win32 CONTEXT contém valores dos registros de CPU e representa o estado da CPU em um momento específico.

A semente ajuda o CLR a determinar em que ponto ele iniciará a movimentação de pilha e se o início da pilha é um código auxiliar não gerenciado. Caso contrário, a semente é ignorada. Uma semente precisa ser fornecida para uma movimentação assíncrona. Se você estiver fazendo uma movimentação síncrona, nenhuma semente será necessária.

O parâmetro context será válido somente se o sinalizador COR_PRF_SNAPSHOT_CONTEXT tiver sido transmitido no parâmetro infoFlags.

contextSize
[in] O tamanho da estrutura CONTEXT, que é referenciada pelo parâmetro context.

Comentários

Se você transmitir nulo para thread, isso vai gerar um instantâneo do thread atual. Os instantâneos só poderão ser obtidos de outros threads se o thread de destino for suspenso no momento.

Quando o criador de perfil deseja percorrer a pilha, ele chama DoStackSnapshot. Antes que o CLR seja retornado dessa chamada, ele chama StackSnapshotCallback várias vezes, uma vez para cada quadro gerenciado (ou execução de quadros não gerenciados) na pilha. Quando são encontrados quadros não gerenciados, você precisa percorrê-los por conta própria.

A ordem na qual a pilha é percorrida é o inverso de como os quadros foram enviados para a pilha: folha (enviada por último) primeiro quadro principal (enviado primeiro) e último quadro.

Para obter mais informações sobre como programar o criador de perfil para percorrer pilhas gerenciadas, confira Movimentação de pilha do criador de perfil no .NET Framework 2.0: Noções básicas e além.

Uma movimentação de pilha pode ser síncrona ou assíncrona, conforme explicado nas seções a seguir.

Movimentação de pilha síncrona

Uma movimentação de pilha síncrona envolve percorrer a pilha do thread atual em resposta a um retorno de chamada. Ela não exige propagação nem suspensão.

Você faz uma chamada síncrona quando, em resposta ao CLR chamando um dos métodos ICorProfilerCallback (ou ICorProfilerCallback2) do criador de perfil, você chama DoStackSnapshot para percorrer a pilha do thread atual. Isso é útil quando você deseja ver como é a pilha em uma notificação como ICorProfilerCallback::ObjectAllocated. Basta chamar DoStackSnapshot no método ICorProfilerCallback, transmitindo nulo nos parâmetros context e thread.

Movimentação de pilha assíncrona

Uma movimentação de pilha assíncrona envolve percorrer a pilha de um thread diferente ou percorrer a pilha do thread atual, não em resposta a um retorno de chamada, mas sequestrando o ponteiro de instrução do thread atual. Uma movimentação assíncrona exigirá uma semente se o início da pilha for um código não gerenciado que não faça parte de uma chamada PInvoke (PInvoke) ou COM, mas o código auxiliar no próprio CLR. Por exemplo, o código que faz a compilação JIT (just-in-time) ou a coleta de lixo é o código auxiliar.

Você obtém uma semente suspendendo diretamente o thread de destino e percorrendo a pilha por conta própria, até encontrar o quadro gerenciado mais alto. Depois que o thread de destino for suspenso, obtenha o contexto de registro atual do thread de destino. Em seguida, determine se o contexto de registro aponta para o código não gerenciado chamando ICorProfilerInfo::GetFunctionFromIP: se ele retornar uma FunctionID igual a zero, o quadro será um código não gerenciado. Agora, percorra a pilha até chegar ao primeiro quadro gerenciado e calcule o contexto de semente com base no contexto de registro desse quadro.

Chame DoStackSnapshot com o contexto de semente para iniciar a movimentação de pilha assíncrona. Se você não fornecer uma semente, o DoStackSnapshot poderá ignorar quadros gerenciados no início da pilha e, consequentemente, fornecerá uma movimentação de pilha incompleta. Se você fornecer uma semente, ela precisará apontar para o código gerado pelo Gerador de Imagem Nativo (Ngen.exe) compilado por JIT. Caso contrário, o DoStackSnapshot retornará o código de falha CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX.

As movimentações de pilha assíncronas podem causar deadlocks ou violações de acesso com facilidade, a menos que você siga estas diretrizes:

  • Ao suspender diretamente os threads, lembre-se de que apenas um thread que nunca executou o código gerenciado pode suspender outro thread.

  • Sempre bloqueie o retorno de chamada ICorProfilerCallback::ThreadDestroyed até que a movimentação de pilha desse thread seja concluída.

  • Não mantenha um bloqueio enquanto o criador de perfil chama uma função CLR que possa disparar uma coleta de lixo. Ou seja, não mantenha um bloqueio se o thread proprietário puder fazer uma chamada que dispare uma coleta de lixo.

Há também o risco de deadlock se você chamar DoStackSnapshot em um thread que o criador de perfil criou para que você possa percorrer a pilha de um thread de destino separado. Na primeira vez que o thread que você criou entrar em alguns métodos ICorProfilerInfo* (incluindo DoStackSnapshot), o CLR executará a inicialização por thread específica do CLR nesse thread. Se o criador de perfil tiver suspenso o thread de destino cuja pilha você está tentando percorrer e se esse thread de destino tiver um bloqueio necessário para executar essa inicialização por thread, ocorrerá um deadlock. Para evitar esse deadlock, faça uma chamada inicial em DoStackSnapshot do thread criado pelo criador de perfil para percorrer um thread de destino separado, mas não suspenda o thread de destino primeiro. Essa chamada inicial garante que a inicialização por thread possa ser concluída sem um deadlock. Se o DoStackSnapshot for bem-sucedido e relatar, pelo menos, um quadro, após esse ponto, será seguro para esse thread criado pelo criador de perfil suspender qualquer thread de destino e chamar DoStackSnapshot para percorrer a pilha desse thread de destino.

Requisitos

Plataformas: confira Requisitos do sistema.

Cabeçalho: CorProf.idl, CorProf.h

Biblioteca: CorGuids.lib

Versões do .NET Framework: disponíveis desde 2.0

Confira também