Fix logging to a file.

In spite of limitations, it remains the only way to obtain desired logs for some people.

svn path=/trunk/; revision=43331
This commit is contained in:
Dmitry Gorbachev 2009-10-07 19:57:40 +00:00
parent ffbb3fd184
commit 07dc415f89

View file

@ -14,16 +14,17 @@
/* GLOBALS *******************************************************************/ /* GLOBALS *******************************************************************/
#define BufferSize 32*1024 #define KdpBufferSize (1024 * 512)
BOOLEAN KdpLoggingEnabled = FALSE;
PCHAR KdpDebugBuffer = NULL;
volatile ULONG KdpCurrentPosition = 0;
volatile ULONG KdpFreeBytes = 0;
KSPIN_LOCK KdpDebugLogSpinLock;
KEVENT KdpLoggerThreadEvent;
HANDLE KdpLogFileHandle;
HANDLE KdbLogFileHandle;
BOOLEAN KdpLogInitialized;
CHAR DebugBuffer[BufferSize];
ULONG CurrentPosition;
WORK_QUEUE_ITEM KdpDebugLogQueue;
KSPIN_LOCK KdpSerialSpinLock; KSPIN_LOCK KdpSerialSpinLock;
BOOLEAN ItemQueued; KD_PORT_INFORMATION SerialPortInfo = { DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_BAUD_RATE, 0 };
KD_PORT_INFORMATION SerialPortInfo = {DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_BAUD_RATE, 0};
/* Current Port in use. FIXME: Do we support more then one? */ /* Current Port in use. FIXME: Do we support more then one? */
ULONG KdpPort; ULONG KdpPort;
@ -32,56 +33,103 @@ ULONG KdpPort;
VOID VOID
NTAPI NTAPI
KdpPrintToLogInternal(PVOID Context) KdpLoggerThread(PVOID Context)
{ {
ULONG beg, end, num;
IO_STATUS_BLOCK Iosb; IO_STATUS_BLOCK Iosb;
/* Write to the Debug Log */ KdpLoggingEnabled = TRUE;
NtWriteFile(KdbLogFileHandle,
NULL,
NULL,
NULL,
&Iosb,
DebugBuffer,
CurrentPosition,
NULL,
NULL);
/* Clear the Current Position */ while (TRUE)
CurrentPosition = 0; {
KeWaitForSingleObject(&KdpLoggerThreadEvent, 0, KernelMode, FALSE, NULL);
/* A new item can be queued now */ /* Bug */
ItemQueued = FALSE; end = KdpCurrentPosition;
num = KdpFreeBytes;
beg = (end + num) % KdpBufferSize;
num = KdpBufferSize - num;
/* Nothing to do? */
if (num == 0)
continue;
if (end > beg)
{
NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
KdpDebugBuffer + beg, num, NULL, NULL);
}
else
{
NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
KdpDebugBuffer + beg, KdpBufferSize - beg, NULL, NULL);
NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
KdpDebugBuffer, end, NULL, NULL);
}
InterlockedExchangeAddUL(&KdpFreeBytes, num);
}
} }
VOID VOID
NTAPI NTAPI
KdpPrintToLog(PCH String, KdpPrintToLogFile(PCH String,
ULONG StringLength) ULONG StringLength)
{ {
/* Don't overflow */ ULONG beg, end, num;
if ((CurrentPosition + StringLength) > BufferSize) return; KIRQL OldIrql;
/* Add the string to the buffer */ if (KdpDebugBuffer == NULL) return;
RtlCopyMemory(&DebugBuffer[CurrentPosition], String, StringLength);
/* Update the Current Position */ /* Acquire the printing spinlock without waiting at raised IRQL */
CurrentPosition += StringLength; while (TRUE)
/* Make sure we are initialized and can queue */
if (!KdpLogInitialized || (ItemQueued)) return;
/*
* Queue the work item
* Note that we don't want to queue if we are > DISPATCH_LEVEL...
* The message is in the buffer and will simply be taken care of at
* the next time we are at <= DISPATCH, so it won't be lost.
*/
if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
{ {
ExQueueWorkItem(&KdpDebugLogQueue, HyperCriticalWorkQueue); /* Wait when the spinlock becomes available */
ItemQueued = TRUE; while (!KeTestSpinLock(&KdpDebugLogSpinLock));
/* Spinlock was free, raise IRQL */
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
/* Try to get the spinlock */
if (KeTryToAcquireSpinLockAtDpcLevel(&KdpDebugLogSpinLock))
break;
/* Someone else got the spinlock, lower IRQL back */
KeLowerIrql(OldIrql);
} }
beg = KdpCurrentPosition;
num = KdpFreeBytes;
if (StringLength < num)
num = StringLength;
if (num != 0)
{
end = (beg + num) % KdpBufferSize;
KdpCurrentPosition = end;
KdpFreeBytes -= num;
if (end > beg)
{
RtlCopyMemory(KdpDebugBuffer + beg, String, num);
}
else
{
RtlCopyMemory(KdpDebugBuffer + beg, String, KdpBufferSize - beg);
RtlCopyMemory(KdpDebugBuffer, String + KdpBufferSize - beg, end);
}
}
/* Release spinlock */
KiReleaseSpinLock(&KdpDebugLogSpinLock);
/* Lower IRQL */
KeLowerIrql(OldIrql);
/* Signal the logger thread */
if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled)
KeSetEvent(&KdpLoggerThreadEvent, 0, FALSE);
} }
VOID VOID
@ -90,9 +138,11 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
ULONG BootPhase) ULONG BootPhase)
{ {
NTSTATUS Status; NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING FileName; UNICODE_STRING FileName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK Iosb; IO_STATUS_BLOCK Iosb;
HANDLE ThreadHandle;
KPRIORITY Priority;
if (!KdpDebugMode.File) return; if (!KdpDebugMode.File) return;
@ -102,11 +152,21 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
/* Write out the functions that we support for now */ /* Write out the functions that we support for now */
DispatchTable->KdpInitRoutine = KdpInitDebugLog; DispatchTable->KdpInitRoutine = KdpInitDebugLog;
DispatchTable->KdpPrintRoutine = KdpPrintToLog; DispatchTable->KdpPrintRoutine = KdpPrintToLogFile;
/* Register as a Provider */ /* Register as a Provider */
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList); InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
}
else if (BootPhase == 1)
{
/* Allocate a buffer for debug log */
KdpDebugBuffer = ExAllocatePool(NonPagedPool, KdpBufferSize);
KdpFreeBytes = KdpBufferSize;
/* Initialize spinlock */
KeInitializeSpinLock(&KdpDebugLogSpinLock);
/* Display separator + ReactOS version at start of the debug log */ /* Display separator + ReactOS version at start of the debug log */
DPRINT1("---------------------------------------------------------------\n"); DPRINT1("---------------------------------------------------------------\n");
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n"); DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
@ -117,7 +177,7 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
} }
else if (BootPhase == 3) else if (BootPhase == 3)
{ {
/* Setup the Log Name */ /* Setup the log name */
RtlInitUnicodeString(&FileName, L"\\SystemRoot\\debug.log"); RtlInitUnicodeString(&FileName, L"\\SystemRoot\\debug.log");
InitializeObjectAttributes(&ObjectAttributes, InitializeObjectAttributes(&ObjectAttributes,
&FileName, &FileName,
@ -125,9 +185,9 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
NULL, NULL,
NULL); NULL);
/* Create the Log File */ /* Create the log file */
Status = NtCreateFile(&KdbLogFileHandle, Status = NtCreateFile(&KdpLogFileHandle,
FILE_ALL_ACCESS, FILE_APPEND_DATA | SYNCHRONIZE,
&ObjectAttributes, &ObjectAttributes,
&Iosb, &Iosb,
NULL, NULL,
@ -138,9 +198,26 @@ KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
NULL, NULL,
0); 0);
/* Allow it to be used */ if (!NT_SUCCESS(Status)) return;
ExInitializeWorkItem(&KdpDebugLogQueue, &KdpPrintToLogInternal, NULL);
KdpLogInitialized = TRUE; KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE);
/* Create the logger thread */
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
KdpLoggerThread,
NULL);
if (!NT_SUCCESS(Status)) return;
Priority = 7;
NtSetInformationThread(ThreadHandle,
ThreadPriority,
&Priority,
sizeof(Priority));
} }
} }
@ -160,7 +237,7 @@ KdpSerialDebugPrint(LPSTR Message,
/* Wait when the spinlock becomes available */ /* Wait when the spinlock becomes available */
while (!KeTestSpinLock(&KdpSerialSpinLock)); while (!KeTestSpinLock(&KdpSerialSpinLock));
/* Spinlock was free, raise irql */ /* Spinlock was free, raise IRQL */
KeRaiseIrql(HIGH_LEVEL, &OldIrql); KeRaiseIrql(HIGH_LEVEL, &OldIrql);
/* Try to get the spinlock */ /* Try to get the spinlock */