Метод ICorProfilerInfo2::DoStackSnapshot
Выполняет обход кадров управляемого кода в стеке для заданного потока и отправляет сведения профилировщику посредством обратного вызова.
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);
Параметры
thread
[in] Идентификатор целевого потока.При передаче значения NULL в параметре thread выполняется моментальный снимок текущего потока. Если же передается идентификатор ThreadID другого потока, среда CLR приостанавливает поток, делает моментальный снимок и возобновляет выполнение этого потока.
callback
[in] Указатель на реализацию метода StackSnapshotCallback, который вызывается средой CLR для предоставления профилировщику сведений о каждом кадре управляемого кода и каждом выполнении кадров неуправляемого кода.Метод StackSnapshotCallback реализуется средством записи профилировщика.
infoFlags
[in] Значение перечисления COR_PRF_SNAPSHOT_INFO, задающее количество данных, переданных назад методом StackSnapshotCallback для каждого кадра.clientData
[in] Указатель на данные клиента, которые передаются непосредственно с помощью функции обратного вызова StackSnapshotCallback.context
[in] Указатель на структуру Win32 CONTEXT, которая используется для присвоения начального значения для прохода стека. Структура CONTEXT для Win32 содержит значение для регистров ЦП и представляет состояние ЦП в определенный момент времени.Начальное значение позволяет среде CLR определить место, с которого нужно начать проход, если на вершине стека расположен вспомогательный неуправляемый код; в противном случае начальное значение игнорируется. Начальное значение нужно указывать для асинхронного прохода. При выполнении синхронного прохода начальное значение не требуется.
Параметр context является допустимым, только если в параметр infoFlags был передан флаг COR_PRF_SNAPSHOT_CONTEXT.
contextSize
[in] Размер структуры CONTEXT, на которую ссылается параметр context.
Заметки
При передаче значения NULL для параметра thread создается моментальный снимок текущего потока. Моментальные снимки других потоков можно сделать только в случае приостановки целевого потока на это время.
Когда профилировщику нужно выполнить проход по стеку, он вызывает метод DoStackSnapshot. Перед возвратом из этого вызова, среда CLR несколько раз выполнит вызов StackSnapshotCallback, по одному разу для каждого кадра управляемого кода (или запуска кадров неуправляемого кода) в стеке. Если встречаются кадры неуправляемого кода, их проход нужно выполнить самостоятельно.
Порядок, в котором выполняется проход стека, является обратным по отношению к порядку, в котором кадры были переданы в стек: сначала конечный кадр (последний переданный), а в конце последний кадр (первый переданный).
Дополнительные сведения о программировании в профилировщике выполнения прохода стеков управляемого кода см. в документе Пошаговый анализ стеков при помощи профилировщика в среде платформы .NET Framework 2.0: Основные принципы и некоторые особенности в библиотеке MSDN.
Проход стека можно выполнять синхронно или асинхронно, как описано в следующих разделах.
Синхронный проход стека
Синхронный проход стека предполагает проход стека текущего потока в ответ на обратный вызов. Для него не требуется присвоение начального значения или приостановка.
Синхронный вызов осуществляется, когда в ответ на вызов средой CLR одного из методов интерфейса ICorProfilerCallback (или ICorProfilerCallback2) профилировщика, нужно вызвать метод DoStackSnapshot для прохода стека текущего потока. Этот вызов удобно использовать при необходимости получить представление о внешнем виде стека при получении такого уведомления, как ICorProfilerCallback::ObjectAllocated. При этом нужно просто вызвать метод DoStackSnapshot из метода ICorProfilerCallback и передать значение NULL в параметры context и thread.
Асинхронный проход стека
Асинхронный проход стека приводит к проходу стека другого потока или проходу стека текущего потока не в ответ на обратный вызов, а путем перехвата указателя инструкций текущего потока. Для асинхронного прохода требуется исходное значение, если на вершине стека расположен неуправляемый код, не являющийся частью вызова платформы (PInvoke) или вызова модели COM и представляющий собой вспомогательный код в самой среде CLR. Например, код, выполняющий JIT-компиляцию или сборку мусора, является вспомогательным.
Чтобы получить начальное значение, нужно самостоятельно приостановить целевой поток и пройти по стеку вручную, пока не будет найден самый верхний кадр управляемого кода. После приостановки целевого потока нужно получить текущий контекст регистра целевого потока. Затем нужно определить, указывает ли состояние регистров на неуправляемый код, вызвав для этого метод ICorProfilerInfo::GetFunctionFromIP. если он возвратить в качестве значения FunctionID нуль, кадр является неуправляемым кодом. Теперь нужно выполнять проход стека до тех пор, пока не будет достигнут кадр управляемого кода, а затем вычислить контекст начального значения, исходя из контекста регистра для этого кадра.
Чтобы начать асинхронный проход стека, нужно вызывать метод DoStackSnapshot с контекстом начального значения. Если начальное значение не указано, метод DoStackSnapshot пропустит кадры управляемого кода на вершине стека и, как следствие выполнит неполный проход стека. Если начальное значение все же задано, оно должно указывать на код, скомпилированный путем использования JIT-компиляции, или код, сгенерированный генератором образов в машинном коде (Ngen.exe); в противном случае метод DoStackSnapshot возвратит код ошибки CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX.
Если не придерживаться этих инструкций асинхронные проходы стека могут легко вызвать взаимоблокировку или нарушение прав доступа.
При непосредственной приостановке потоков следует помнить, что приостановить другой поток может только поток, в котором никогда не выполнялся управляемый код.
До завершения прохода стека потока нужно всегда блокировать обратный вызов ICorProfilerCallback::ThreadDestroyed.
Не следует блокировать поток во время обращения профилировщика к функции среды CLR, способной запустить сборку мусора. Иными словами, не следует применять блокировку, если собственный поток может осуществить вызов, который включит сборку мусора.
Также риск взаимоблокировки существует при вызове DoStackSnapshot из потока, созданного профилировщиком для прохода по стеку конкретного целевого потока. При первом создании поток входит в определенные методы ICorProfilerInfo* (включая DoStackSnapshot), среда CLR выполняет инициализацию потока, связанную со средой CLR. Если профилировщик приостановил целевой поток, чей стек пытается пройти пользователь, и если этот целевой поток является владельцем блокировки, необходимой для выполнения инициализации каждого потока, произойдет взаимоблокировка. Чтобы избежать этой взаимоблокировки, выполните исходный вызов DoStackSnapshot из потока, созданного профилировщиком для прохода по отдельному целевому потоку, не приостанавливая перед этим сам целевой поток. Исходный вызов гарантирует, что инициализация отдельных потоков сможет завершиться без взаимоблокировки. Если DoStackSnapshot успешно выполняется и выдает по крайней мере один фрейм, после этой точки данный поток, созданный профилировщиком, может безопасно приостанавливать любой целевой поток и вызывать DoStackSnapshot для прохода стека этого целевого потока.
Требования
Платформы: см. раздел Требования к системе для .NET Framework.
Заголовок: CorProf.idl, CorProf.h
Библиотека: CorGuids.lib
Версии платформы .NET Framework: 4, 3.5 с пакетом обновления 1 (SP1), 3.5, 3.0 с пакетом обновления 1 (SP1), 3.0, 2.0 с пакетом обновления 1 (SP1), 2.0