647 lines
19 KiB
C
647 lines
19 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sxsactctx.c
|
|
|
|
Abstract:
|
|
|
|
Side-by-side activation support for Windows/NT
|
|
Implementation of the application context object.
|
|
|
|
Author:
|
|
|
|
Michael Grier (MGrier) 2/1/2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#if defined(__cplusplus)
|
|
extern "C" {
|
|
#endif
|
|
#pragma warning(disable:4214) // bit field types other than int
|
|
#pragma warning(disable:4201) // nameless struct/union
|
|
#pragma warning(disable:4115) // named type definition in parentheses
|
|
#pragma warning(disable:4127) // condition expression is constant
|
|
#include <ntos.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <sxstypes.h>
|
|
#include "sxsp.h"
|
|
#include "limits.h"
|
|
|
|
#define IS_ALIGNED(_p, _n) ((((ULONG_PTR) (_p)) & ((_n) - 1)) == 0)
|
|
#define IS_WORD_ALIGNED(_p) IS_ALIGNED((_p), 2)
|
|
#define IS_DWORD_ALIGNED(_p) IS_ALIGNED((_p), 4)
|
|
|
|
BOOLEAN g_SxsKeepActivationContextsAlive;
|
|
BOOLEAN g_SxsTrackReleaseStacks;
|
|
|
|
// These must be accessed -only- with the peb lock held
|
|
LIST_ENTRY g_SxsLiveActivationContexts;
|
|
LIST_ENTRY g_SxsFreeActivationContexts;
|
|
ULONG g_SxsMaxDeadActivationContexts = ULONG_MAX;
|
|
ULONG g_SxsCurrentDeadActivationContexts;
|
|
|
|
#if DBG
|
|
VOID RtlpSxsBreakOnInvalidMarker(PCACTIVATION_CONTEXT ActivationContext, ULONG FailureCode);
|
|
static CHAR *SxsSteppedOnMarkerText =
|
|
"%s : Invalid activation context marker %p found in activation context %p\n"
|
|
" This means someone stepped on the allocation, or someone is using a\n"
|
|
" deallocated activation context\n";
|
|
|
|
#define VALIDATE_ACTCTX(pA) do { \
|
|
const PACTIVATION_CONTEXT_WRAPPED pActual = CONTAINING_RECORD(pA, ACTIVATION_CONTEXT_WRAPPED, ActivationContext); \
|
|
if (pActual->MagicMarker != ACTCTX_MAGIC_MARKER) { \
|
|
DbgPrint(SxsSteppedOnMarkerText, __FUNCTION__, pActual->MagicMarker, pA); \
|
|
ASSERT(pActual->MagicMarker == ACTCTX_MAGIC_MARKER); \
|
|
RtlpSxsBreakOnInvalidMarker((pA), SXS_CORRUPTION_ACTCTX_MAGIC_NOT_MATCHED); \
|
|
} \
|
|
} while (0)
|
|
#else
|
|
#define VALIDATE_ACTCTX(pA)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
RtlpMoveActCtxToFreeList(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
RtlpPlaceActivationContextOnLiveList(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
);
|
|
|
|
NTSTATUS
|
|
RtlpValidateActivationContextData(
|
|
IN ULONG Flags,
|
|
IN PCACTIVATION_CONTEXT_DATA Data,
|
|
IN SIZE_T BufferSize OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PCACTIVATION_CONTEXT_DATA_TOC_HEADER TocHeader;
|
|
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader;
|
|
|
|
if (Flags != 0) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((Data->Magic != ACTIVATION_CONTEXT_DATA_MAGIC) ||
|
|
(Data->FormatVersion != ACTIVATION_CONTEXT_DATA_FORMAT_WHISTLER) ||
|
|
((BufferSize != 0) &&
|
|
(BufferSize < Data->TotalSize))) {
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
|
|
// Check required elements...
|
|
if ((Data->DefaultTocOffset == 0) ||
|
|
!IS_DWORD_ALIGNED(Data->DefaultTocOffset)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: Warning: Activation context data at %p missing default TOC\n", Data);
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
|
|
// How can we not have an assembly roster?
|
|
if ((Data->AssemblyRosterOffset == 0) ||
|
|
!IS_DWORD_ALIGNED(Data->AssemblyRosterOffset)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: Warning: Activation context data at %p lacks assembly roster\n", Data);
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Data->DefaultTocOffset != 0) {
|
|
if ((Data->DefaultTocOffset >= Data->TotalSize) ||
|
|
((Data->DefaultTocOffset + sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER)) > Data->TotalSize)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: Activation context data at %p has invalid TOC header offset\n", Data);
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
|
|
TocHeader = (PCACTIVATION_CONTEXT_DATA_TOC_HEADER) (((ULONG_PTR) Data) + Data->DefaultTocOffset);
|
|
|
|
if (TocHeader->HeaderSize < sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: Activation context data at %p has TOC header too small (%lu)\n", Data, TocHeader->HeaderSize);
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((TocHeader->FirstEntryOffset >= Data->TotalSize) ||
|
|
(!IS_DWORD_ALIGNED(TocHeader->FirstEntryOffset)) ||
|
|
((TocHeader->FirstEntryOffset + (TocHeader->EntryCount * sizeof(ACTIVATION_CONTEXT_DATA_TOC_ENTRY))) > Data->TotalSize)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: Activation context data at %p has invalid TOC entry array offset\n", Data);
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// we should finish validating the rest of the structure...
|
|
|
|
if ((Data->AssemblyRosterOffset >= Data->TotalSize) ||
|
|
((Data->AssemblyRosterOffset + sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)) > Data->TotalSize)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: Activation context data at %p has invalid assembly roster offset\n", Data);
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
|
|
AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) Data) + Data->AssemblyRosterOffset);
|
|
|
|
if (Data->AssemblyRosterOffset != 0) {
|
|
if (AssemblyRosterHeader->HeaderSize < sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)) {
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SXS: Activation context data at %p has assembly roster header too small (%lu)\n", Data, AssemblyRosterHeader->HeaderSize);
|
|
Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlCreateActivationContext(
|
|
IN ULONG Flags,
|
|
IN PCACTIVATION_CONTEXT_DATA ActivationContextData,
|
|
IN ULONG ExtraBytes,
|
|
IN PACTIVATION_CONTEXT_NOTIFY_ROUTINE NotificationRoutine,
|
|
IN PVOID NotificationContext,
|
|
OUT PACTIVATION_CONTEXT *ActCtx
|
|
)
|
|
{
|
|
PACTIVATION_CONTEXT NewActCtx = NULL;
|
|
PACTIVATION_CONTEXT_WRAPPED AllocatedActCtx = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG i, j;
|
|
PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader;
|
|
BOOLEAN UninitializeStorageMapOnExit = FALSE;
|
|
|
|
DbgPrintEx(
|
|
DPFLTR_SXS_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"SXS: RtlCreateActivationContext() called with parameters:\n"
|
|
" Flags = 0x%08lx\n"
|
|
" ActivationContextData = %p\n"
|
|
" ExtraBytes = %lu\n"
|
|
" NotificationRoutine = %p\n"
|
|
" NotificationContext = %p\n"
|
|
" ActCtx = %p\n",
|
|
Flags,
|
|
ActivationContextData,
|
|
ExtraBytes,
|
|
NotificationRoutine,
|
|
NotificationContext,
|
|
ActCtx);
|
|
|
|
RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT_DATA(ActivationContextData);
|
|
|
|
if (ActCtx != NULL)
|
|
*ActCtx = NULL;
|
|
|
|
if ((Flags != 0) ||
|
|
(ActivationContextData == NULL) ||
|
|
(ExtraBytes > 65536) ||
|
|
(ActCtx == NULL))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure that the activation context data passes muster
|
|
Status = RtlpValidateActivationContextData(0, ActivationContextData, 0);
|
|
if (!NT_SUCCESS(Status))
|
|
goto Exit;
|
|
|
|
// Allocate enough space to hold the new activation context, plus space for the 'magic'
|
|
// marker
|
|
AllocatedActCtx = (PACTIVATION_CONTEXT_WRAPPED)RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
0,
|
|
sizeof(ACTIVATION_CONTEXT_WRAPPED) + ExtraBytes);
|
|
if (AllocatedActCtx == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the new activation context object, then stamp in the magic signature
|
|
NewActCtx = &AllocatedActCtx->ActivationContext;
|
|
AllocatedActCtx->MagicMarker = ACTCTX_MAGIC_MARKER;
|
|
|
|
AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) ActivationContextData) + ActivationContextData->AssemblyRosterOffset);
|
|
|
|
Status = RtlpInitializeAssemblyStorageMap(
|
|
&NewActCtx->StorageMap,
|
|
AssemblyRosterHeader->EntryCount,
|
|
(AssemblyRosterHeader->EntryCount > NUMBER_OF(NewActCtx->InlineStorageMapEntries)) ? NULL : NewActCtx->InlineStorageMapEntries);
|
|
if (!NT_SUCCESS(Status))
|
|
goto Exit;
|
|
|
|
UninitializeStorageMapOnExit = TRUE;
|
|
|
|
NewActCtx->RefCount = 1;
|
|
NewActCtx->Flags = 0;
|
|
NewActCtx->ActivationContextData = (PCACTIVATION_CONTEXT_DATA) ActivationContextData;
|
|
NewActCtx->NotificationRoutine = NotificationRoutine;
|
|
NewActCtx->NotificationContext = NotificationContext;
|
|
|
|
for (i=0; i<NUMBER_OF(NewActCtx->SentNotifications); i++)
|
|
NewActCtx->SentNotifications[i] = 0;
|
|
|
|
for (i=0; i<NUMBER_OF(NewActCtx->DisabledNotifications); i++)
|
|
NewActCtx->DisabledNotifications[i] = 0;
|
|
|
|
for (i=0; i<ACTCTX_RELEASE_STACK_SLOTS; i++)
|
|
for (j=0; j<ACTCTX_RELEASE_STACK_DEPTH; j++)
|
|
NewActCtx->StackTraces[i][j] = NULL;
|
|
|
|
NewActCtx->StackTraceIndex = 0;
|
|
|
|
if (g_SxsKeepActivationContextsAlive) {
|
|
RtlpPlaceActivationContextOnLiveList(NewActCtx);
|
|
}
|
|
|
|
|
|
*ActCtx = &AllocatedActCtx->ActivationContext;
|
|
AllocatedActCtx = NULL;
|
|
|
|
UninitializeStorageMapOnExit = FALSE;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Exit:
|
|
if (AllocatedActCtx != NULL) {
|
|
if (UninitializeStorageMapOnExit) {
|
|
RtlpUninitializeAssemblyStorageMap(&AllocatedActCtx->ActivationContext.StorageMap);
|
|
}
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, AllocatedActCtx);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlAddRefActivationContext(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
)
|
|
{
|
|
if ((ActCtx != NULL) &&
|
|
(!IS_SPECIAL_ACTCTX(ActCtx)) &&
|
|
(ActCtx->RefCount != LONG_MAX))
|
|
{
|
|
LONG NewRefCount = LONG_MAX;
|
|
|
|
VALIDATE_ACTCTX(ActCtx);
|
|
|
|
for (;;)
|
|
{
|
|
LONG OldRefCount = ActCtx->RefCount;
|
|
|
|
ASSERT(OldRefCount > 0);
|
|
|
|
if (OldRefCount == LONG_MAX)
|
|
{
|
|
NewRefCount = LONG_MAX;
|
|
break;
|
|
}
|
|
|
|
NewRefCount = OldRefCount + 1;
|
|
|
|
if (InterlockedCompareExchange(&ActCtx->RefCount, NewRefCount, OldRefCount) == OldRefCount)
|
|
break;
|
|
}
|
|
|
|
ASSERT(NewRefCount > 0);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlpFreeActivationContext(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
)
|
|
{
|
|
VALIDATE_ACTCTX(ActCtx);
|
|
|
|
ASSERT(ActCtx->RefCount == 0);
|
|
BOOLEAN DisableNotification = FALSE;
|
|
|
|
if (ActCtx->NotificationRoutine != NULL) {
|
|
|
|
// There's no need to check for the notification being disabled; destroy
|
|
// notifications are sent only once, so if the notification routine is not
|
|
// null, we can just call it.
|
|
(*(ActCtx->NotificationRoutine))(
|
|
ACTIVATION_CONTEXT_NOTIFICATION_DESTROY,
|
|
ActCtx,
|
|
ActCtx->ActivationContextData,
|
|
ActCtx->NotificationContext,
|
|
NULL,
|
|
&DisableNotification);
|
|
}
|
|
|
|
RtlpUninitializeAssemblyStorageMap(&ActCtx->StorageMap);
|
|
|
|
//
|
|
// This predates the MAXULONG refcount, maybe we can get rid of the the flag now?
|
|
//
|
|
if ((ActCtx->Flags & ACTIVATION_CONTEXT_NOT_HEAP_ALLOCATED) == 0) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, CONTAINING_RECORD(ActCtx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
RtlReleaseActivationContext(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
)
|
|
{
|
|
if ((ActCtx != NULL) &&
|
|
(!IS_SPECIAL_ACTCTX(ActCtx)) &&
|
|
(ActCtx->RefCount > 0) &&
|
|
(ActCtx->RefCount != LONG_MAX))
|
|
{
|
|
LONG NewRefCount = LONG_MAX;
|
|
ULONG StackTraceSlot = 0;
|
|
|
|
VALIDATE_ACTCTX(ActCtx);
|
|
|
|
// Complicated version of InterlockedDecrement that won't decrement LONG_MAX
|
|
for (;;)
|
|
{
|
|
LONG OldRefCount = ActCtx->RefCount;
|
|
ASSERT(OldRefCount != 0);
|
|
|
|
if (OldRefCount == LONG_MAX)
|
|
{
|
|
NewRefCount = OldRefCount;
|
|
break;
|
|
}
|
|
|
|
NewRefCount = OldRefCount - 1;
|
|
|
|
if (InterlockedCompareExchange(&ActCtx->RefCount, NewRefCount, OldRefCount) == OldRefCount)
|
|
break;
|
|
}
|
|
|
|
|
|
// This spiffiness will capture the last N releases of this activation context, in
|
|
// a circular list fashion. Just look at ((ActCtx->StackTraceIndex - 1) % ACTCTX_RELEASE_STACK_SLOTS)
|
|
// to find the most recent release call. This is especially handy for people who over-release.
|
|
if (g_SxsTrackReleaseStacks)
|
|
{
|
|
StackTraceSlot = ((ULONG)InterlockedIncrement((LONG*)&ActCtx->StackTraceIndex)) % ACTCTX_RELEASE_STACK_SLOTS;
|
|
RtlCaptureStackBackTrace(1, ACTCTX_RELEASE_STACK_DEPTH, ActCtx->StackTraces[StackTraceSlot], NULL);
|
|
}
|
|
|
|
if (NewRefCount == 0)
|
|
{
|
|
// If this flag is set, then we need to put "dead" activation
|
|
// contexts into this special list. This should help us diagnose
|
|
// actctx over-releasing better. Don't do this if we haven't
|
|
// initialized the list head yet.
|
|
if (g_SxsKeepActivationContextsAlive) {
|
|
RtlpMoveActCtxToFreeList(ActCtx);
|
|
}
|
|
// Otherwise, just free it.
|
|
else {
|
|
RtlpFreeActivationContext(ActCtx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlZombifyActivationContext(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if ((ActCtx == NULL) || IS_SPECIAL_ACTCTX(ActCtx))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
VALIDATE_ACTCTX(ActCtx);
|
|
|
|
if ((ActCtx->Flags & ACTIVATION_CONTEXT_ZOMBIFIED) == 0)
|
|
{
|
|
if (ActCtx->NotificationRoutine != NULL)
|
|
{
|
|
// Since disable is sent only once, there's no need to check for
|
|
// disabled notifications.
|
|
|
|
BOOLEAN DisableNotification = FALSE;
|
|
|
|
(*(ActCtx->NotificationRoutine))(
|
|
ACTIVATION_CONTEXT_NOTIFICATION_ZOMBIFY,
|
|
ActCtx,
|
|
ActCtx->ActivationContextData,
|
|
ActCtx->NotificationContext,
|
|
NULL,
|
|
&DisableNotification);
|
|
}
|
|
ActCtx->Flags |= ACTIVATION_CONTEXT_ZOMBIFIED;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
RtlpEnsureLiveDeadListsInitialized(
|
|
VOID
|
|
)
|
|
{
|
|
if (g_SxsLiveActivationContexts.Flink == NULL) {
|
|
RtlAcquirePebLock();
|
|
__try {
|
|
if (g_SxsLiveActivationContexts.Flink != NULL)
|
|
__leave;
|
|
|
|
InitializeListHead(&g_SxsLiveActivationContexts);
|
|
InitializeListHead(&g_SxsFreeActivationContexts);
|
|
}
|
|
__finally {
|
|
RtlReleasePebLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
// PRECONDITION: Called only when g_SxsKeepActivationContextsAlive is set, but not dangerous
|
|
// to call at other times, just nonperformant
|
|
VOID
|
|
FASTCALL
|
|
RtlpMoveActCtxToFreeList(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
)
|
|
{
|
|
RtlpEnsureLiveDeadListsInitialized();
|
|
|
|
RtlAcquirePebLock();
|
|
__try {
|
|
// Remove this entry from whatever list it's on. This works fine for entries that were
|
|
// never on any list as well.
|
|
RemoveEntryList(&ActCtx->Links);
|
|
|
|
// If we are about to overflow the "max dead count" and there's items on the
|
|
// dead list to clear out, start clearing out entries until we're underwater
|
|
// again.
|
|
while ((g_SxsCurrentDeadActivationContexts != 0) &&
|
|
(g_SxsCurrentDeadActivationContexts >= g_SxsMaxDeadActivationContexts)) {
|
|
|
|
LIST_ENTRY *ple2 = RemoveHeadList(&g_SxsFreeActivationContexts);
|
|
PACTIVATION_CONTEXT ActToFree = CONTAINING_RECORD(ple2, ACTIVATION_CONTEXT, Links);
|
|
|
|
// If this assert fires, then "something bad" happened while walking the list
|
|
ASSERT(ple2 != &g_SxsFreeActivationContexts);
|
|
|
|
RtlpFreeActivationContext(ActToFree);
|
|
|
|
g_SxsCurrentDeadActivationContexts--;
|
|
}
|
|
|
|
// Now, if the max dead count is greater than zero, add this to the dead list
|
|
if (g_SxsMaxDeadActivationContexts > 0) {
|
|
|
|
InsertTailList(&g_SxsFreeActivationContexts, &ActCtx->Links);
|
|
|
|
g_SxsCurrentDeadActivationContexts++;
|
|
|
|
}
|
|
// Otherwise, just free it
|
|
else {
|
|
|
|
RtlpFreeActivationContext(ActCtx);
|
|
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
RtlReleasePebLock();
|
|
}
|
|
}
|
|
|
|
// PRECONDITION: g_SxsKeepActivationContextsAlive set. Not dangerous to call when not set,
|
|
// just underperformant.
|
|
VOID
|
|
FASTCALL
|
|
RtlpPlaceActivationContextOnLiveList(
|
|
PACTIVATION_CONTEXT ActCtx
|
|
)
|
|
{
|
|
// Ensure these are initialized.
|
|
RtlpEnsureLiveDeadListsInitialized();
|
|
|
|
RtlAcquirePebLock();
|
|
__try {
|
|
InsertHeadList(&g_SxsLiveActivationContexts, &ActCtx->Links);
|
|
}
|
|
__finally {
|
|
RtlReleasePebLock();
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
RtlpFreeCachedActivationContexts(
|
|
VOID
|
|
)
|
|
{
|
|
LIST_ENTRY *ple = NULL;
|
|
|
|
// Don't bother if these were never initialized
|
|
if ((g_SxsLiveActivationContexts.Flink == NULL) || (g_SxsFreeActivationContexts.Flink == NULL))
|
|
return;
|
|
|
|
RtlAcquirePebLock();
|
|
__try {
|
|
ple = g_SxsLiveActivationContexts.Flink;
|
|
|
|
while (ple != &g_SxsLiveActivationContexts) {
|
|
PACTIVATION_CONTEXT ActCtx = CONTAINING_RECORD(ple, ACTIVATION_CONTEXT, Links);
|
|
ple = ActCtx->Links.Flink;
|
|
|
|
RemoveEntryList(&ActCtx->Links);
|
|
RtlpFreeActivationContext(ActCtx);
|
|
}
|
|
|
|
ple = g_SxsFreeActivationContexts.Flink;
|
|
|
|
while (ple != &g_SxsFreeActivationContexts) {
|
|
PACTIVATION_CONTEXT ActCtx = CONTAINING_RECORD(ple, ACTIVATION_CONTEXT, Links);
|
|
ple = ActCtx->Links.Flink;
|
|
|
|
RemoveEntryList(&ActCtx->Links);
|
|
RtlpFreeActivationContext(ActCtx);
|
|
}
|
|
}
|
|
__finally {
|
|
RtlReleasePebLock();
|
|
}
|
|
}
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
RtlpSxsBreakOnInvalidMarker(
|
|
PCACTIVATION_CONTEXT ActivationContext,
|
|
ULONG FailureCode
|
|
)
|
|
{
|
|
EXCEPTION_RECORD Exr;
|
|
|
|
Exr.ExceptionRecord = NULL;
|
|
Exr.ExceptionCode = STATUS_SXS_CORRUPTION;
|
|
Exr.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
|
Exr.NumberParameters = 3;
|
|
Exr.ExceptionInformation[0] = SXS_CORRUPTION_ACTCTX_MAGIC;
|
|
Exr.ExceptionInformation[1] = FailureCode;
|
|
Exr.ExceptionInformation[2] = (ULONG_PTR)ActivationContext;
|
|
RtlRaiseException(&Exr);
|
|
}
|
|
#endif
|
|
|
|
#if defined(__cplusplus)
|
|
} /* extern "C" */
|
|
#endif
|