////////////////////////////////////////////////////////////////////////////////
//
//  Microsoft Research Singularity
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  File: EventController.cpp
//
//  Note:   Kernel & Process
//

#include "hal.h"
#include "eventing.h"

bool GetTracingHandles(UIntPtr * storageHandle,
                       UIntPtr * sourceHandle,
                       UIntPtr * eventTypeHandle);

bool GetMonitoringHandles(UIntPtr * storageHandle,
                          UIntPtr * sourceHandle,
                          UIntPtr * eventTypeHandle);

SOURCE_CONTROLLER SourceController = {NULL, NULL, NULL, NULL, NULL};

char * ConvertToChars(char * dst, bartok_char *src, int32 length)
{
    if (src != NULL) {
        bartok_char *end = src + length;

        while (src < end) {
            *dst++ = (uint8)*src++;
        }
    }
    *dst++ = '\0';
    return dst;
}

void ConvertToChars(char * dst, Class_System_String *arg)
{
    ConvertToChars(dst, &arg->m_firstChar, arg->m_stringLength);
}

void
RegisterRepositoryStorage(PMEMORY_STORAGE storage)
{
    EV_ASSERT(SourceController.SourceRepository == NULL);
    SourceController.SourceRepository = storage;
    RegisterNativeTypes();
}

bool
RegisterStorage(PMEMORY_STORAGE storage)
{
    //  Note the caller of this function needs to assure mutual exclusion

    if (SourceController.SourceRepository == NULL) {

        //  The first storage registered needs to be the type repository

        RegisterRepositoryStorage(storage);

    } else {

        storage->Link = SourceController.StorageList;
        SourceController.StorageList = storage;
    }

    return true;
}


void
UnRegisterStorage(PMEMORY_STORAGE storage)
{
    //  Note the caller of this function needs to assure mutual exclusion

    PMEMORY_STORAGE tmpStorage = SourceController.StorageList;

    EV_ASSERT(tmpStorage != NULL);

    if (tmpStorage == storage) {

        SourceController.StorageList = tmpStorage->Link;

    } else {

        while (tmpStorage->Link != storage) {

            tmpStorage = tmpStorage->Link;
        }

        if (tmpStorage->Link == storage) {

            tmpStorage->Link = storage->Link;
        }
    }
}

void
RegisterExternalController(PEXTERNAL_CONTROLLER_DESCRIPTOR controller)
{
    //  Note the caller of this function needs to assure mutual exclusion

    controller->Link = SourceController.ExternalControllers;
    SourceController.ExternalControllers = controller;
}

void
UnRegisterExternalController(PEXTERNAL_CONTROLLER_DESCRIPTOR controller)
{
    //  Note the caller of this function needs to assure mutual exclusion

    PEXTERNAL_CONTROLLER_DESCRIPTOR tmpController = SourceController.ExternalControllers;

    EV_ASSERT(tmpController != NULL);

    if (tmpController == controller) {

        SourceController.ExternalControllers = tmpController->Link;

    } else {

        while (tmpController->Link != controller) {

            tmpController = tmpController->Link;
        }

        if (tmpController->Link == controller) {

            tmpController->Link = controller->Link;
        }
    }

    //  Insert it to the free llist

    controller->Link = SourceController.FreeControllerList;
    SourceController.FreeControllerList = controller;

}

void
RegisterQueryView(PQUERY_VIEW queryView)
{
    //  Note the caller of this function needs to assure mutula exclusion

    queryView->Link = SourceController.QueryViews;
    SourceController.QueryViews = queryView;
}

void
UnRegisterQueryView(PQUERY_VIEW queryView)
{
    //  Note the caller of this function needs to assure mutual exclusion

    PQUERY_VIEW tmpQueryView = SourceController.QueryViews;

    EV_ASSERT(tmpQueryView != NULL);

    if (tmpQueryView == queryView) {

        SourceController.QueryViews = tmpQueryView->Link;

    } else {

        while (tmpQueryView->Link != queryView) {

            tmpQueryView = tmpQueryView->Link;
        }

        if (tmpQueryView->Link == queryView) {

            tmpQueryView->Link = queryView->Link;
        }
    }

    //  Insert it to the free llist

    queryView->Link = SourceController.QueryViews;
    SourceController.FreeQueryViews = queryView;

}

