1189 lines
44 KiB
C#
1189 lines
44 KiB
C#
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: EventController.cs
|
||
|
//
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using System.Threading;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.V1.Services;
|
||
|
using Microsoft.Singularity.Eventing;
|
||
|
using System.Collections;
|
||
|
|
||
|
namespace Microsoft.Singularity.Eventing
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Define here the controller class. A controller object
|
||
|
// defines the scope of the tracing / eventing,
|
||
|
// defines the lifetime of the eventing related metadata such as
|
||
|
// event types, sources and consumers, and implicitely
|
||
|
// respects the isolation boundary for events. Queries and
|
||
|
// traces accross controllers should use contracts. Queries / logging
|
||
|
// from SIPs to kernel use syscalls ABIs
|
||
|
//
|
||
|
|
||
|
[CLSCompliant(false)]
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
public abstract class Controller {
|
||
|
|
||
|
// Commonly all events / traces are using by default the local controller
|
||
|
// A SIP and kernel has the optional to instantiate additional controllers.
|
||
|
|
||
|
internal static LocalController LocalControllerObject;
|
||
|
|
||
|
// Some events may choose for a system-wide visibility, in which case
|
||
|
// a SIP may refer through a system controller. For kernel, both system and
|
||
|
// local controller are the same.
|
||
|
|
||
|
internal static Controller SystemControllerObject;
|
||
|
|
||
|
// default size for entry enumerations
|
||
|
|
||
|
const ushort DefaultEntrySize = 256;
|
||
|
|
||
|
//
|
||
|
// Define the accessor methods to the system and local controller
|
||
|
//
|
||
|
|
||
|
static public LocalController GetLocalController()
|
||
|
{
|
||
|
return LocalControllerObject;
|
||
|
}
|
||
|
|
||
|
static public Controller GetSystemController()
|
||
|
{
|
||
|
return SystemControllerObject;
|
||
|
}
|
||
|
|
||
|
static public bool IsSystemScope()
|
||
|
{
|
||
|
#if SINGULARITY_KERNEL
|
||
|
|
||
|
return true;
|
||
|
|
||
|
#else // SINGULARITY_KERNEL
|
||
|
|
||
|
return false;
|
||
|
|
||
|
#endif // SINGULARITY_KERNEL
|
||
|
|
||
|
}
|
||
|
|
||
|
// Public methods
|
||
|
|
||
|
static public void InitializeSystem() {
|
||
|
|
||
|
// Create the system controller if needed. The SIPs will
|
||
|
// get a proxy controller object that will handle operations
|
||
|
// as syscalls.
|
||
|
// TODO: Further optimizations may allow writing a more
|
||
|
// efficient proxy that may use shared memory.
|
||
|
|
||
|
#if SINGULARITY_KERNEL
|
||
|
|
||
|
KernelController controller = new KernelController();
|
||
|
|
||
|
if (controller != null) {
|
||
|
|
||
|
LocalControllerObject = controller;
|
||
|
SystemControllerObject = LocalControllerObject;
|
||
|
controller.Initialize();
|
||
|
}
|
||
|
#else
|
||
|
LocalController controller = new LocalController();
|
||
|
|
||
|
if (controller != null) {
|
||
|
|
||
|
LocalControllerObject = controller;
|
||
|
|
||
|
// For SIPs we need a proxy object that will handle the calls
|
||
|
// to the system controller
|
||
|
|
||
|
SystemControllerObject = new SystemControllerProxy();
|
||
|
|
||
|
controller.Initialize();
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
if (SystemControllerObject != null) {
|
||
|
|
||
|
SystemControllerObject.Initialize();
|
||
|
SystemControllerObject.RegisterController();
|
||
|
QuerySession.InitializeQuerySystem();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Avoid any cleanup that would normally happen when a storage is deleted or
|
||
|
// a source is de-registered during SIP shutdown. Beside the work is unnecessary,
|
||
|
// there are problems with the order of executing the finalizers at shutdown
|
||
|
|
||
|
internal static bool Finalized = false;
|
||
|
|
||
|
static public void Finalize() {
|
||
|
Finalized = true;
|
||
|
}
|
||
|
|
||
|
// Private fields
|
||
|
|
||
|
internal Mutex Lock;
|
||
|
|
||
|
//
|
||
|
// Abstract methods
|
||
|
//
|
||
|
|
||
|
public abstract bool RegisterEvent(string eventName,
|
||
|
string eventDescription,
|
||
|
ref UIntPtr eventHandle);
|
||
|
|
||
|
public abstract bool RegisterEventField(UIntPtr eventHandle,
|
||
|
string fieldName,
|
||
|
UInt16 offset,
|
||
|
UInt16 type);
|
||
|
|
||
|
public abstract bool RegisterEventGenericField(UIntPtr eventHandle,
|
||
|
string fieldName,
|
||
|
UInt16 offset,
|
||
|
UInt16 size,
|
||
|
UIntPtr fieldTypeHandle);
|
||
|
|
||
|
public abstract bool RegisterEnum(string enumName,
|
||
|
UInt16 type,
|
||
|
ref UIntPtr eventHandle);
|
||
|
|
||
|
public abstract bool RegisterEnumValue(UIntPtr eventHandle,
|
||
|
string valueName,
|
||
|
UInt64 value,
|
||
|
byte flagChar);
|
||
|
|
||
|
public abstract UIntPtr WalkEventDescriptor(UIntPtr eventHandle,
|
||
|
UIntPtr currentField,
|
||
|
ref UInt16 offset,
|
||
|
ref UInt16 type,
|
||
|
ref string bufferName);
|
||
|
|
||
|
public abstract bool GetSourceInformation(UIntPtr sourceHandle,
|
||
|
ref UIntPtr storageHandle,
|
||
|
ref UIntPtr eventType,
|
||
|
ref UInt16 count,
|
||
|
ref string bufferName);
|
||
|
|
||
|
// Virtual methods
|
||
|
|
||
|
internal virtual void Initialize()
|
||
|
{
|
||
|
Lock = new Mutex();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Controller related methods
|
||
|
//
|
||
|
|
||
|
public virtual bool RegisterController()
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public virtual void UnRegisterController(int processId)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Storage related methods
|
||
|
//
|
||
|
|
||
|
public virtual EventingStorage OpenStorage(UIntPtr storageHandle)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Source related methods
|
||
|
//
|
||
|
|
||
|
public virtual bool RegisterSource(EventSource source)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public virtual void UnRegisterSource(EventSource source){}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Query functionality methods
|
||
|
//
|
||
|
|
||
|
public virtual int QuerySourcesList(UIntPtr [] buffer, int size)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
public virtual int QueryEventTypeList(UIntPtr [] buffer, int size)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
public virtual bool QueryActiveEntry(UIntPtr sourceHandle,
|
||
|
int index,
|
||
|
ref QueryBuffer entryBuffer)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public virtual void EnumerateActiveSources(QuerySourceDelegate sourceDelegate,
|
||
|
ActiveSourceEntryDelegate activeEntryDelegate,
|
||
|
QueryEntryDelegate entryDelegate,
|
||
|
ushort maxEntrySize,
|
||
|
ref EnumerationContext context)
|
||
|
{
|
||
|
|
||
|
if (maxEntrySize == 0) {
|
||
|
maxEntrySize = DefaultEntrySize;
|
||
|
}
|
||
|
|
||
|
// Create a temporary buffer to store the temporary query information
|
||
|
|
||
|
QueryBuffer entryBuffer = new QueryBuffer(maxEntrySize);
|
||
|
|
||
|
if ((entryBuffer == null) || (sourceDelegate == null)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Prepare to query the controller for the source list. We just pick up an number
|
||
|
// that would represent the limit for most common cases as the initial guess.
|
||
|
|
||
|
int currentSize = 100;
|
||
|
UIntPtr [] sourceArray = new UIntPtr[currentSize];
|
||
|
|
||
|
if (sourceArray != null) {
|
||
|
|
||
|
// Query the controller for the actual source list
|
||
|
|
||
|
int sourceCount = QuerySourcesList(sourceArray, currentSize);
|
||
|
|
||
|
//
|
||
|
// The array was not large enough, attempt again with the new size
|
||
|
|
||
|
while (sourceCount > currentSize) {
|
||
|
|
||
|
sourceArray = new UIntPtr[sourceCount];
|
||
|
sourceCount = QuerySourcesList(sourceArray, currentSize);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We sucessfully received an array of entries. We walk them and build the
|
||
|
// required information
|
||
|
//
|
||
|
|
||
|
for (int i = 0; i < sourceCount; i++) {
|
||
|
|
||
|
UIntPtr sourceHandle = sourceArray[i];
|
||
|
UIntPtr storageHandle = 0;
|
||
|
UIntPtr eventType = 0;
|
||
|
UInt16 count = 0;
|
||
|
string bufferName = "";
|
||
|
|
||
|
if (GetSourceInformation(sourceHandle,
|
||
|
ref storageHandle,
|
||
|
ref eventType,
|
||
|
ref count,
|
||
|
ref bufferName)) {
|
||
|
|
||
|
if (storageHandle == 0) {
|
||
|
|
||
|
//
|
||
|
// This is an active source. The eventing has no information
|
||
|
// about the storage, it has instead information about the
|
||
|
// types of events handled by this source
|
||
|
//
|
||
|
|
||
|
EventDescriptor descriptor = QuerySession.GetEventDescriptor(this,
|
||
|
eventType);
|
||
|
|
||
|
if (descriptor != null) {
|
||
|
|
||
|
// The source is valid, call the delegate with the appropriate
|
||
|
// arguments filled in
|
||
|
// TODO: Also retrieve the control flags status
|
||
|
|
||
|
|
||
|
if (!sourceDelegate(sourceHandle,
|
||
|
storageHandle,
|
||
|
eventType,
|
||
|
count,
|
||
|
bufferName,
|
||
|
descriptor,
|
||
|
ref context)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (entryDelegate != null) {
|
||
|
|
||
|
// The caller also provided an entry delegate. We need in that
|
||
|
// case to also enumerate all entries from the active source
|
||
|
|
||
|
for (int index = 0; index < count; index++) {
|
||
|
|
||
|
if (!QueryActiveEntry(sourceHandle,
|
||
|
index,
|
||
|
ref entryBuffer)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
activeEntryDelegate(sourceHandle,
|
||
|
index,
|
||
|
descriptor,
|
||
|
entryBuffer,
|
||
|
ref context);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
// This source has an associated storage. Enumerate the entries from
|
||
|
// the storage
|
||
|
// TODO: we might also want to filter the sources inside the storage
|
||
|
// since multiple sources can share the same storage
|
||
|
|
||
|
if (!sourceDelegate(sourceHandle,
|
||
|
storageHandle,
|
||
|
eventType,
|
||
|
count,
|
||
|
bufferName,
|
||
|
null,
|
||
|
ref context)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
EventingStorage storage = OpenStorage(storageHandle);
|
||
|
|
||
|
if (storage != null) {
|
||
|
|
||
|
// Instantiate a query session for the storage and
|
||
|
// enumerate the entries passing the provided delegate
|
||
|
|
||
|
QuerySession query = new QuerySession();
|
||
|
|
||
|
if ((query != null) && (context != null) &&
|
||
|
query.Initialize(storage, false)) {
|
||
|
|
||
|
query.EnumerateEntries(entryDelegate, ref context);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static unsafe bool GetSharedSourceHandles(uint infoId,
|
||
|
out UIntPtr storageHandle,
|
||
|
out UIntPtr sourceHandle,
|
||
|
out UIntPtr eventTypeHandle )
|
||
|
{
|
||
|
|
||
|
if ((infoId == TracingInfo) || (infoId == MonitoringInfo)) {
|
||
|
|
||
|
UIntPtr tmpStorageHandle;
|
||
|
UIntPtr tmpSourceHandle;
|
||
|
UIntPtr tmpEventTypeHandle;
|
||
|
|
||
|
if (GetSharedSourceHandlesInternal(infoId,
|
||
|
&tmpStorageHandle,
|
||
|
&tmpSourceHandle,
|
||
|
&tmpEventTypeHandle)) {
|
||
|
|
||
|
storageHandle = tmpStorageHandle;
|
||
|
sourceHandle = tmpSourceHandle;
|
||
|
eventTypeHandle = tmpEventTypeHandle;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
storageHandle = 0;
|
||
|
sourceHandle = 0;
|
||
|
eventTypeHandle = 0;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
public const uint TracingInfo = 1;
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
public const uint MonitoringInfo = 2;
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe bool GetSharedSourceHandlesInternal(uint infoId,
|
||
|
UIntPtr * storageHandle,
|
||
|
UIntPtr * sourceHandle,
|
||
|
UIntPtr * eventTypeHandle );
|
||
|
}
|
||
|
|
||
|
|
||
|
[CLSCompliant(false)]
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
public class LocalController : Controller {
|
||
|
|
||
|
//
|
||
|
// Internal fields
|
||
|
//
|
||
|
|
||
|
// The type repository is a permanent
|
||
|
|
||
|
internal EventingStorage TypesRepository;
|
||
|
internal Hashtable EventTable;
|
||
|
internal Hashtable SourcesHandleTable;
|
||
|
internal Hashtable SourcesLookupTable;
|
||
|
|
||
|
internal ControllerLogger InternalSource;
|
||
|
|
||
|
internal const uint BUFFER_EXPANSION_SIZE = 0x10000;
|
||
|
|
||
|
// Public methods
|
||
|
|
||
|
// Private methods
|
||
|
|
||
|
internal override void Initialize() {
|
||
|
|
||
|
base.Initialize();
|
||
|
|
||
|
EventTable = new Hashtable();
|
||
|
SourcesLookupTable = new Hashtable();
|
||
|
SourcesHandleTable = new Hashtable();
|
||
|
|
||
|
UIntPtr RepositoryStorageHandle = FetchLocalStorage();
|
||
|
|
||
|
if (RepositoryStorageHandle != 0) {
|
||
|
|
||
|
TypesRepository = EventingStorage.CreateStorageFromHandle(RepositoryStorageHandle);
|
||
|
|
||
|
// Fetch now the existing source list created before initializing the controller
|
||
|
|
||
|
int currentSize = 20;
|
||
|
UIntPtr [] sourceArray = new UIntPtr[currentSize];
|
||
|
|
||
|
if (sourceArray != null) {
|
||
|
|
||
|
unsafe {
|
||
|
fixed(UIntPtr * ptr = sourceArray) {
|
||
|
|
||
|
int sourceCount = QuerySystemSources(ptr, (ushort)currentSize);
|
||
|
|
||
|
while (sourceCount > currentSize) {
|
||
|
|
||
|
sourceArray = new UIntPtr[sourceCount];
|
||
|
sourceCount = QuerySystemSources(ptr, (ushort)currentSize);
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < sourceCount; i++) {
|
||
|
|
||
|
UIntPtr sourceHandle = sourceArray[i];
|
||
|
UIntPtr storageHandle = 0;
|
||
|
string bufferName = "";
|
||
|
|
||
|
if (GetNativeSourceName(sourceHandle, ref storageHandle, ref bufferName)) {
|
||
|
|
||
|
EventSource source = new EventSource(this, bufferName, storageHandle);
|
||
|
|
||
|
if (source != null) {
|
||
|
source.Register();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
TypesRepository = EventingStorage.CreateLocalStorage(QualityOfService.PermanentEvents,
|
||
|
BUFFER_EXPANSION_SIZE);
|
||
|
SetRepositoryStorage(TypesRepository.GetHandle());
|
||
|
}
|
||
|
|
||
|
string sourceName = "ControllerLog";
|
||
|
|
||
|
#if SINGULARITY_KERNEL
|
||
|
|
||
|
sourceName = sourceName + "{kernel}";
|
||
|
|
||
|
#else
|
||
|
unsafe {
|
||
|
|
||
|
int argMaxLen = ProcessService.GetStartupArg(0, null, 0);
|
||
|
char[] argArray = new char [argMaxLen];
|
||
|
|
||
|
|
||
|
fixed (char *argptr = &argArray[0]) {
|
||
|
int len = ProcessService.GetStartupArg(0,
|
||
|
argptr,
|
||
|
argArray.Length);
|
||
|
sourceName = sourceName + "{"+String.StringCTOR(argptr, 0, len)+"}";
|
||
|
sourceName = sourceName + "(PID:"+ ProcessService.GetCurrentProcessId() +")";
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
InternalSource = ControllerLogger.Create(sourceName, TypesRepository);
|
||
|
}
|
||
|
|
||
|
// Event schema registration routines
|
||
|
|
||
|
public override bool RegisterEvent(string eventName,
|
||
|
string eventDescription,
|
||
|
ref UIntPtr eventHandle) {
|
||
|
|
||
|
Lock.AcquireMutex();
|
||
|
object o = EventTable[eventName];
|
||
|
|
||
|
if (o != null) {
|
||
|
|
||
|
// Type already registered. Return the existing value
|
||
|
eventHandle = (UIntPtr)o;
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
eventHandle = RegisterEventDescriptorInternal(eventName, eventDescription);
|
||
|
|
||
|
while (eventHandle == 0) {
|
||
|
|
||
|
if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
eventHandle = RegisterEventDescriptorInternal(eventName, eventDescription);
|
||
|
}
|
||
|
|
||
|
EventTable[eventName] = eventHandle;
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool RegisterEventField(UIntPtr eventHandle,
|
||
|
string fieldName,
|
||
|
UInt16 offset,
|
||
|
UInt16 type) {
|
||
|
|
||
|
UIntPtr field = RegisterEventFieldInternal(eventHandle,
|
||
|
fieldName,
|
||
|
offset,
|
||
|
type);
|
||
|
|
||
|
while (field == 0) {
|
||
|
|
||
|
Lock.AcquireMutex();
|
||
|
if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
|
||
|
field = RegisterEventFieldInternal(eventHandle,
|
||
|
fieldName,
|
||
|
offset,
|
||
|
type);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool RegisterEventGenericField(UIntPtr eventHandle,
|
||
|
string fieldName,
|
||
|
UInt16 offset,
|
||
|
UInt16 size,
|
||
|
UIntPtr fieldTypeHandle) {
|
||
|
|
||
|
UIntPtr field = RegisterEventGenericFieldInternal(eventHandle,
|
||
|
fieldName,
|
||
|
offset,
|
||
|
size,
|
||
|
fieldTypeHandle);
|
||
|
|
||
|
while (field == 0) {
|
||
|
|
||
|
Lock.AcquireMutex();
|
||
|
if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
|
||
|
field = RegisterEventGenericFieldInternal(eventHandle,
|
||
|
fieldName,
|
||
|
offset,
|
||
|
size,
|
||
|
fieldTypeHandle);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Enumeration registration support
|
||
|
//
|
||
|
|
||
|
public override bool RegisterEnum(string enumName,
|
||
|
UInt16 type,
|
||
|
ref UIntPtr eventHandle) {
|
||
|
|
||
|
Lock.AcquireMutex();
|
||
|
object o = EventTable[enumName];
|
||
|
|
||
|
if (o != null) {
|
||
|
|
||
|
// Type already registered. Return the existing value
|
||
|
eventHandle = (UIntPtr)o;
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
eventHandle = RegisterEnumDescriptorInternal(enumName, type);
|
||
|
|
||
|
while (eventHandle == 0) {
|
||
|
|
||
|
if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
eventHandle = RegisterEnumDescriptorInternal(enumName, type);
|
||
|
}
|
||
|
|
||
|
EventTable[enumName] = eventHandle;
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool RegisterEnumValue(UIntPtr eventHandle,
|
||
|
string valueName,
|
||
|
UInt64 value,
|
||
|
byte flagChar) {
|
||
|
|
||
|
UIntPtr field = RegisterValueDescriptorInternal(eventHandle,
|
||
|
valueName,
|
||
|
value,
|
||
|
flagChar);
|
||
|
|
||
|
while (field == 0) {
|
||
|
|
||
|
Lock.AcquireMutex();
|
||
|
if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
field = RegisterValueDescriptorInternal(eventHandle,
|
||
|
valueName,
|
||
|
value,
|
||
|
flagChar);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Storage registration routines
|
||
|
|
||
|
public bool RegisterStorage(EventingStorage Storage)
|
||
|
{
|
||
|
Lock.AcquireMutex();
|
||
|
bool success = RegisterStorageImpl(Storage.GetHandle());
|
||
|
Lock.ReleaseMutex();
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
public void UnRegisterStorage(EventingStorage Storage)
|
||
|
{
|
||
|
if (!Controller.Finalized) {
|
||
|
|
||
|
Lock.AcquireMutex();
|
||
|
UnRegisterStorageImpl(Storage.GetHandle());
|
||
|
Lock.ReleaseMutex();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Eventing source support routines
|
||
|
|
||
|
public override bool RegisterSource(EventSource source)
|
||
|
{
|
||
|
// Sanity check against double registration
|
||
|
if (source.SourceHandle != 0) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
UIntPtr sourceHandle= 0;
|
||
|
|
||
|
Lock.AcquireMutex();
|
||
|
|
||
|
object obj = SourcesLookupTable[source.SourceName];
|
||
|
|
||
|
if (obj != null) {
|
||
|
|
||
|
sourceHandle = (UIntPtr)obj;
|
||
|
}
|
||
|
|
||
|
if (sourceHandle != 0) {
|
||
|
|
||
|
object existingSource = SourcesHandleTable[sourceHandle];
|
||
|
|
||
|
if (existingSource != null) {
|
||
|
|
||
|
// Type already registered. Return the existing value
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
// The handle for this source has not been allocated
|
||
|
// Register a new one
|
||
|
|
||
|
sourceHandle = AllocateSourceHandleImpl(source.SourceName);
|
||
|
|
||
|
while (sourceHandle == 0) {
|
||
|
|
||
|
if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
sourceHandle = AllocateSourceHandleImpl(source.SourceName);
|
||
|
}
|
||
|
|
||
|
SourcesLookupTable[source.SourceName] = sourceHandle;
|
||
|
}
|
||
|
|
||
|
// We must have here a valid source handle
|
||
|
|
||
|
source.SourceHandle = sourceHandle;
|
||
|
SourcesHandleTable[sourceHandle] = source;
|
||
|
|
||
|
ActiveSource activeSource = source as ActiveSource;
|
||
|
|
||
|
if (activeSource == null) {
|
||
|
|
||
|
// regular sources with associated memory storage
|
||
|
|
||
|
RegisterSourceStorageImpl(sourceHandle,
|
||
|
source.Storage.GetHandle(),
|
||
|
source.ControlFlags);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
RegisterActiveSourceImpl(sourceHandle,
|
||
|
activeSource.EventTypeHandle,
|
||
|
activeSource.DebugBufferAddress,
|
||
|
activeSource.Count,
|
||
|
activeSource.EntrySize);
|
||
|
|
||
|
// Active sources, the object does the event buffer management
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override void UnRegisterSource(EventSource source)
|
||
|
{
|
||
|
if (!Controller.Finalized) {
|
||
|
Lock.AcquireMutex();
|
||
|
|
||
|
if (source.SourceHandle != 0) {
|
||
|
|
||
|
SourcesHandleTable.Remove(source.SourceHandle);
|
||
|
UnRegisterSourceImpl(source.SourceHandle);
|
||
|
|
||
|
source.SourceHandle = 0;
|
||
|
}
|
||
|
Lock.ReleaseMutex();
|
||
|
}
|
||
|
}
|
||
|
public override int QuerySourcesList(UIntPtr [] buffer, int size)
|
||
|
{
|
||
|
int i = 0;
|
||
|
Lock.AcquireMutex();
|
||
|
|
||
|
IDictionaryEnumerator enumerator = SourcesHandleTable.GetEnumerator();
|
||
|
while (enumerator.MoveNext()) {
|
||
|
|
||
|
if (i < size) {
|
||
|
|
||
|
EventSource source = enumerator.Value as EventSource;
|
||
|
buffer[i++] = source.SourceHandle;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
public override int QueryEventTypeList(UIntPtr [] buffer, int size)
|
||
|
{
|
||
|
int i = 0;
|
||
|
Lock.AcquireMutex();
|
||
|
|
||
|
IDictionaryEnumerator enumerator = EventTable.GetEnumerator();
|
||
|
while (enumerator.MoveNext()) {
|
||
|
|
||
|
if (i < size) {
|
||
|
|
||
|
UIntPtr eventHandle = (UIntPtr)enumerator.Value;
|
||
|
buffer[i++] = eventHandle;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
public override bool GetSourceInformation(UIntPtr sourceHandle,
|
||
|
ref UIntPtr storageHandle,
|
||
|
ref UIntPtr eventType,
|
||
|
ref UInt16 count,
|
||
|
ref string bufferName)
|
||
|
{
|
||
|
Lock.AcquireMutex();
|
||
|
|
||
|
EventSource source = SourcesHandleTable[sourceHandle] as EventSource;
|
||
|
|
||
|
if (source != null) {
|
||
|
|
||
|
bufferName = source.SourceName;
|
||
|
ActiveSource activeSource = source as ActiveSource;
|
||
|
|
||
|
if (activeSource != null) {
|
||
|
|
||
|
storageHandle = 0;
|
||
|
eventType = activeSource.EventTypeHandle;
|
||
|
count = activeSource.Count;
|
||
|
|
||
|
} else {
|
||
|
storageHandle = source.Storage.GetHandle();
|
||
|
eventType = 0;
|
||
|
count = 0;
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override UIntPtr WalkEventDescriptor(UIntPtr eventHandle,
|
||
|
UIntPtr currentField,
|
||
|
ref UInt16 offset,
|
||
|
ref UInt16 type,
|
||
|
ref string bufferName)
|
||
|
{
|
||
|
UIntPtr fieldHandle = currentField;
|
||
|
UInt16 tmpOffset;
|
||
|
UInt16 tmpType;
|
||
|
const UInt16 MaxBufferSize = 256;
|
||
|
|
||
|
char[] tmpBufferName = new char[MaxBufferSize];
|
||
|
|
||
|
unsafe {
|
||
|
|
||
|
fixed(char* ptrBytes = &tmpBufferName[0]) {
|
||
|
|
||
|
fieldHandle = MemoryStorage.WalkEventDescriptorImpl(eventHandle,
|
||
|
fieldHandle,
|
||
|
&tmpOffset,
|
||
|
&tmpType,
|
||
|
ptrBytes,
|
||
|
MaxBufferSize);
|
||
|
|
||
|
if (fieldHandle != 0) {
|
||
|
|
||
|
string fieldName = "";
|
||
|
|
||
|
if (fieldName != null) {
|
||
|
for (int i = 0; i < MaxBufferSize; i++) {
|
||
|
|
||
|
if (tmpBufferName[i] == 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
fieldName += tmpBufferName[i];
|
||
|
}
|
||
|
}
|
||
|
type = tmpType;
|
||
|
offset = tmpOffset;
|
||
|
bufferName = fieldName;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return fieldHandle;
|
||
|
}
|
||
|
|
||
|
public override bool QueryActiveEntry(UIntPtr sourceHandle,
|
||
|
int index,
|
||
|
ref QueryBuffer entryBuffer)
|
||
|
{
|
||
|
unsafe {
|
||
|
|
||
|
UInt32 offset;
|
||
|
UIntPtr type;
|
||
|
|
||
|
fixed(byte * ptr = &(entryBuffer.GetBuffer()[0])) {
|
||
|
|
||
|
bool success = ReadActiveSourceItem(sourceHandle, index, &type, ptr, entryBuffer.GetBufferSize());
|
||
|
|
||
|
|
||
|
entryBuffer.Type = type;
|
||
|
|
||
|
// the active entries do not have any header
|
||
|
|
||
|
entryBuffer.UserOffset = 0;
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public unsafe bool ReadActiveSourceItem(UIntPtr sourceHandle,
|
||
|
int item,
|
||
|
UIntPtr * type,
|
||
|
byte * buffer,
|
||
|
UInt16 bufferSize )
|
||
|
{
|
||
|
Lock.AcquireMutex();
|
||
|
|
||
|
object source = SourcesHandleTable[sourceHandle];
|
||
|
|
||
|
if (source != null) {
|
||
|
ActiveSource activeSource = source as ActiveSource;
|
||
|
|
||
|
if (activeSource != null) {
|
||
|
|
||
|
bool success = activeSource.GetActiveEntry(item, type, buffer, bufferSize);
|
||
|
Lock.ReleaseMutex();
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Lock.ReleaseMutex();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
internal bool GetNativeSourceName(UIntPtr sourceHandle,
|
||
|
ref UIntPtr storageHandle,
|
||
|
ref string bufferName)
|
||
|
{
|
||
|
bool success = false;
|
||
|
const UInt16 MaxBufferSize = 256;
|
||
|
UIntPtr tmpHandle;
|
||
|
|
||
|
char[] tmpBufferName = new char[MaxBufferSize];
|
||
|
|
||
|
unsafe {
|
||
|
|
||
|
fixed(char* ptrBytes = &tmpBufferName[0]) {
|
||
|
|
||
|
success = QueryNativeSourceInfo(sourceHandle, &tmpHandle, ptrBytes, MaxBufferSize);
|
||
|
|
||
|
if (success) {
|
||
|
|
||
|
string sourceName = "";
|
||
|
|
||
|
if (sourceName != null) {
|
||
|
for (int i = 0; i < MaxBufferSize; i++) {
|
||
|
|
||
|
if (tmpBufferName[i] == 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
sourceName += tmpBufferName[i];
|
||
|
}
|
||
|
}
|
||
|
bufferName = sourceName;
|
||
|
storageHandle = tmpHandle;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
// ABI interfaces
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe bool GetControllerHandle(UIntPtr * sourceHandle, UIntPtr * storageHandle);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe UIntPtr FetchLocalStorage();
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe bool SetRepositoryStorage(UIntPtr StorageHandle);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe UIntPtr RegisterEventDescriptorInternal(string eventName,
|
||
|
string eventDescription);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe UIntPtr RegisterEventFieldInternal(UIntPtr eventHandle,
|
||
|
string fieldName,
|
||
|
UInt16 offset,
|
||
|
UInt16 type);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe UIntPtr RegisterEventGenericFieldInternal(UIntPtr eventHandle,
|
||
|
string fieldName,
|
||
|
UInt16 offset,
|
||
|
UInt16 size,
|
||
|
UIntPtr fieldTypeHandle);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe UIntPtr RegisterEnumDescriptorInternal(string enumName,
|
||
|
UInt16 type);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe UIntPtr RegisterValueDescriptorInternal(UIntPtr enumHandle,
|
||
|
string valueName,
|
||
|
UInt64 value,
|
||
|
byte flagChar);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe bool RegisterStorageImpl(UIntPtr StorageHandle);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe void UnRegisterStorageImpl(UIntPtr StorageHandle);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe UIntPtr AllocateSourceHandleImpl(string sourceName);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe void UnRegisterSourceImpl(UIntPtr sourceHandle);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe void RegisterSourceStorageImpl(UIntPtr sourceHandle,
|
||
|
UIntPtr storageHandle,
|
||
|
UInt32 controlFlags);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in EventController.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe void RegisterActiveSourceImpl(UIntPtr sourceHandle,
|
||
|
UIntPtr eventTypeHandle,
|
||
|
UIntPtr debuggerBufferAddress,
|
||
|
UInt16 count,
|
||
|
UInt16 entrySize);
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in MemoryStorage.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe bool QueryNativeSourceInfo(UIntPtr sourceHandle,
|
||
|
UIntPtr * storageHandle,
|
||
|
char * bufferName,
|
||
|
UInt16 bufferSize );
|
||
|
|
||
|
[AccessedByRuntime("output to header : defined in MemoryStorage.cpp")]
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(256)]
|
||
|
[NoHeapAllocation]
|
||
|
public static extern unsafe int QuerySystemSources(UIntPtr * sourceHandles,
|
||
|
UInt16 arraySize );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Event source for controller entries. Events and traces related
|
||
|
// to the controller's activity will use this source for logging
|
||
|
// For now, then only interesting event logged is the creation of
|
||
|
// the controller, which is helpful to associate a process name and ID with the
|
||
|
// current controller
|
||
|
//
|
||
|
|
||
|
[CLSCompliant(false)]
|
||
|
public class ControllerLogger : EventSource {
|
||
|
|
||
|
public static ControllerLogger Create(string sourceName, EventingStorage storage) {
|
||
|
|
||
|
ControllerLogger Logger = new ControllerLogger(sourceName,
|
||
|
storage,
|
||
|
CAPTURE_STACK_TRACE | ENABLE_ALL_MASK);
|
||
|
|
||
|
if (Logger != null) {
|
||
|
|
||
|
Logger.Register();
|
||
|
}
|
||
|
|
||
|
return Logger;
|
||
|
}
|
||
|
|
||
|
ControllerLogger(string sourceName, EventingStorage storage, uint controlFlags)
|
||
|
:base(sourceName, storage, controlFlags) {}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|