/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: schedt.c Abstract: Psched Tracing support Author: Rajesh Sundaram (rajeshsu) 01-Aug-1998. Environment: Kernel Mode Revision History: --*/ #include "psched.h" #pragma hdrstop // // Globals // NDIS_SPIN_LOCK GlobalLoggingLock; ULONG SchedTraceIndex; ULONG SchedBufferSize; ULONG SchedTraced; UCHAR *SchedTraceBuffer; ULONG SchedBufferStart; ULONG SchedTraceBytesUnread; ULONG SchedTraceThreshold; PVOID SchedTraceThreshContext; SCHEDTRACE_THRESH_PROC SchedTraceThreshProc; BOOLEAN TraceBufferAllocated; VOID SchedInitialize( ULONG BufferSize) { SchedBufferSize = BufferSize; TraceBufferAllocated = FALSE; PsAllocatePool(SchedTraceBuffer, SchedBufferSize, PsMiscTag); if(SchedTraceBuffer){ TraceBufferAllocated = TRUE; NdisAllocateSpinLock(&GlobalLoggingLock); } else { TraceBufferAllocated = FALSE; } } VOID SchedDeInitialize( ) { if(TraceBufferAllocated) { PsFreePool(SchedTraceBuffer); TraceBufferAllocated = FALSE; } NdisFreeSpinLock(&GlobalLoggingLock); } VOID DbugTraceSetThreshold( ULONG Threshold, PVOID Context, SCHEDTRACE_THRESH_PROC ThreshProc) { ULONG bytesToCopyAtEnd; ULONG bytesToCopyAtStart; NdisAcquireSpinLock(&GlobalLoggingLock); SchedTraceThreshProc = ThreshProc; SchedTraceThreshold = (Threshold <= SchedBufferSize) ? Threshold : SchedBufferSize; SchedTraceThreshContext = Context; if ((SchedTraceThreshContext != NULL) && (SchedTraceBytesUnread >= SchedTraceThreshold)) { SchedTraceThreshContext = NULL; NdisReleaseSpinLock(&GlobalLoggingLock); (*ThreshProc)(Context); } else { NdisReleaseSpinLock(&GlobalLoggingLock); } } VOID DbugReadTraceBuffer( PUCHAR Buffer, ULONG BytesToRead, PULONG BytesRead ) { ULONG bytesToCopyAtEnd; ULONG bytesToCopyAtStart; ULONG bytesToCopy; ULONG startIndex; // Copy the most recently added bytes to the user buffer. If BytesToRead is less than // the number of unread bytes in the trace buffer, the older bytes are lost. This // ensures that the last record in the user buffer is complete (as long as the user // buffer is big enough to accommodate at least that one record). NdisAcquireSpinLock(&GlobalLoggingLock); bytesToCopy = (SchedTraceBytesUnread <= BytesToRead) ? SchedTraceBytesUnread : BytesToRead; startIndex = (bytesToCopy > SchedTraceIndex) ? SchedTraceIndex + SchedBufferSize - bytesToCopy : SchedTraceIndex - bytesToCopy; if ((startIndex + bytesToCopy) > SchedBufferSize) { bytesToCopyAtEnd = SchedBufferSize - startIndex; bytesToCopyAtStart = bytesToCopy - bytesToCopyAtEnd; RtlCopyMemory(Buffer, &SchedTraceBuffer[startIndex], bytesToCopyAtEnd); RtlCopyMemory(Buffer + bytesToCopyAtEnd, &SchedTraceBuffer[0], bytesToCopyAtStart); } else { bytesToCopyAtEnd = bytesToCopy; RtlCopyMemory(Buffer, &SchedTraceBuffer[startIndex], bytesToCopy); } SchedTraceBytesUnread = 0; *BytesRead = bytesToCopy; NdisReleaseSpinLock(&GlobalLoggingLock); } NTSTATUS WriteRecord( UCHAR * Record, ULONG Bytes ) { ULONG bytesToCopyAtEnd; ULONG bytesToCopyAtStart; SCHEDTRACE_THRESH_PROC ThreshProc; PVOID Context; if(!TraceBufferAllocated){ return(STATUS_UNSUCCESSFUL); } NdisAcquireSpinLock(&GlobalLoggingLock); if((SchedTraceIndex + Bytes) > SchedBufferSize){ bytesToCopyAtEnd = SchedBufferSize - SchedTraceIndex; bytesToCopyAtStart = Bytes - bytesToCopyAtEnd; RtlCopyMemory(&SchedTraceBuffer[SchedTraceIndex], Record, bytesToCopyAtEnd); RtlCopyMemory(&SchedTraceBuffer[0], (UCHAR *)Record + bytesToCopyAtEnd, bytesToCopyAtStart); SchedTraceIndex = bytesToCopyAtStart; SchedTraced += Bytes; } else{ bytesToCopyAtEnd = Bytes; RtlCopyMemory(&SchedTraceBuffer[SchedTraceIndex], Record, Bytes); SchedTraceIndex += Bytes; SchedTraced += Bytes; } SchedTraceBytesUnread += Bytes; if (SchedTraceBytesUnread > SchedBufferSize) { SchedTraceBytesUnread = SchedBufferSize; } if ((SchedTraceThreshContext != NULL) && (SchedTraceBytesUnread >= SchedTraceThreshold)) { ThreshProc = SchedTraceThreshProc; Context = SchedTraceThreshContext; SchedTraceThreshContext = NULL; NdisReleaseSpinLock(&GlobalLoggingLock); (*ThreshProc)(Context); } else { NdisReleaseSpinLock(&GlobalLoggingLock); } return(STATUS_SUCCESS); } #define ClearRecord(x, y) \ RtlFillMemory(x, y, 0) VOID DbugSchedString(char *format, ...) { TRACE_RECORD_STRING record; CHAR buffer[TRACE_STRING_LENGTH]; va_list va; va_start(va, format); _vsnprintf(buffer, TRACE_STRING_LENGTH-1, format, va); va_end(va); ClearRecord(&record, sizeof(TRACE_RECORD_STRING)); record.Preamble = TRACE_PREAMBLE; record.RecordType = RECORD_TSTRING; PsGetCurrentTime(&record.Now); strncpy(record.StringStart, buffer, TRACE_STRING_LENGTH); WriteRecord((UCHAR *)&record, sizeof(TRACE_RECORD_STRING)); return; } VOID DbugRecv( ULONG Event, ULONG Action, PVOID Adapter, PNDIS_PACKET Packet1, PNDIS_PACKET Packet2 ) { TRACE_RECORD_RECV record; ClearRecord(&record, sizeof(TRACE_RECORD_RECV)); record.Preamble = TRACE_PREAMBLE; record.RecordType = RECORD_RECV; PsGetCurrentTime(&record.Now); record.Event = Event; record.Action = Action; record.Adapter = Adapter; record.Packet1 = Packet1; record.Packet2 = Packet2; WriteRecord((UCHAR *)&record, sizeof(TRACE_RECORD_RECV)); } VOID DbugSend( ULONG Event, ULONG Action, PVOID Adapter, PVOID Vc, PNDIS_PACKET Packet1, PNDIS_PACKET Packet2 ) { TRACE_RECORD_SEND record; ClearRecord(&record, sizeof(TRACE_RECORD_SEND)); record.Preamble = TRACE_PREAMBLE; record.RecordType = RECORD_SEND; PsGetCurrentTime(&record.Now); record.Event = Event; record.Action = Action; record.Adapter = Adapter; record.Vc = Vc; record.Packet1 = Packet1; record.Packet2 = Packet2; WriteRecord((UCHAR *)&record, sizeof(TRACE_RECORD_SEND)); } VOID DbugOid( ULONG Action, ULONG Local, ULONG PTState, ULONG MPState, PVOID Adapter, ULONG Oid, ULONG Status ) { TRACE_RECORD_OID record; ClearRecord(&record, sizeof(TRACE_RECORD_OID)); record.Preamble = TRACE_PREAMBLE; record.RecordType = RECORD_OID; PsGetCurrentTime(&record.Now); record.Action = Action; record.Local = Local; record.Oid = Oid; record.PTState = PTState; record.MPState = MPState; record.Adapter = Adapter; record.Status = Status; WriteRecord((UCHAR *)&record, sizeof(TRACE_RECORD_OID)); } VOID DbugSchedPkts( ULONG CallingFunction, PVOID VC, PNDIS_PACKET Packet, ULONG Action, ULONG PacketLength) { TRACE_RECORD_PKT record; ClearRecord(&record, sizeof(TRACE_RECORD_PKT)); record.Preamble = TRACE_PREAMBLE; record.RecordType = RECORD_PKT; record.CallingFunction = CallingFunction; PsGetCurrentTime(&record.Now); record.VC = VC; record.Packet = Packet; record.Action = Action; record.PacketLength = PacketLength; WriteRecord((UCHAR *)&record, sizeof(TRACE_RECORD_PKT)); } VOID DbugSched( ULONG SchedulerComponent, ULONG Action, PVOID VC, PNDIS_PACKET Packet, ULONG PacketLength, ULONG Priority, LONGLONG ArrivalTime, LONGLONG ConformanceTime, ULONG PacketsInComponent, ULONG BytesInComponent ) { TRACE_RECORD_SCHED record; ClearRecord(&record, sizeof(TRACE_RECORD_SCHED)); record.Preamble = TRACE_PREAMBLE; record.RecordType = RECORD_SCHED; record.SchedulerComponent = SchedulerComponent; PsGetCurrentTime(&record.Now); record.Action = Action; record.VC = VC; record.Packet = Packet; record.PacketLength = PacketLength; record.Priority = Priority; record.ArrivalTime = ArrivalTime, record.ConformanceTime = ConformanceTime; record.PacketsInComponent = PacketsInComponent; record.BytesInComponent = BytesInComponent; WriteRecord((UCHAR *)&record, sizeof(TRACE_RECORD_SCHED)); } VOID DbugComponentSpecificRec( ULONG Component, PVOID Data, ULONG Length) { TRACE_RECORD_COMPONENT_SPECIFIC record; ClearRecord(&record, sizeof(TRACE_RECORD_COMPONENT_SPECIFIC)); record.Preamble = TRACE_PREAMBLE; record.RecordType = RECORD_COMPONENT_SPECIFIC; record.SchedulerComponent = Component; PsGetCurrentTime(&record.Now); record.Length = (Length > MAX_RECORD_DATA) ? MAX_RECORD_DATA : Length; RtlCopyMemory(record.Data, Data, record.Length); WriteRecord((UCHAR *)&record, record.Length + FIELD_OFFSET(TRACE_RECORD_COMPONENT_SPECIFIC, Data)); } ULONG SchedtGetBufferSize() { return SchedBufferSize; } ULONG SchedtGetBytesUnread() { return SchedTraceBytesUnread; }