PQUERY_VIEW AllocateQueryView( )
{
    if (SourceController.FreeQueryViews != NULL) {

        PQUERY_VIEW queryView = SourceController.FreeQueryViews;
        SourceController.FreeQueryViews = queryView->Link;
        RegisterQueryView(queryView);
        return queryView;
    }

    QUERY_VIEW source;

    PMEMORY_HEADER Entry = InternalLogFixedRecord( GetLocalRepositoryHandle(),
        RECORD_EVENT_CONTROLLER,
        0,
        &source,
        sizeof(source));

    if (Entry == NULL) {
        return NULL;
    }

    PQUERY_VIEW newSource = (PQUERY_VIEW)GetUserRecordStructure(Entry);
    RegisterQueryView(newSource);
    return newSource;
}



bool
RegisterSource(PSOURCE_DESCRIPTOR newSource)
{
    //  Note the caller of this function needs to assure mutual exclusion

    newSource->Link = (UIntPtr)SourceController.SourceDescriptors;
    SourceController.SourceDescriptors = newSource;

    return true;
}


//
//  ABI entries
//

UIntPtr Class_Microsoft_Singularity_Eventing_LocalController::
    g_FetchLocalStorage()
{
    return (UIntPtr)GetLocalRepository();
}

bool Class_Microsoft_Singularity_Eventing_LocalController::g_SetRepositoryStorage(UIntPtr storageHandle)
{
    if (SourceController.SourceRepository != NULL) {
        return false;
    }

    RegisterRepositoryStorage(HANDLE_TO_STORAGE(storageHandle));
    return true;
}


UIntPtr Class_Microsoft_Singularity_Eventing_LocalController::
    g_RegisterEventDescriptorInternal(Class_System_String * eventName,
                                      Class_System_String * eventDescription)
{
    return (UIntPtr)RegisterEventDescriptorImplementation(Class_Microsoft_Singularity_Eventing_DataType___string,
                                                          &eventName->m_firstChar,
                                                          eventName->m_stringLength,
                                                          &eventDescription->m_firstChar,
                                                          eventDescription->m_stringLength);
}

UIntPtr Class_Microsoft_Singularity_Eventing_LocalController::
    g_RegisterEventFieldInternal(UIntPtr eventHandle,
        Class_System_String * fieldName,
        uint16 offset,
        uint16 type)
{
    return (UIntPtr) RegisterFieldDescriptorImplementation(
                            Class_Microsoft_Singularity_Eventing_DataType___string,
                            HANDLE_TO_HEADER(eventHandle),
                            &fieldName->m_firstChar,
                            fieldName->m_stringLength,
                            offset,
                            type);
}

UIntPtr Class_Microsoft_Singularity_Eventing_LocalController::
    g_RegisterEventGenericFieldInternal(UIntPtr eventHandle,
                                        Class_System_String * fieldName,
                                        uint16 offset,
                                        uint16 size,
                                        UIntPtr typeFieldDescriptor)
{
    return (UIntPtr)RegisterGenericFieldDescriptorImplementation(
                     Class_Microsoft_Singularity_Eventing_DataType___string,
                     HANDLE_TO_HEADER(eventHandle),
                     &fieldName->m_firstChar,
                     fieldName->m_stringLength,
                     offset,
                     size,
                     typeFieldDescriptor);
}

UIntPtr Class_Microsoft_Singularity_Eventing_LocalController::
    g_RegisterEnumDescriptorInternal(Class_System_String * name,
                                     uint16 type)
{
    return (UIntPtr)RegisterEnumDescriptorImplementation(
                        Class_Microsoft_Singularity_Eventing_DataType___string,
                        &name->m_firstChar,
                        name->m_stringLength,
                        type);
}

