mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
455 lines
8.8 KiB
455 lines
8.8 KiB
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
opaqueidp.h
|
|
|
|
Abstract:
|
|
|
|
This module contains declarations private to the opaque ID table. These
|
|
declarations are placed in a separate .H file to make it easier to access
|
|
them from within the kernel debugger extension DLL.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 10-Sep-1999
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#ifndef _OPAQUEIDP_H_
|
|
#define _OPAQUEIDP_H_
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
//
|
|
// The internal structure of an HTTP_OPAQUE_ID.
|
|
//
|
|
// N.B. This structure must be EXACTLY the same size as an HTTP_OPAQUE_ID!
|
|
//
|
|
|
|
#define PROCESSOR_BIT_WIDTH 6
|
|
#define FIRST_INDEX_BIT_WIDTH 18
|
|
#define SECOND_INDEX_BIT_WIDTH 8
|
|
#define OPAQUE_ID_CYCLIC_BIT_WIDTH 29
|
|
#define OPAQUE_ID_TYPE_BIT_WIDTH 3
|
|
|
|
typedef union _UL_OPAQUE_ID_INTERNAL
|
|
{
|
|
HTTP_OPAQUE_ID OpaqueId;
|
|
|
|
struct
|
|
{
|
|
union
|
|
{
|
|
ULONG Index;
|
|
|
|
struct
|
|
{
|
|
ULONG Processor : PROCESSOR_BIT_WIDTH;
|
|
ULONG FirstIndex : FIRST_INDEX_BIT_WIDTH;
|
|
ULONG SecondIndex : SECOND_INDEX_BIT_WIDTH;
|
|
};
|
|
};
|
|
|
|
union
|
|
{
|
|
ULONG Cyclic;
|
|
|
|
struct
|
|
{
|
|
ULONG OpaqueIdCyclic : OPAQUE_ID_CYCLIC_BIT_WIDTH;
|
|
ULONG OpaqueIdType : OPAQUE_ID_TYPE_BIT_WIDTH;
|
|
};
|
|
};
|
|
};
|
|
|
|
} UL_OPAQUE_ID_INTERNAL, *PUL_OPAQUE_ID_INTERNAL;
|
|
|
|
C_ASSERT( sizeof(HTTP_OPAQUE_ID) == sizeof(UL_OPAQUE_ID_INTERNAL) );
|
|
C_ASSERT( 8 * sizeof(HTTP_OPAQUE_ID) == (PROCESSOR_BIT_WIDTH + \
|
|
FIRST_INDEX_BIT_WIDTH + \
|
|
SECOND_INDEX_BIT_WIDTH + \
|
|
OPAQUE_ID_CYCLIC_BIT_WIDTH + \
|
|
OPAQUE_ID_TYPE_BIT_WIDTH \
|
|
));
|
|
C_ASSERT((1 << PROCESSOR_BIT_WIDTH) >= MAXIMUM_PROCESSORS);
|
|
|
|
|
|
//
|
|
// A per-entry opaque ID lock.
|
|
//
|
|
|
|
#define OPAQUE_ID_DPC
|
|
|
|
#ifdef OPAQUE_ID_DPC
|
|
typedef KSPIN_LOCK UL_OPAQUE_ID_LOCK, *PUL_OPAQUE_ID_LOCK;
|
|
|
|
__inline
|
|
VOID
|
|
FASTCALL
|
|
UlpInitializeOpaqueIdLock(
|
|
IN PUL_OPAQUE_ID_LOCK pLock
|
|
)
|
|
{
|
|
KeInitializeSpinLock( pLock );
|
|
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
FASTCALL
|
|
UlpAcquireOpaqueIdLock(
|
|
IN PUL_OPAQUE_ID_LOCK pLock,
|
|
OUT PKIRQL pOldIrql
|
|
)
|
|
{
|
|
KeAcquireSpinLock( pLock, pOldIrql );
|
|
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
FASTCALL
|
|
UlpReleaseOpaqueIdLock(
|
|
IN PUL_OPAQUE_ID_LOCK pLock,
|
|
IN KIRQL OldIrql
|
|
)
|
|
{
|
|
KeReleaseSpinLock( pLock, OldIrql );
|
|
|
|
}
|
|
#else
|
|
typedef volatile LONG UL_OPAQUE_ID_LOCK, *PUL_OPAQUE_ID_LOCK;
|
|
|
|
__inline
|
|
VOID
|
|
FASTCALL
|
|
UlpInitializeOpaqueIdLock(
|
|
IN PUL_OPAQUE_ID_LOCK pLock
|
|
)
|
|
{
|
|
*pLock = 0;
|
|
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
FASTCALL
|
|
UlpAcquireOpaqueIdLock(
|
|
IN PUL_OPAQUE_ID_LOCK pLock,
|
|
OUT PKIRQL pOldIrql
|
|
)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
while (*pLock == 1)
|
|
{
|
|
PAUSE_PROCESSOR
|
|
}
|
|
|
|
if (0 == InterlockedCompareExchange( pLock, 1, 0 ))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
FASTCALL
|
|
UlpReleaseOpaqueIdLock(
|
|
IN PUL_OPAQUE_ID_LOCK pLock,
|
|
IN KIRQL OldIrql
|
|
)
|
|
{
|
|
ASSERT( *pLock == 1 );
|
|
|
|
InterlockedExchange( pLock, 0 );
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// A second-level table entry.
|
|
//
|
|
// Note that FreeListEntry and pContext are in an anonymous
|
|
// union to save space; an entry is either on the free list or in use,
|
|
// so only one of these fields will be used at a time.
|
|
//
|
|
// Also note that Cyclic is in a second anonymous union. It's overlayed
|
|
// with FirstLevelIndex (which is basically the second-level table's
|
|
// index in the first-level table) and ID type (used to distinguish
|
|
// free entries from in-use entries).
|
|
//
|
|
|
|
#define SECOND_LEVEL_TABLE_SIZE 256
|
|
|
|
C_ASSERT( SECOND_LEVEL_TABLE_SIZE == 1 << SECOND_INDEX_BIT_WIDTH );
|
|
|
|
typedef struct _UL_OPAQUE_ID_TABLE_ENTRY
|
|
{
|
|
//
|
|
// NonPagedPool
|
|
//
|
|
|
|
union
|
|
{
|
|
//
|
|
// To ensure FreeListEntry is aligned on 8-byte boundary.
|
|
//
|
|
|
|
ULONGLONG Alignment;
|
|
|
|
struct
|
|
{
|
|
union
|
|
{
|
|
//
|
|
// An entry to the global ID table's free ID list.
|
|
//
|
|
|
|
SINGLE_LIST_ENTRY FreeListEntry;
|
|
|
|
//
|
|
// Context associated with the opaque ID.
|
|
//
|
|
|
|
PVOID pContext;
|
|
};
|
|
|
|
//
|
|
// A per-entry ID cyclic that guarantees we can generate
|
|
// 2 ^ OPAQUE_ID_CYCLIC_BIT_WIDTH of opaque IDs from the
|
|
// current entry without repeating. This gives us extra
|
|
// protection than using a global ID cyclic.
|
|
//
|
|
|
|
ULONG EntryOpaqueIdCyclic;
|
|
};
|
|
};
|
|
|
|
//
|
|
// A per-entry lock that protects the entry.
|
|
//
|
|
|
|
UL_OPAQUE_ID_LOCK Lock;
|
|
|
|
//
|
|
// The ID index for the opaque ID when the entry is free or the cyclic
|
|
// when the entry is in use.
|
|
//
|
|
|
|
union
|
|
{
|
|
union
|
|
{
|
|
ULONG Index;
|
|
|
|
struct
|
|
{
|
|
ULONG Processor : PROCESSOR_BIT_WIDTH;
|
|
ULONG FirstIndex : FIRST_INDEX_BIT_WIDTH;
|
|
ULONG Reserved : SECOND_INDEX_BIT_WIDTH;
|
|
};
|
|
};
|
|
|
|
union
|
|
{
|
|
ULONG Cyclic;
|
|
|
|
struct
|
|
{
|
|
ULONG OpaqueIdCyclic : OPAQUE_ID_CYCLIC_BIT_WIDTH;
|
|
ULONG OpaqueIdType : OPAQUE_ID_TYPE_BIT_WIDTH;
|
|
};
|
|
};
|
|
};
|
|
|
|
} UL_OPAQUE_ID_TABLE_ENTRY, *PUL_OPAQUE_ID_TABLE_ENTRY;
|
|
|
|
|
|
//
|
|
// We keep a per-processor first-level ID tables. A single table is a
|
|
// major scalability bottleneck on SMP machines. The size of the first-level
|
|
// table is controlled by a registry setting.
|
|
//
|
|
|
|
#if DBG
|
|
#define OPAQUE_ID_INSTRUMENTATION
|
|
#endif
|
|
|
|
typedef struct _UL_OPAQUE_ID_TABLE
|
|
{
|
|
//
|
|
// A list of free IDs available on this table.
|
|
//
|
|
|
|
SLIST_HEADER FreeOpaqueIdSListHead;
|
|
|
|
//
|
|
// An arrary of second-level ID table entries.
|
|
//
|
|
|
|
PUL_OPAQUE_ID_TABLE_ENTRY *FirstLevelTable;
|
|
|
|
//
|
|
// The corresponding CPU this table represents.
|
|
//
|
|
|
|
UCHAR Processor;
|
|
|
|
//
|
|
// The lock really only protects FirstLevelTableInUse.
|
|
//
|
|
|
|
UL_SPIN_LOCK Lock;
|
|
|
|
//
|
|
// The current number of first-level tables allocated.
|
|
//
|
|
|
|
ULONG FirstLevelTableInUse;
|
|
|
|
//
|
|
// The maximum size we can grow for the first-level tables.
|
|
//
|
|
|
|
ULONG FirstLevelTableSize;
|
|
|
|
#ifdef OPAQUE_ID_INSTRUMENTATION
|
|
LONGLONG NumberOfAllocations;
|
|
LONGLONG NumberOfFrees;
|
|
LONGLONG NumberOfTotalGets;
|
|
LONGLONG NumberOfSuccessfulGets;
|
|
#endif
|
|
} UL_OPAQUE_ID_TABLE, *PUL_OPAQUE_ID_TABLE;
|
|
|
|
|
|
//
|
|
// Necessary to ensure our array of UL_OPAQUE_ID_TABLE structures is
|
|
// cache aligned.
|
|
//
|
|
|
|
typedef union _UL_ALIGNED_OPAQUE_ID_TABLE
|
|
{
|
|
UL_OPAQUE_ID_TABLE OpaqueIdTable;
|
|
|
|
UCHAR CacheAlignment[(sizeof(UL_OPAQUE_ID_TABLE) + UL_CACHE_LINE - 1) & ~(UL_CACHE_LINE - 1)];
|
|
|
|
} UL_ALIGNED_OPAQUE_ID_TABLE, *PUL_ALIGINED_OPAQUE_ID_TABLE;
|
|
|
|
|
|
//
|
|
// An inline function that maps a specified HTTP_OPAQUE_ID to the
|
|
// corresponding ID table entry.
|
|
//
|
|
|
|
extern UL_ALIGNED_OPAQUE_ID_TABLE g_UlOpaqueIdTable[];
|
|
|
|
__inline
|
|
BOOLEAN
|
|
FASTCALL
|
|
UlpExtractIndexFromOpaqueId(
|
|
IN HTTP_OPAQUE_ID OpaqueId,
|
|
OUT PULONG pProcessor,
|
|
OUT PULONG pFirstIndex,
|
|
OUT PULONG pSecondIndex
|
|
)
|
|
{
|
|
UL_OPAQUE_ID_INTERNAL InternalId;
|
|
PUL_OPAQUE_ID_TABLE pOpaqueIdTable;
|
|
|
|
InternalId.OpaqueId = OpaqueId;
|
|
|
|
//
|
|
// Verify the processor portion of the index.
|
|
//
|
|
|
|
*pProcessor = InternalId.Processor;
|
|
|
|
if (*pProcessor >= g_UlNumberOfProcessors)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Verify the first-level index.
|
|
//
|
|
|
|
pOpaqueIdTable = &g_UlOpaqueIdTable[*pProcessor].OpaqueIdTable;
|
|
*pFirstIndex = InternalId.FirstIndex;
|
|
|
|
if (*pFirstIndex >= pOpaqueIdTable->FirstLevelTableInUse)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Second-level index is always valid since we only allocated 8-bits.
|
|
//
|
|
|
|
ASSERT( InternalId.SecondIndex < SECOND_LEVEL_TABLE_SIZE );
|
|
|
|
*pSecondIndex = InternalId.SecondIndex;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
__inline
|
|
PUL_OPAQUE_ID_TABLE_ENTRY
|
|
FASTCALL
|
|
UlpMapOpaqueIdToTableEntry(
|
|
IN HTTP_OPAQUE_ID OpaqueId
|
|
)
|
|
{
|
|
PUL_OPAQUE_ID_TABLE pOpaqueIdTable;
|
|
ULONG Processor;
|
|
ULONG FirstIndex;
|
|
ULONG SecondIndex;
|
|
|
|
if (UlpExtractIndexFromOpaqueId(
|
|
OpaqueId,
|
|
&Processor,
|
|
&FirstIndex,
|
|
&SecondIndex
|
|
))
|
|
{
|
|
pOpaqueIdTable = &g_UlOpaqueIdTable[Processor].OpaqueIdTable;
|
|
return pOpaqueIdTable->FirstLevelTable[FirstIndex] + SecondIndex;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
|
|
NTSTATUS
|
|
UlpExpandOpaqueIdTable(
|
|
IN PUL_OPAQUE_ID_TABLE pOpaqueIdTable,
|
|
IN LONG CapturedFirstTableInUse
|
|
);
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}; // extern "C"
|
|
#endif
|
|
|
|
#endif // _OPAQUEIDP_H_
|
|
|