singrdk/base/Kernel/Native/MemoryStorage.cpp

894 lines
25 KiB
C++

////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: MemoryStorage.cpp
//
// Note: Kernel & Process
//
#include "hal.h"
#include "eventing.h"
#ifndef SINGULARITY_KERNEL
void DebugPrintEvent(UIntPtr eventHandle)
{
Class_Microsoft_Singularity_Eventing_SystemControllerProxy::g_DebugPrintLogEntry(eventHandle);
}
#endif
uint32
MemoryStorageGetNextGeneration(PMEMORY_STORAGE Storage)
{
return (uint32)InterlockedIncrement((volatile INT32* )&Storage->Generation);
}
PMEMORY_HEADER
MemoryStorageAdvanceCursor(PMEMORY_STORAGE Storage,
PMEMORY_ZONE CurrentCursor,
uint16 size)
{
PMEMORY_ZONE NewCursor;
PMEMORY_ZONE CapturedCursor = Storage->ZoneCursor;
BOOL Reycled = false;
NewCursor = CurrentCursor;
if (NewCursor == NULL) {
NewCursor = Storage->MemoryZoneLink;
}
for (NewCursor = NewCursor->Link; NewCursor != CurrentCursor; NewCursor = NewCursor->Link) {
if (NewCursor == NULL) {
// Restart from the begining of the storage
// Make sure the policy allows this
if (Storage->Flags & MEMORY_STORAGE_FLAGS_RECYCLE_MEMORY) {
if (Reycled) {
// Every zone has been tried for this allocation
// return back the failure.
return NULL;
}
if (Storage->Flags & MEMORY_STORAGE_FLAGS_BREAK_ON_RECYCLE) {
// If we trap here, there is a request to stop before over-writing
// any buffer contents. That is about to happen, so this is the
// last chance to retrieve those contents before they are lost.
//
// Then proceed from this breakpoint.
__debugbreak();
}
Reycled = true;
NewCursor = Storage->MemoryZoneLink;
} else {
// We must return here failure, as recycling the memory for older events
// is not permited
return NULL;
}
}
if (IsZoneCompleted(NewCursor)) {
RecycleZone(NewCursor);
}
PMEMORY_HEADER Event = AllocateEventEntry(NewCursor, size);
if (Event != NULL) {
// we were successfuly in using this zone, set it as current cursor
// It is possible some other thread already did it, or even moved far ahead
// But this should not be a problem as there are no guarantees wrt. ordering
// in the storage
InterlockedCompareExchangePointer((PVOID *)&Storage->ZoneCursor,
(PVOID)NewCursor,
(PVOID)CapturedCursor);
return Event;
}
}
return NULL;
}
uint32
CaptureStackTrace(UIntPtr * StackArray, UINT MaxStackSize)
{
uint32 Index;
UIntPtr CurrentFrame = Class_Microsoft_Singularity_Isal_Isa::g_GetFramePointer();
UIntPtr CallerFrame = Class_Microsoft_Singularity_Isal_Isa::g_GetFrameCallerFrame(CurrentFrame);
Struct_Microsoft_Singularity_ProcessorContext *processorContext =
Class_Microsoft_Singularity_Processor::g_GetCurrentProcessorContext();
if ((CurrentFrame <= (UIntPtr)processorContext->cpuRecord.interruptStackBegin) &&
(CurrentFrame > (UIntPtr)processorContext->cpuRecord.interruptStackLimit)) {
// Capture the interrupte stack. Always check against the limits
// before fetching the next frame
for (Index = 0; (CallerFrame != 0) && Index < MaxStackSize; Index += 1) {
if ((CallerFrame > (UIntPtr)processorContext->cpuRecord.interruptStackBegin) ||
(CallerFrame < (UIntPtr)processorContext->cpuRecord.interruptStackLimit)) {
return Index;
}
StackArray[Index] = Class_Microsoft_Singularity_Isal_Isa::g_GetFrameReturnAddress(CallerFrame);
CallerFrame = Class_Microsoft_Singularity_Isal_Isa::g_GetFrameCallerFrame(CallerFrame);
}
return Index;
}
for (Index = 0; (CallerFrame != 0) && Index < MaxStackSize; Index += 1) {
StackArray[Index] = Class_Microsoft_Singularity_Isal_Isa::g_GetFrameReturnAddress(CallerFrame);
CallerFrame = Class_Microsoft_Singularity_Isal_Isa::g_GetFrameCallerFrame(CallerFrame);
}
return Index;
}
PMEMORY_HEADER
InternalLogRecord(UIntPtr StorageHandle,
uint32 Flags,
UIntPtr eventType,
PVOID Buffer,
uint32 size,
PVOID * ExtendedBuffer,
uint32 ExtendedSize )
{
if (StorageHandle == 0) return NULL;
PMEMORY_STORAGE Storage = (PMEMORY_STORAGE)StorageHandle;
UIntPtr Stacks[RECORD_MAXSTACKSIZE];
uint32 StackSize = 0;
uint32 allocSize = (uint32)ROUND_UP_TO_POWER2(size, sizeof(UIntPtr));
if (Flags & RECORD_STACK_TRACES) {
StackSize = CaptureStackTrace(Stacks, RECORD_MAXSTACKSIZE);
if (StackSize) {
// There is no point to save the eip of the current function in the database
// since is redundant information. Reuse instead that slot to keep the stack size
Stacks[0] = (UIntPtr)(StackSize - 1);
// Convert to memory usage
StackSize *= sizeof(UIntPtr);
} else {
// clear the flag as there is no stack available
Flags &= ~RECORD_STACK_TRACES;
}
}
PMEMORY_ZONE Zone = Storage->ZoneCursor;
if (Zone == NULL) {
Zone = Storage->MemoryZoneLink;
}
UINT32 EntrySize = GetRecordHeaderSize (Flags, StackSize);
PMEMORY_HEADER Event = AllocateEventEntry(Zone,
(uint16)(EntrySize + allocSize + ExtendedSize - sizeof(MEMORY_HEADER)));
if (Event == NULL) {
// The zone is filled up, advance the cursor to the next zone
Event = MemoryStorageAdvanceCursor(Storage, Zone,
(uint16)(EntrySize + allocSize + ExtendedSize - sizeof(MEMORY_HEADER)));
}
if (Event != NULL) {
// Copy the entry flags, which also include the layout description
Event->Flags = (uint16)Flags;
Event->Type = eventType;
// Handle the stack traces, if present
UCHAR * Dest = (UCHAR *)GetRecordInternalStructure(Event, RECORD_STACK_TRACES);
if (Dest != NULL) {
memcpy(Dest, Stacks, StackSize);
}
// Copy the remaining portion provided by the user to the buffer
if (Buffer) {
memcpy((char *)Event + EntrySize, Buffer, size);
}
if (ExtendedSize != 0) {
*ExtendedBuffer = (char *)Event + EntrySize + allocSize;
}
}
return Event;
}
PMEMORY_HEADER
InternalLogFixedRecord(UIntPtr StorageHandle,
uint32 Flags,
UIntPtr eventType,
PVOID Buffer,
uint32 size)
{
PMEMORY_HEADER entry = InternalLogRecord(StorageHandle, Flags, eventType, Buffer, size, NULL, 0);
if (entry != NULL) {
if (Flags & Class_Microsoft_Singularity_Eventing_EventSource_CAPTURE_DEBUG_PRINT){
DebugPrintEvent((UIntPtr)entry);
}
CommitEventEntry(entry);
}
return entry;
}
PMEMORY_HEADER
InternalLogVariableRecord(
bool doCommit,
UIntPtr StorageHandle,
uint32 Flags,
UIntPtr eventType,
PVOID Buffer,
uint32 size,
int32 variableItemsCount,
Struct_Microsoft_Singularity_Eventing_ArrayType * variableItems)
{
if (StorageHandle == 0) return NULL;
PVOID ExtendedBuffer;
int i;
int arrayDescriptorSize = variableItemsCount * sizeof(uint16);
int32 extendedSize = arrayDescriptorSize;
for (i = 0; i < variableItemsCount; i++) {
extendedSize += (int32)variableItems[i].Length;
if ((variableItems[i].Type == EVENT_FIELD_TYPE_string)
||
(variableItems[i].Type == EVENT_FIELD_TYPE_szChar)) {
// Account for the null terminator that ConvertToChars automatically
// inserts to the string. For szChar data, the string will also have one
// null character at the end, that has not been encounted for
extendedSize += 1;
}
}
PMEMORY_HEADER Entry = InternalLogRecord(StorageHandle,
Flags,
eventType,
Buffer,
size,
&ExtendedBuffer,
extendedSize);
if (Entry == NULL) {
return Entry;
}
if (extendedSize > 0) {
// Note the test for extendedSize. This is the only case where we are
// allowed to add something after calling InternalLogRecord. We are also required
// explicitely commit the entry when we're done
for (i = 0; i < variableItemsCount; i++) {
//
// For strings, the mechanism wil automatically extend the buffer with one
// extra character to include the null terminator. The length in the field
// should be however consistent and report the correct length of the buffer
//
if (variableItems[i].Type == EVENT_FIELD_TYPE_string) {
// Account for the null terminator that ConvertToChars automatically
// inserts to the string.
unsigned short adjustedLength = variableItems[i].Length + 1;
C_ASSERT(sizeof(adjustedLength) == sizeof(variableItems[i].Length));
memcpy(ExtendedBuffer, &adjustedLength, sizeof(adjustedLength));
ExtendedBuffer = (char *)ExtendedBuffer + sizeof(variableItems[i].Length);
// If this was a bartok string, convert it to ascii
ExtendedBuffer = ConvertToChars((char *)ExtendedBuffer,
(bartok_char *)variableItems[i].Buffer,
(int32)variableItems[i].Length);
EV_ASSERT(ExtendedBuffer <= (PVOID)((char*)Entry + Entry->Size ));
} else if (variableItems[i].Type == EVENT_FIELD_TYPE_szChar) {
// Account for the null terminator that is automatically
// inserted to the string.
unsigned short adjustedLength = variableItems[i].Length + 1;
//
// Save the total size in bytes and save it to the entry. Move the pointer forward
//
C_ASSERT(sizeof(adjustedLength) == sizeof(variableItems[i].Length));
memcpy(ExtendedBuffer, &adjustedLength, sizeof(adjustedLength));
ExtendedBuffer = (char *)ExtendedBuffer + sizeof(adjustedLength);
//
// Copy now the actual content of the buffer
//
memcpy(ExtendedBuffer, variableItems[i].Buffer, (int32)variableItems[i].Length);
ExtendedBuffer = (char *)ExtendedBuffer + variableItems[i].Length;
*(char *)ExtendedBuffer = (char)0;
ExtendedBuffer = (char *)ExtendedBuffer + 1;
} else {
//
// Save the length of the data and advance the pointer
//
memcpy(ExtendedBuffer, &variableItems[i].Length, sizeof(variableItems[i].Length));
ExtendedBuffer = (char *)ExtendedBuffer + sizeof(variableItems[i].Length);
// nothing else to do here, just copy the content and advance the pointer
memcpy(ExtendedBuffer, variableItems[i].Buffer, (int32)variableItems[i].Length);
ExtendedBuffer = (char *)ExtendedBuffer + variableItems[i].Length;
}
EV_ASSERT(ExtendedBuffer <= (PVOID)((char*)Entry + Entry->Size ));
}
}
if (Flags & Class_Microsoft_Singularity_Eventing_EventSource_CAPTURE_DEBUG_PRINT){
DebugPrintEvent((UIntPtr)Entry);
}
if (doCommit) {
CommitEventEntry(Entry);
}
return Entry;
}
UIntPtr
OpenLoggingStorage(UIntPtr sourceHandle, uint32 * flags)
{
if (sourceHandle == 0) return 0;
PSOURCE_DESCRIPTOR source = HANDLE_TO_SOURCE(sourceHandle);
if (((source->ControlFlags & (*flags)) >> 16) == 0) return 0;
*flags |= source->ControlFlags;
return source->StorageHandle;
}
PMEMORY_ZONE
GetNextZone(PQUERY_VIEW view)
{
if (view->StartZone == NULL) {
return NULL;
}
for (;;) {
if (view->Forward) {
view->CurrentZone = view->CurrentZone->Link;
if (view->CurrentZone == NULL) {
view->CurrentZone = view->Storage->MemoryZoneLink;
}
} else {
view->CurrentZone = view->CurrentZone->BkLink;
if (view->CurrentZone == NULL) {
view->CurrentZone = view->Storage->BkLink;
}
}
if (view->CurrentZone == view->StartZone) {
return NULL;
}
// ??? handle the generation wrap
if (view->CurrentZone->Generation <= view->QueryGeneration) {
view->CurrentEntryIndex = 0;
view->ZoneGeneration = view->CurrentZone->Generation;
return view->CurrentZone;
}
}
}
PQUERY_VIEW
CreateQuery(UIntPtr storageHandle, bool forward)
{
PQUERY_VIEW queryView = AllocateQueryView( );
if (queryView) {
queryView->Storage = HANDLE_TO_STORAGE(storageHandle);
queryView->Forward = forward;
queryView->QueryGeneration = queryView->Storage->Generation;
queryView->CurrentZone = NULL;
queryView->ZoneGeneration = 0;
queryView->CurrentEntry = NULL;
queryView->CurrentEntryIndex = 0;
queryView->EndOfBuffer = false;
if (forward) {
queryView->StartZone = queryView->Storage->ZoneCursor;
if (queryView->StartZone != NULL) {
queryView->StartZone = queryView->StartZone->Link;
}
if (queryView->StartZone == NULL) {
queryView->StartZone = queryView->Storage->MemoryZoneLink;
}
} else {
queryView->StartZone = queryView->Storage->ZoneCursor;
if (queryView->StartZone == NULL) {
queryView->StartZone = queryView->Storage->BkLink;
}
}
queryView->CurrentZone = queryView->StartZone;
queryView->QueryReset = true;
}
return queryView;
}
PMEMORY_HEADER
GetNextStorageEntry(PQUERY_VIEW queryView)
{
PMEMORY_HEADER Entry;
if (queryView->EndOfBuffer) {
return NULL;
}
if (queryView->CurrentEntry) {
Entry = GetNextEntry(queryView);
if (Entry) {
return Entry;
}
}
PMEMORY_ZONE zone;
if (queryView->QueryReset) {
zone = queryView->StartZone;
queryView->QueryReset = false;
queryView->ZoneGeneration = zone->Generation;
queryView->CurrentEntryIndex = 0;
} else {
zone = GetNextZone(queryView);
}
while (zone != NULL) {
queryView->CurrentEntry = GetFirstEntry(zone, queryView->Forward);
if (queryView->CurrentEntry) {
return queryView->CurrentEntry;
}
zone = GetNextZone(queryView);
}
queryView->EndOfBuffer = true;
return NULL;
}
//
// ABI calls for Eventing.MemoryStorage
//
UIntPtr Class_Microsoft_Singularity_Eventing_MemoryStorage::
g_MemoryStorageCreateImpl(uint32 Flags, UCHAR * InitialBuffer, uint32 BufferSize, uint32 ZoneSize)
{
if (BufferSize <= sizeof(MEMORY_STORAGE)) {
return 0;
}
PMEMORY_STORAGE Storage = (PMEMORY_STORAGE)InitialBuffer;
Storage->StorageSize = 0;
Storage->MemoryZoneLink = NULL;
Storage->ZoneCursor = NULL;
Storage->Flags = Flags;
Storage->BkLink = NULL;
Storage->Generation = 0;
ZoneSize = (uint32)ROUND_UP_TO_POWER2(ZoneSize, EV_ZONE_ALIGNMENT);
if (((Flags & 0xF) == MEMORY_STORAGE_FLAGS_PERMANENT)
||
((Flags & 0xF) == MEMORY_STORAGE_FLAGS_ACTIVE_STORAGE) ) {
ZoneSize = BufferSize;
}
if (ZoneSize < sizeof(MEMORY_ZONE)) {
ZoneSize = BufferSize / EV_DEFAULT_ZONE_BUFFER_RATIO;
ZoneSize = (uint32)ROUND_UP_TO_POWER2(ZoneSize, EV_ZONE_ALIGNMENT);
}
if (ZoneSize > EV_MAXIMUM_ZONE_SIZE) {
Storage->DefaultZoneSize = EV_MAXIMUM_ZONE_SIZE;
} else {
Storage->DefaultZoneSize = ZoneSize;
}
Storage->ZoneCount = 0;
InitialBuffer = (UCHAR *)(Storage + 1);
InitialBuffer = (UCHAR *)ROUND_UP_TO_POWER2(InitialBuffer, EV_ZONE_ALIGNMENT);
Class_Microsoft_Singularity_Eventing_MemoryStorage::g_MemoryStorageRegisterBufferImpl(
(UIntPtr)Storage,
InitialBuffer,
(uint32)(BufferSize - ((uint8 *)InitialBuffer - (uint8 *)Storage)));
Storage->ZoneCursor = Storage->MemoryZoneLink;
return (UIntPtr)Storage;
}
void
Class_Microsoft_Singularity_Eventing_MemoryStorage::
g_MemoryStorageRegisterBufferImpl(UIntPtr StorageHandle, UCHAR * Buffer, uint32 BufferSize)
{
PMEMORY_STORAGE Storage = (PMEMORY_STORAGE)StorageHandle;
PMEMORY_ZONE LastZone = NULL;
PMEMORY_ZONE ZoneChain = NULL;
PMEMORY_ZONE TempZone;
PMEMORY_ZONE LastExistingZone = Storage->BkLink;
InterlockedExchangeAdd((volatile INT32 *)&Storage->StorageSize, BufferSize);
if ((Storage->DefaultZoneSize != 0) && (BufferSize > Storage->DefaultZoneSize)) {
// We have to split the larger chunk in multiple zones
uint32 MaxZone = BufferSize / Storage->DefaultZoneSize;
for (uint32 i = 0; i < MaxZone; i++) {
TempZone = InitializeMemoryZone(Buffer, Storage->DefaultZoneSize, StorageHandle);
EV_ASSERT(TempZone != NULL);
InterlockedIncrement((volatile INT32* )&Storage->ZoneCount);
if (ZoneChain == NULL) {
ZoneChain = TempZone;
}
// Link the zones togeather. Note the chain is not yet published outside
// until is pushed to the memory storage list eventually
if (LastZone) {
LastZone->Link = TempZone;
}
TempZone->BkLink = LastZone;
LastZone = TempZone;
Buffer = (UCHAR *)Buffer + Storage->DefaultZoneSize;
BufferSize -= Storage->DefaultZoneSize;
}
}
TempZone = InitializeMemoryZone(Buffer, BufferSize, StorageHandle);
if (TempZone != NULL) {
InterlockedIncrement((volatile INT32 *)&Storage->ZoneCount);
// Here the remining portion might be too small for a whole zone.
if (ZoneChain == NULL) {
ZoneChain = TempZone;
}
// Link the zones togeather. Note the chain is not yet published outside
// until is pushed to the memory storage list eventually
if (LastZone) {
LastZone->Link = TempZone;
}
TempZone->BkLink = LastZone;
LastZone = TempZone;
}
if (LastZone != NULL) {
LastZone->Link = NULL;
if (LastExistingZone == NULL) {
// The existing list is empty. Insert the new one to the head
ZoneChain->BkLink = NULL;
Storage->BkLink = LastZone;
Storage->MemoryZoneLink = ZoneChain;
} else {
LastExistingZone->Link = ZoneChain;
ZoneChain->BkLink = LastExistingZone;
}
Storage->BkLink = LastZone;
}
}
UIntPtr Class_Microsoft_Singularity_Eventing_EventSource::
g_LogSourceEntryImpl(UIntPtr sourceHandle,
uint32 flags,
UIntPtr eventType,
uint8 * Buffer,
int32 size)
{
UIntPtr storageHandle = OpenLoggingStorage(sourceHandle, &flags);
return (UIntPtr)InternalLogFixedRecord(storageHandle,
flags,
eventType,
Buffer,
size);
}
UIntPtr Class_Microsoft_Singularity_Eventing_EventSource::
g_LogSourceEntryImpl(UIntPtr sourceHandle,
uint32 flags,
UIntPtr eventType,
uint8 * Buffer,
int32 size,
int32 arraysCount,
Struct_Microsoft_Singularity_Eventing_ArrayType * arrays)
{
UIntPtr storageHandle = OpenLoggingStorage(sourceHandle, &flags);
return (UIntPtr)InternalLogVariableRecord(true,
storageHandle,
flags,
eventType,
Buffer,
size,
arraysCount,
arrays);
}
uint32 Class_Microsoft_Singularity_Eventing_MemoryStorage::
g_GetMemoryStorageOveheadImpl()
{
// Determine the overhead in the pesimistic case
return sizeof(MEMORY_STORAGE) +
(sizeof(MEMORY_ZONE) + EV_ZONE_ALIGNMENT) * EV_DEFAULT_ZONE_BUFFER_RATIO +
sizeof(MEMORY_HEADER) * EV_DEFAULT_ZONE_BUFFER_RATIO;
}
UIntPtr Class_Microsoft_Singularity_Eventing_MemoryStorage::
g_CreateQueryViewImpl(UIntPtr storageHandle, bool forward)
{
return (UIntPtr)CreateQuery(storageHandle, forward);
}
void Class_Microsoft_Singularity_Eventing_MemoryStorage::
g_DeleteQueryViewImpl(UIntPtr queryHandle)
{
UnRegisterQueryView((PQUERY_VIEW)queryHandle);
}
UIntPtr Class_Microsoft_Singularity_Eventing_MemoryStorage::
g_GetNextEntryImpl(UIntPtr queryHandle,
UIntPtr * typeHandle,
uint32 * userOffset,
uint8 * buffer,
uint16 bufferSize)
{
PQUERY_VIEW view = (PQUERY_VIEW)queryHandle;
PMEMORY_HEADER entry = GetNextStorageEntry(view);
if (entry != NULL) {
*typeHandle = entry->Type;
void * src = GetUserRecordStructure(entry);
if (entry->Size < bufferSize) {
bufferSize = entry->Size;
}
memcpy(buffer, entry , bufferSize);
*userOffset = (uint32)((ULONG_PTR)src - (ULONG_PTR)entry);
}
return (UIntPtr) entry;
}
UIntPtr Class_Microsoft_Singularity_Eventing_MemoryStorage::
g_WalkEventDescriptorImpl(UIntPtr eventHandle,
UIntPtr currentField,
uint16 * offset,
uint16 * type,
bartok_char * bufferName,
uint16 bufferSize)
{
if (eventHandle == 0) {
eventHandle = Handle_MEMORY_HEADER;
}
PMEMORY_HEADER Entry = HANDLE_TO_HEADER(eventHandle);
EV_ASSERT(Entry->Flags == RECORD_EVENT_TYPE);
PEVENT_DESCRIPTOR eventDescriptor = (PEVENT_DESCRIPTOR)GetUserRecordStructure(Entry);
PEVENT_FIELD_DESCRIPTOR field = NULL;
char * src;
if (currentField == 0) {
src = GetExtendedString(eventHandle, 1);
} else if (currentField == eventHandle) {
// start now with the fields inside the event
field = eventDescriptor->fieldsLink;
} else {
field = (PEVENT_FIELD_DESCRIPTOR)(currentField);
field = field->fieldsLink;
if (field == NULL) {
return 0;
}
}
if (field == NULL) {
// This is refers the event descriptor itself.
// The type returned will be zero, the only meaningful information
// will be the event name
*offset = 0;
*type = 0;
} else {
*offset = field->Offset;
*type = field->Type;
src = GetExtendedString((UIntPtr)((PMEMORY_HEADER)field - 1), 1);
}
if ((bufferName != NULL) && (bufferSize != 0)) {
while ((bufferSize != 0) && (*src)) {
*bufferName++ = *src++;
bufferSize -= sizeof(bartok_char);
}
if (bufferSize == 0) {
// Move back one position to insert the null terminator.
// We have at least this character in the buffer due to the test two levels above
bufferSize -= sizeof(bartok_char);
}
*bufferName = 0;
}
if (field == NULL) {
return eventHandle;
}
return (UIntPtr)field;
}
//
///////////////////////////////////////////////////////////////// End of File.