UIntPtr Class_Microsoft_Singularity_Eventing_LocalController::
    g_RegisterValueDescriptorInternal(UIntPtr eventHandle,
                                      Class_System_String * name,
                                      uint64 value,
                                      uint8 flagLetter)
{
    return (UIntPtr)RegisterValueDescriptorImplementation(
                         Class_Microsoft_Singularity_Eventing_DataType___string,
                         HANDLE_TO_HEADER(eventHandle),
                         &name->m_firstChar,
                         name->m_stringLength,
                         value,
                         flagLetter);
}


bool
Class_Microsoft_Singularity_Eventing_LocalController::g_RegisterStorageImpl(UIntPtr storageHandle)
{
  return RegisterStorage(HANDLE_TO_STORAGE(storageHandle));
}
void
Class_Microsoft_Singularity_Eventing_LocalController::g_UnRegisterStorageImpl(UIntPtr storageHandle)
{
  UnRegisterStorage(HANDLE_TO_STORAGE(storageHandle));
}

UIntPtr
Class_Microsoft_Singularity_Eventing_LocalController::g_AllocateSourceHandleImpl(
    Class_System_String * sourceName)
{
    SOURCE_DESCRIPTOR source = {NULL, 0};
    PVOID ExtendedBuffer;

    PMEMORY_HEADER Entry = InternalLogRecord( GetLocalRepositoryHandle(),
        RECORD_EVENT_SOURCE,
        0,
        &source,
        sizeof(source),
        &ExtendedBuffer,
        sourceName->m_stringLength + 1);

    if (Entry != NULL) {

        PSOURCE_DESCRIPTOR newSource = (PSOURCE_DESCRIPTOR)GetUserRecordStructure(Entry);

        ConvertToChars((char *)ExtendedBuffer, sourceName);
        RegisterSource(newSource);
        CommitEventEntry(Entry);
    }

    return (UIntPtr)Entry;
}

PSOURCE_DESCRIPTOR
GetSourceFromHandle(UIntPtr sourceHandle)
{
    if (sourceHandle == 0) {

        return NULL;
    }

    PMEMORY_HEADER entry = HANDLE_TO_HEADER(sourceHandle);

    if (entry->Flags == RECORD_EVENT_SOURCE) {

        return (PSOURCE_DESCRIPTOR)GetUserRecordStructure(entry);
    }
    return NULL;
}

UIntPtr
AllocateNativeSourceHandle(char * sourceName)
{
    SOURCE_DESCRIPTOR source = {0,NULL,0,0,0,0,0,0};

    PVOID ExtendedBuffer;
    uint16 sourceLen = strlen(sourceName) + 1;

    PMEMORY_HEADER Entry = InternalLogRecord( GetLocalRepositoryHandle(),
        RECORD_EVENT_SOURCE,
        0,
        &source,
        sizeof(source),
        &ExtendedBuffer,
        sourceLen);

    if (Entry != NULL) {

        PSOURCE_DESCRIPTOR newSource = (PSOURCE_DESCRIPTOR)GetUserRecordStructure(Entry);
        memcpy(ExtendedBuffer, sourceName, sourceLen);

        RegisterSource(newSource);
        CommitEventEntry(Entry);
    }

    return (UIntPtr)Entry;
}

UIntPtr
RegisterNativeSource(char * sourceName, UIntPtr storageHandle, uint32 controlFlags)
{
    UIntPtr sourceHandle = AllocateNativeSourceHandle(sourceName);

    if (sourceHandle != 0) {

        Class_Microsoft_Singularity_Eventing_LocalController::g_RegisterSourceStorageImpl(
            sourceHandle, storageHandle, controlFlags);

        if (storageHandle != 0) {

            RegisterStorage(HANDLE_TO_STORAGE(storageHandle));
        }

    }

    return sourceHandle;
}

