CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT

The CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT was introduced in the .NET Framework version 2.0. The .NET Framework 4 returns this HRESULT in two scenarios:

  • When a hijacking profiler forcibly resets a thread's register context at an arbitrary time so that the thread tries to access structures that are in an inconsistent state.

  • When a profiler tries to call an informational method that triggers garbage collection from a callback method that forbids garbage collection.

These two scenarios are discussed in the following sections.

Hijacking Profilers

(This scenario is primarily an issue with hijacking profilers although there are cases where non-hijacking profilers can see this HRESULT.)

In this scenario, a hijacking profiler forcibly resets a thread's register context at an arbitrary time so that the thread can enter profiler code or re-enter the common language runtime (CLR) through an ICorProfilerInfo method.

Many of the IDs that the profiling API provides point to data structures in the CLR. Many ICorProfilerInfo calls merely read information from these data structures and pass them back. However, the CLR might change things in those structures as it runs, and it might use locks to do so. Suppose the CLR was already holding (or attempting to acquire) a lock at the time the profiler hijacked the thread. If the thread re-enters the CLR and tries to take more locks or inspect structures that were in the process of being modified, these structures might be in an inconsistent state. Deadlocks and access violations can easily occur in such situations.

In general, when a non-hijacking profiler executes code inside an ICorProfilerCallback method and calls into an ICorProfilerInfo method with valid parameters, it should not deadlock or receive an access violation. For example, profiler code that runs inside the ICorProfilerCallback::ClassLoadFinished method may ask for information about the class by calling the ICorProfilerInfo2::GetClassIDInfo2 method. The code might receive an CORPROF_E_DATAINCOMPLETE HRESULT to indicate that information is unavailable; however, it will not deadlock or receive an access violation. This class of calls into ICorProfilerInfo are called synchronous, because they are made from an ICorProfilerCallback method.

However, a managed thread that executes code that is not within an ICorProfilerCallback method is considered to be making an asynchronous call. In the .NET Framework version 1, it was difficult to determine what might happen in an asynchronous call. The call could deadlock, crash, or give an invalid answer. The .NET Framework version 2.0 introduced some simple checks to help you avoid this problem. In the .NET Framework 2.0, if you call an unsafe ICorProfilerInfo function asynchronously, it fails with an CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT.

In general, asynchronous calls are not safe. However, the following methods are safe and specifically support asynchronous calls:

For additional information, see the entry Why we have CORPROF_E_UNSUPPORTED_CALL_SEQUENCE in the CLR Profiling API blog.

Triggering Garbage Collections

This scenario involves a profiler that is running inside a callback method (for example, one of the ICorProfilerCallback methods) that forbids garbage collection. If the profiler tries to call an informational method (for example, a method on the ICorProfilerInfo interface) that might trigger a garbage collection, the informational method fails with a CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT.

The following table displays the callback methods that forbid garbage collections, and informational methods that may trigger garbage collections. If the profiler executes inside one of the listed callback methods and calls one of the listed informational methods, that informational method fails with a CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT.

Callback methods that forbid garbage collections Informational methods that trigger garbage collections
ThreadAssignedToOSThread

ExceptionUnwindFunctionEnter

ExceptionUnwindFunctionLeave

ExceptionUnwindFinallyEnter

ExceptionUnwindFinallyLeave

ExceptionCatcherEnter

RuntimeSuspendStarted

RuntimeSuspendFinished

RuntimeSuspendAborted

RuntimeThreadSuspended

RuntimeThreadResumed

MovedReferences

ObjectReferences

ObjectsAllocatedByClass

RootReferences2

HandleCreated

HandleDestroyed

GarbageCollectionStarted

GarbageCollectionFinished
GetILFunctionBodyAllocator

SetILFunctionBody

SetILInstrumentedCodeMap

ForceGC

GetClassFromToken

GetClassFromTokenAndTypeArgs

GetFunctionFromTokenAndTypeArgs

GetAppDomainInfo

EnumModules

RequestProfilerDetach

GetAppDomainsContainingModule

See also