void
Class_Microsoft_Singularity_Eventing_LocalController::g_RegisterSourceStorageImpl(
    UIntPtr sourceHandle,
    UIntPtr storageHandle,
    uint32 controlFlags)
{
    PSOURCE_DESCRIPTOR Source;

    Source = (PSOURCE_DESCRIPTOR)GetUserRecordStructure(HANDLE_TO_HEADER(sourceHandle));

    if (Source) {
        Source->StorageHandle = storageHandle;
        Source->EventTypeHandle = 0;
        Source->DebuggerBufferAddress = 0;
        Source->Count = 0;
        Source->EntrySize = 0;
        Source->ControlFlags = controlFlags;
    }
}

void
Class_Microsoft_Singularity_Eventing_LocalController::g_RegisterActiveSourceImpl(
    UIntPtr sourceHandle,
    UIntPtr eventTypeHandle,
    UIntPtr debuggerBufferAddress,
    uint16 count,
    uint16 entrySize)
{
    PSOURCE_DESCRIPTOR Source;

    Source = (PSOURCE_DESCRIPTOR)GetUserRecordStructure(HANDLE_TO_HEADER(sourceHandle));

    if (Source) {

        Source->StorageHandle = 0;
        Source->EventTypeHandle = eventTypeHandle;
        Source->DebuggerBufferAddress = debuggerBufferAddress;
        Source->Count = count;
        Source->EntrySize = entrySize;
        Source->ControlFlags = 0xFFFF0000;
    }
}

void
Class_Microsoft_Singularity_Eventing_LocalController::g_UnRegisterSourceImpl(
    UIntPtr sourceHandle)
{
    PSOURCE_DESCRIPTOR Source;

    Source = (PSOURCE_DESCRIPTOR)GetUserRecordStructure(HANDLE_TO_HEADER(sourceHandle));

    if (Source) {

        EV_ASSERT(Source->StorageHandle == 0);
        Source->StorageHandle = 0;
    }
}


bool Class_Microsoft_Singularity_Eventing_LocalController::
    g_GetControllerHandle(UIntPtr *storageHandle, UIntPtr *contextHandle)
{
    // ????? Some correct values are needed that would allow switching to the right context in debugger
    // Note these values are not being accessed programatically. Correct contracts should be established
    // to query entries cross SIPs

    *storageHandle = (UIntPtr)&SourceController;
    *contextHandle = 0;
    return true;
}


bool Class_Microsoft_Singularity_Eventing_LocalController::
g_QueryNativeSourceInfo(UIntPtr sourceHandle,
                            UIntPtr * storageHandle,
                            bartok_char * bufferName,
                            uint16 bufferSize)
{
    PMEMORY_HEADER Entry = HANDLE_TO_HEADER(sourceHandle);
    PSOURCE_DESCRIPTOR source = (PSOURCE_DESCRIPTOR)GetUserRecordStructure(Entry);

    *storageHandle = source->StorageHandle;

    char * src = (char *)(source + 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;
    }

    return true;
}


int Class_Microsoft_Singularity_Eventing_LocalController::
g_QuerySystemSources(UIntPtr * sourceHandles,
                              uint16 arraySize)
{

    int totalSources = 0;

    PSOURCE_DESCRIPTOR source = SourceController.SourceDescriptors;

    while (source != NULL) {

        if (totalSources < arraySize) {

            sourceHandles[totalSources] = (UIntPtr)((PMEMORY_HEADER)source - 1);
        }

        source = (PSOURCE_DESCRIPTOR)source->Link;
        totalSources += 1;
    }

    return totalSources;
}

bool Class_Microsoft_Singularity_Eventing_Controller::
    g_GetSharedSourceHandlesInternal(uint32 infoId,
                                     UIntPtr * storageHandle,
                                     UIntPtr * sourceHandle,
                                     UIntPtr * eventTypeHandle)
{
    switch (infoId) {
        case Class_Microsoft_Singularity_Eventing_Controller_TracingInfo:
            return GetTracingHandles(storageHandle, sourceHandle, eventTypeHandle);

        case Class_Microsoft_Singularity_Eventing_Controller_MonitoringInfo:
            return GetMonitoringHandles(storageHandle, sourceHandle, eventTypeHandle);
    }

    return false;
}



//
///////////////////////////////////////////////////////////////// End of File.

