Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

memprint.c File Reference

#include "exp.h"
#include <stdarg.h>
#include <string.h>
#include <memprint.h>

Go to the source code of this file.

Classes

struct  _MEM_PRINT_MESSAGE_HEADER

Defines

#define MEM_PRINT_MAX_MESSAGE_SIZE   256
#define MEM_PRINT_SUBBUFFER_SIZE   (MemPrintBufferSize / MemPrintSubbufferCount)
#define GET_MEM_PRINT_SUBBUFFER(i)   ((CSHORT)( (i) / MEM_PRINT_SUBBUFFER_SIZE ))

Typedefs

typedef _MEM_PRINT_MESSAGE_HEADER MEM_PRINT_MESSAGE_HEADER
typedef _MEM_PRINT_MESSAGE_HEADERPMEM_PRINT_MESSAGE_HEADER

Functions

VOID MemPrintWriteCompleteApc (IN PVOID ApcContext, IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved)
VOID MemPrintWriteThread (IN PVOID Dummy)
VOID MemPrintInitialize (VOID)
VOID MemPrint (CHAR *Format,...)
VOID MemPrintFlush (VOID)

Variables

CLONG MemPrintBufferSize = MEM_PRINT_DEF_BUFFER_SIZE
CLONG MemPrintSubbufferCount = MEM_PRINT_DEF_SUBBUFFER_COUNT
PCHAR MemPrintBuffer
ULONG MemPrintFlags = MEM_PRINT_FLAG_CONSOLE
KSPIN_LOCK MemPrintSpinLock
CHAR MemPrintTempBuffer [MEM_PRINT_MAX_MESSAGE_SIZE]
BOOLEAN MemPrintInitialized = FALSE
CLONG MemPrintIndex = 0
CLONG MemPrintCurrentSubbuffer = 0
BOOLEAN MemPrintSubbufferWriting [MEM_PRINT_MAX_SUBBUFFER_COUNT]
KEVENT MemPrintSubbufferFullEvent [MEM_PRINT_MAX_SUBBUFFER_COUNT]


Define Documentation

#define GET_MEM_PRINT_SUBBUFFER  )     ((CSHORT)( (i) / MEM_PRINT_SUBBUFFER_SIZE ))
 

Definition at line 62 of file memprint.c.

Referenced by MemPrint().

#define MEM_PRINT_MAX_MESSAGE_SIZE   256
 

Definition at line 53 of file memprint.c.

Referenced by MemPrint().

#define MEM_PRINT_SUBBUFFER_SIZE   (MemPrintBufferSize / MemPrintSubbufferCount)
 

Definition at line 60 of file memprint.c.

Referenced by MemPrintFlush(), and MemPrintWriteThread().


Typedef Documentation

typedef struct _MEM_PRINT_MESSAGE_HEADER MEM_PRINT_MESSAGE_HEADER
 

typedef struct _MEM_PRINT_MESSAGE_HEADER * PMEM_PRINT_MESSAGE_HEADER
 

Referenced by MemPrint(), and MemPrintFlush().


Function Documentation

VOID MemPrint CHAR Format,
  ...
 

Definition at line 250 of file memprint.c.

References ASSERT, CHAR, DbgPrint, FALSE, GET_MEM_PRINT_SUBBUFFER, KeAcquireSpinLock, KeReleaseSpinLock(), KeSetEvent(), MEM_PRINT_FLAG_CONSOLE, MEM_PRINT_FLAG_HEADER, MEM_PRINT_MAX_MESSAGE_SIZE, MemPrintBuffer, MemPrintBufferSize, MemPrintCurrentSubbuffer, MemPrintFlags, MemPrintIndex, MemPrintInitialized, MemPrintSpinLock, MemPrintSubbufferCount, MemPrintSubbufferFullEvent, MemPrintSubbufferWriting, PMEM_PRINT_MESSAGE_HEADER, _MEM_PRINT_MESSAGE_HEADER::Size, strlen(), TRUE, _MEM_PRINT_MESSAGE_HEADER::Type, and USHORT.

00256 : 00257 00258 This routine is called in place of DbgPrint to process in-memory 00259 printing. 00260 00261 Arguments: 00262 00263 Format - A format string in the style of DbgPrint. 00264 00265 - formatting arguments. 00266 00267 Return Value: 00268 00269 None. 00270 00271 --*/ 00272 00273 { 00274 va_list arglist; 00275 KIRQL oldIrql; 00276 CLONG nextSubbuffer; 00277 PMEM_PRINT_MESSAGE_HEADER messageHeader; 00278 CHAR tempBuffer[MEM_PRINT_MAX_MESSAGE_SIZE]; 00279 00280 va_start(arglist, Format); 00281 _vsnprintf( tempBuffer, sizeof( tempBuffer ), Format, arglist ); 00282 va_end(arglist); 00283 00284 // 00285 // If memory DbgPrint has not been initialized, simply print to the 00286 // console. 00287 // 00288 00289 if ( !MemPrintInitialized ) { 00290 00291 DbgPrint( "%s", tempBuffer ); 00292 return; 00293 } 00294 00295 // 00296 // Acquire the spin lock that synchronizes access to the pointers 00297 // and circular buffer. 00298 // 00299 00300 KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql ); 00301 00302 // 00303 // Make sure that the request will fit. xx_sprintf will just dump 00304 // all it gets, so assume the message is maximum size, and, if the 00305 // request would go into the next subbuffer and it is writing, fail 00306 // the request. 00307 // 00308 00309 nextSubbuffer = 00310 GET_MEM_PRINT_SUBBUFFER( MemPrintIndex + MEM_PRINT_MAX_MESSAGE_SIZE ); 00311 00312 if ( nextSubbuffer != MemPrintCurrentSubbuffer ) { 00313 00314 // 00315 // The request will go to a new subbuffer. Check if we should 00316 // wrap around to the first subbuffer (i.e. start of circular 00317 // buffer). 00318 // 00319 00320 if ( nextSubbuffer == MemPrintSubbufferCount ) { 00321 nextSubbuffer = 0; 00322 } 00323 00324 // 00325 // Is that subbuffer available for use? 00326 // 00327 00328 if ( MemPrintSubbufferWriting[nextSubbuffer] ) { 00329 00330 // 00331 // It is in use. Print to the console. Oh well. 00332 // 00333 00334 KeReleaseSpinLock( &MemPrintSpinLock, oldIrql ); 00335 00336 DbgPrint( "%s", tempBuffer ); 00337 00338 return; 00339 } 00340 00341 // 00342 // If we went to subbuffer 0 and it is available to receive 00343 // data, set up the "end of last subbuffer" conditions and reset 00344 // the index into the circular buffer. By setting a special 00345 // type value in the message header that precedes the garbage at 00346 // the end of the last subbuffer, an interpreter program can 00347 // know to skip over the garbage by using the size in the 00348 // header. This is done instead of writing only good data so 00349 // that we can write just full sectors to disk, thereby 00350 // enhancing write performance. 00351 // 00352 00353 if ( nextSubbuffer == 0 ) { 00354 00355 // 00356 // Set up the message header. This always gets done at the 00357 // end of the circular buffer, regardless of the flags bit. 00358 // 00359 00360 messageHeader = 00361 (PMEM_PRINT_MESSAGE_HEADER)&MemPrintBuffer[MemPrintIndex]; 00362 RtlStoreUshort( 00363 &messageHeader->Size, 00364 (USHORT)(MemPrintBufferSize - MemPrintIndex - 1) 00365 ); 00366 RtlStoreUshort( 00367 &messageHeader->Type, 00368 (USHORT)0xffff 00369 ); 00370 00371 // 00372 // Zero out the rest of the subbuffer. 00373 // 00374 00375 for ( MemPrintIndex += sizeof(MEM_PRINT_MESSAGE_HEADER); 00376 MemPrintIndex < MemPrintBufferSize; 00377 MemPrintIndex++ ) { 00378 00379 MemPrintBuffer[MemPrintIndex] = 0; 00380 } 00381 00382 // 00383 // Reset the index to start at the beginning of the circular 00384 // buffer. 00385 // 00386 00387 MemPrintIndex = 0; 00388 } 00389 } 00390 00391 // 00392 // Store a pointer to the location that will contain the message 00393 // header. 00394 // 00395 00396 messageHeader = (PMEM_PRINT_MESSAGE_HEADER)&MemPrintBuffer[MemPrintIndex]; 00397 00398 if ( MemPrintFlags & MEM_PRINT_FLAG_HEADER ) { 00399 MemPrintIndex += sizeof(MEM_PRINT_MESSAGE_HEADER); 00400 } 00401 00402 // 00403 // Dump the formatted string to the subbuffer. xx_sprintf is a special 00404 // version of sprintf that takes a variable argument list. 00405 // 00406 00407 ASSERT( MemPrintIndex + MEM_PRINT_MAX_MESSAGE_SIZE - 00408 sizeof(MEM_PRINT_MESSAGE_HEADER) <= MemPrintBufferSize ); 00409 00410 00411 RtlMoveMemory( &MemPrintBuffer[MemPrintIndex], tempBuffer, strlen(tempBuffer)+1 ); 00412 00413 MemPrintIndex += strlen(tempBuffer); 00414 00415 // 00416 // Write the total message size to the message header. 00417 // 00418 00419 if ( MemPrintFlags & MEM_PRINT_FLAG_HEADER ) { 00420 messageHeader->Size = 00421 (USHORT)( &MemPrintBuffer[MemPrintIndex] - (PCHAR)messageHeader ); 00422 messageHeader->Type = (USHORT)0xdead; 00423 messageHeader++; 00424 } 00425 00426 // 00427 // If it was too large, there's a potential problem with writing off 00428 // the end of the circular buffer. Print the offending message to 00429 // the console and breakpoint. 00430 // 00431 00432 if ( &MemPrintBuffer[MemPrintIndex] - (PCHAR)messageHeader > 00433 MEM_PRINT_MAX_MESSAGE_SIZE ) { 00434 DbgPrint( "Message too long!! :\n" ); 00435 DbgPrint( "%s", messageHeader ); 00436 DbgBreakPoint( ); 00437 } 00438 00439 // 00440 // Print to the console if the appropriate flag is on. 00441 // 00442 00443 if ( MemPrintFlags & MEM_PRINT_FLAG_CONSOLE ) { 00444 DbgPrint( "%s", messageHeader ); 00445 } 00446 00447 // 00448 // Calculate whether we have stepped into a new subbuffer. 00449 // 00450 00451 nextSubbuffer = GET_MEM_PRINT_SUBBUFFER( MemPrintIndex ); 00452 00453 if ( nextSubbuffer != MemPrintCurrentSubbuffer ) { 00454 00455 //DbgPrint( "Subbuffer %ld complete.\n", MemPrintCurrentSubbuffer ); 00456 00457 // 00458 // We did step into a new subbuffer, so set the boolean to 00459 // indicate that the old subbuffer is writing to disk, thereby 00460 // preventing it from being overwritten until the write is 00461 // complete. 00462 // 00463 00464 MemPrintSubbufferWriting[MemPrintCurrentSubbuffer] = TRUE; 00465 00466 // 00467 // Set the event that will wake up the thread writing subbuffers 00468 // to disk. 00469 // 00470 00471 KeSetEvent( 00472 &MemPrintSubbufferFullEvent[MemPrintCurrentSubbuffer], 00473 2, 00474 FALSE 00475 ); 00476 00477 // 00478 // Update the current subbuffer. 00479 // 00480 00481 MemPrintCurrentSubbuffer = nextSubbuffer; 00482 } 00483 00484 KeReleaseSpinLock( &MemPrintSpinLock, oldIrql ); 00485 00486 return; 00487 00488 } // MemPrint

VOID MemPrintFlush VOID   ) 
 

Definition at line 492 of file memprint.c.

References DbgPrint, FALSE, KeAcquireSpinLock, KeDelayExecutionThread(), KeReleaseSpinLock(), KernelMode, KeSetEvent(), MEM_PRINT_SUBBUFFER_SIZE, MemPrintBuffer, MemPrintBufferSize, MemPrintCurrentSubbuffer, MemPrintIndex, MemPrintSpinLock, MemPrintSubbufferFullEvent, MemPrintSubbufferWriting, PMEM_PRINT_MESSAGE_HEADER, _MEM_PRINT_MESSAGE_HEADER::Size, TRUE, _MEM_PRINT_MESSAGE_HEADER::Type, and USHORT.

00498 : 00499 00500 This routine causes the current subbuffer to be written to disk, 00501 regardless of how full it is. The unwritten part of the subbuffer 00502 is zeroed before writing. 00503 00504 Arguments: 00505 00506 None. 00507 00508 Return Value: 00509 00510 None. 00511 00512 --*/ 00513 00514 { 00515 KIRQL oldIrql; 00516 PMEM_PRINT_MESSAGE_HEADER messageHeader; 00517 CLONG nextSubbufferIndex; 00518 LARGE_INTEGER delayInterval; 00519 00520 // 00521 // Acquire the spin lock that protects memory DbgPrint variables. 00522 // 00523 00524 KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql ); 00525 00526 DbgPrint( "Flushing subbuffer %ld\n", MemPrintCurrentSubbuffer ); 00527 00528 // 00529 // Set up the header that indicates that unused space follows. 00530 // 00531 00532 messageHeader = 00533 (PMEM_PRINT_MESSAGE_HEADER)&MemPrintBuffer[MemPrintIndex]; 00534 messageHeader->Size = 00535 (USHORT)(MemPrintBufferSize - MemPrintIndex - 1); 00536 messageHeader->Type = (USHORT)0xffff; 00537 00538 // 00539 // Determine where the next subbuffer starts. 00540 // 00541 00542 nextSubbufferIndex = 00543 (MemPrintCurrentSubbuffer + 1) * MEM_PRINT_SUBBUFFER_SIZE; 00544 00545 // 00546 // Zero out the rest of the subbuffer. 00547 // 00548 00549 for ( MemPrintIndex += sizeof(MEM_PRINT_MESSAGE_HEADER); 00550 MemPrintIndex < nextSubbufferIndex; 00551 MemPrintIndex++ ) { 00552 00553 MemPrintBuffer[MemPrintIndex] = 0; 00554 } 00555 00556 // 00557 // Indicate that the subbuffer should be written to disk. 00558 // 00559 00560 MemPrintSubbufferWriting[MemPrintCurrentSubbuffer] = TRUE; 00561 00562 KeSetEvent( 00563 &MemPrintSubbufferFullEvent[MemPrintCurrentSubbuffer], 00564 8, 00565 FALSE 00566 ); 00567 00568 // 00569 // Increment the current subbuffer so that it corresponds with the 00570 // buffer index. 00571 // 00572 00573 MemPrintCurrentSubbuffer++; 00574 00575 KeReleaseSpinLock( &MemPrintSpinLock, oldIrql ); 00576 00577 // 00578 // Delay so that the memory print write thread wakes up and performs 00579 // the write to disk. 00580 // 00581 // !!! This is obviously not a perfect solution--the write thread 00582 // may never wake up, so this could complete before the flush 00583 // is really done. 00584 // 00585 00586 delayInterval.QuadPart = -10*10*1000*1000; 00587 00588 DbgPrint( "Delaying...\n" ); 00589 KeDelayExecutionThread( KernelMode, TRUE, &delayInterval ); 00590 DbgPrint( "Woke up.\n" ); 00591 00592 return; 00593 00594 } // MemPrintFlush

VOID MemPrintInitialize VOID   ) 
 

Definition at line 124 of file memprint.c.

References DbgPrint, ExAllocatePoolWithTag, FALSE, KeInitializeEvent, KeInitializeSpinLock(), MEM_PRINT_MAX_SUBBUFFER_COUNT, MemPrintBuffer, MemPrintBufferSize, MemPrintInitialized, MemPrintSpinLock, MemPrintSubbufferCount, MemPrintSubbufferFullEvent, MemPrintSubbufferWriting, MemPrintWriteThread(), NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, PsCreateSystemThread(), and TRUE.

00130 : 00131 00132 This is the initialization routine for the in-memory DbgPrint routine. 00133 It should be called before the first call to MemPrint to set up the 00134 various structures used and to start the log file write thread. 00135 00136 Arguments: 00137 00138 None. 00139 00140 Return Value: 00141 00142 None. 00143 00144 --*/ 00145 00146 { 00147 CLONG i; 00148 NTSTATUS status; 00149 HANDLE threadHandle; 00150 00151 if ( MemPrintInitialized ) { 00152 return; 00153 } 00154 00155 // 00156 // Allocate memory for the circular buffer that will receive 00157 // the text and data. If we can't do it, try again with a buffer 00158 // half as large. If that fails, quit trying. 00159 // 00160 00161 MemPrintBuffer = ExAllocatePoolWithTag( NonPagedPool, MemPrintBufferSize, 'rPeM' ); 00162 00163 if ( MemPrintBuffer == NULL ) { 00164 00165 MemPrintBufferSize /= 2; 00166 DbgPrint( "Unable to allocate DbgPrint buffer--trying size = %ld\n", 00167 MemPrintBufferSize ); 00168 MemPrintBuffer = ExAllocatePoolWithTag( NonPagedPool, MemPrintBufferSize, 'rPeM' ); 00169 00170 if ( MemPrintBuffer == NULL ) { 00171 DbgPrint( "Couldn't allocate DbgPrint buffer.\n" ); 00172 return; 00173 } else { 00174 //DbgPrint( "MemPrint buffer from %lx to %lx\n", 00175 // MemPrintBuffer, MemPrintBuffer + MemPrintBufferSize ); 00176 } 00177 00178 } else { 00179 //DbgPrint( "MemPrint buffer from %lx to %lx\n", 00180 // MemPrintBuffer, MemPrintBuffer + MemPrintBufferSize ); 00181 } 00182 00183 // 00184 // Allocate the spin lock that protects access to the various 00185 // pointers and the circular buffer. This ensures integrity of the 00186 // buffer. 00187 // 00188 00189 KeInitializeSpinLock( &MemPrintSpinLock ); 00190 00191 // 00192 // Make sure that the subbuffer count is in range. (We assume that 00193 // the number is a power of 2.) 00194 // 00195 00196 if ( MemPrintSubbufferCount < 2 ) { 00197 MemPrintSubbufferCount = 2; 00198 } else if ( MemPrintSubbufferCount > MEM_PRINT_MAX_SUBBUFFER_COUNT ) { 00199 MemPrintSubbufferCount = MEM_PRINT_MAX_SUBBUFFER_COUNT; 00200 } 00201 00202 // 00203 // Initialize the array of BOOLEANs that determines which subbuffers 00204 // are being written to disk and therefore cannot be used to store 00205 // new DbgPrint data. 00206 // 00207 // Initialize the array of events that indicates that a subbuffer is 00208 // ready to be written to disk. 00209 // 00210 00211 for ( i = 0; i < MemPrintSubbufferCount; i++ ) { 00212 MemPrintSubbufferWriting[i] = FALSE; 00213 KeInitializeEvent( 00214 &MemPrintSubbufferFullEvent[i], 00215 SynchronizationEvent, 00216 FALSE 00217 ); 00218 } 00219 00220 // 00221 // Start the thread that writes subbuffers from the large circular 00222 // buffer to disk. 00223 // 00224 00225 status = PsCreateSystemThread( 00226 &threadHandle, 00227 PROCESS_ALL_ACCESS, 00228 NULL, 00229 NtCurrentProcess(), 00230 NULL, 00231 MemPrintWriteThread, 00232 NULL 00233 ); 00234 00235 if ( !NT_SUCCESS(status) ) { 00236 DbgPrint( "MemPrintInitialize: PsCreateSystemThread failed: %X\n", 00237 status ); 00238 return; 00239 } 00240 00241 MemPrintInitialized = TRUE; 00242 ZwClose( threadHandle ); 00243 00244 return; 00245 00246 } // MemPrintInitialize

VOID MemPrintWriteCompleteApc IN PVOID  ApcContext,
IN PIO_STATUS_BLOCK  IoStatusBlock,
IN ULONG  Reserved
 

Definition at line 862 of file memprint.c.

References DbgPrint, FALSE, KeAcquireSpinLock, KeReleaseSpinLock(), MemPrintSpinLock, MemPrintSubbufferWriting, and NT_SUCCESS.

Referenced by MemPrintWriteThread().

00870 : 00871 00872 This APC routine is called when subbuffer writes to disk complete. 00873 It checks for success, printing a message if the write failed. 00874 It also sets the appropriate MemPrintSubbufferWriting location to 00875 FALSE so that the subbuffer can be reused. 00876 00877 Arguments: 00878 00879 ApcContext - contains the index of the subbuffer just written. 00880 00881 IoStatusBlock - the status block for the operation. 00882 00883 Reserved - not used; reserved for future use. 00884 00885 Return Value: 00886 00887 None. 00888 00889 --*/ 00890 00891 { 00892 KIRQL oldIrql; 00893 00894 if ( !NT_SUCCESS(IoStatusBlock->Status) ) { 00895 DbgPrint( "NtWriteFile for subbuffer %ld failed: %X\n", 00896 ApcContext, IoStatusBlock->Status ); 00897 return; 00898 } 00899 00900 //DbgPrint( "Write complete for subbuffer %ld.\n", ApcContext ); 00901 DbgPrint( "." ); 00902 00903 // 00904 // Acquire the spin lock that protects memory print global variables 00905 // and set the subbuffer writing boolean to FALSE so that other 00906 // threads can write to the subbuffer if necessary. 00907 // 00908 00909 KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql ); 00910 MemPrintSubbufferWriting[ (ULONG_PTR)ApcContext ] = FALSE; 00911 KeReleaseSpinLock( &MemPrintSpinLock, oldIrql ); 00912 00913 return; 00914 00915 Reserved; 00916 00917 } // MemPrintWriteCompleteApc } // MemPrintWriteCompleteApc

VOID MemPrintWriteThread IN PVOID  Dummy  ) 
 

Definition at line 598 of file memprint.c.

References ASSERT, DbgPrint, Executive, FALSE, KeAcquireSpinLock, KeDelayExecutionThread(), KeReleaseSpinLock(), KernelMode, KeWaitForMultipleObjects(), L, MEM_PRINT_FLAG_FILE, MEM_PRINT_LOG_FILE_NAME, MEM_PRINT_MAX_SUBBUFFER_COUNT, MEM_PRINT_SUBBUFFER_SIZE, MemPrintBuffer, MemPrintBufferSize, MemPrintFlags, MemPrintSpinLock, MemPrintSubbufferCount, MemPrintSubbufferFullEvent, MemPrintSubbufferWriting, MemPrintWriteCompleteApc(), NT_SUCCESS, NtCreateFile(), NtSetInformationFile(), NtSetInformationThread(), NTSTATUS(), NtTerminateThread(), NtWriteFile(), NULL, RtlAnsiStringToUnicodeString(), RtlFreeUnicodeString(), RtlInitAnsiString(), and TRUE.

Referenced by MemPrintInitialize().

00604 : 00605 00606 The log file write thread executes this routine. It sets up the 00607 log file for writing, then waits for subbuffers to fill, writing 00608 them to disk when they do. When the log file fills, new space 00609 for it is allocated on disk to prevent the file system from 00610 having to do it. 00611 00612 Arguments: 00613 00614 Dummy - Ignored. 00615 00616 Return Value: 00617 00618 None. 00619 00620 --*/ 00621 00622 { 00623 NTSTATUS status; 00624 IO_STATUS_BLOCK ioStatusBlock[MEM_PRINT_MAX_SUBBUFFER_COUNT]; 00625 IO_STATUS_BLOCK localIoStatusBlock; 00626 CLONG i; 00627 KPRIORITY threadPriorityLevel; 00628 00629 NTSTATUS waitStatus; 00630 PVOID waitObjects[64]; 00631 KWAIT_BLOCK waitBlockArray[MEM_PRINT_MAX_SUBBUFFER_COUNT]; 00632 00633 OBJECT_ATTRIBUTES objectAttributes; 00634 PCHAR fileName = MEM_PRINT_LOG_FILE_NAME; 00635 ANSI_STRING fileNameString; 00636 HANDLE fileHandle; 00637 00638 LARGE_INTEGER fileAllocation; 00639 LARGE_INTEGER fileAllocationIncrement; 00640 LARGE_INTEGER totalBytesWritten; 00641 LARGE_INTEGER writeSize; 00642 00643 LARGE_INTEGER delayInterval; 00644 ULONG attempts = 0; 00645 00646 UNICODE_STRING UnicodeFileName; 00647 00648 Dummy; 00649 00650 // 00651 // Initialize the string containing the file name and the object 00652 // attributes structure that will describe the log file to open. 00653 // 00654 00655 RtlInitAnsiString( &fileNameString, fileName ); 00656 status = RtlAnsiStringToUnicodeString(&UnicodeFileName,&fileNameString,TRUE); 00657 if ( !NT_SUCCESS(status) ) { 00658 NtTerminateThread( NtCurrentThread(), status ); 00659 } 00660 00661 InitializeObjectAttributes( 00662 &objectAttributes, 00663 &UnicodeFileName, 00664 OBJ_CASE_INSENSITIVE, 00665 NULL, 00666 NULL 00667 ); 00668 00669 // 00670 // Set the allocation size of the log file to be three times the 00671 // size of the circular buffer. When it fills up, we'll extend 00672 // it. 00673 // 00674 00675 fileAllocationIncrement.LowPart = MemPrintBufferSize * 8; 00676 fileAllocationIncrement.HighPart = 0; 00677 fileAllocation = fileAllocationIncrement; 00678 00679 // 00680 // Open the log file. 00681 // 00682 // !!! The loop here is to help avoid a system initialization 00683 // timing problem, and should be removed when the problem is 00684 // fixed. 00685 // 00686 00687 while ( TRUE ) { 00688 00689 status = NtCreateFile( 00690 &fileHandle, 00691 FILE_WRITE_DATA, 00692 &objectAttributes, 00693 &localIoStatusBlock, 00694 &fileAllocation, 00695 FILE_ATTRIBUTE_NORMAL, 00696 FILE_SHARE_READ, 00697 FILE_OVERWRITE_IF, 00698 FILE_SEQUENTIAL_ONLY, 00699 NULL, 00700 0L 00701 ); 00702 00703 if ( (status != STATUS_OBJECT_PATH_NOT_FOUND) || (++attempts >= 3) ) { 00704 RtlFreeUnicodeString(&UnicodeFileName); 00705 break; 00706 } 00707 00708 delayInterval.QuadPart = -5*10*1000*1000; // five second delay 00709 KeDelayExecutionThread( KernelMode, FALSE, &delayInterval ); 00710 00711 } 00712 00713 if ( !NT_SUCCESS(status) ) { 00714 DbgPrint( "NtCreateFile for log file failed: %X\n", status ); 00715 NtTerminateThread( NtCurrentThread(), status ); 00716 } 00717 00718 // 00719 // Initialize the total bytes written and write size variables. 00720 // 00721 00722 totalBytesWritten.LowPart = 0; 00723 totalBytesWritten.HighPart = 0; 00724 writeSize.LowPart = MEM_PRINT_SUBBUFFER_SIZE; 00725 writeSize.HighPart = 0; 00726 00727 // 00728 // Set up the wait objects array for a call to KeWaitForMultipleObjects. 00729 // 00730 00731 for ( i = 0; i < MemPrintSubbufferCount; i++ ) { 00732 waitObjects[i] = &MemPrintSubbufferFullEvent[i]; 00733 } 00734 00735 // 00736 // Set the priority of the write thread. 00737 // 00738 00739 threadPriorityLevel = LOW_REALTIME_PRIORITY + 1; 00740 00741 status = NtSetInformationThread( 00742 NtCurrentThread(), 00743 ThreadPriority, 00744 &threadPriorityLevel, 00745 sizeof(threadPriorityLevel) 00746 ); 00747 00748 if ( !NT_SUCCESS(status) ) { 00749 DbgPrint( "Unable to set error log thread priority: %X\n", status ); 00750 } 00751 00752 // 00753 // Loop waiting for one of the subbuffer full events to be signaled. 00754 // When one is signaled, wake up and write the subbuffer to the log 00755 // file. 00756 // 00757 00758 while ( TRUE ) { 00759 00760 waitStatus = KeWaitForMultipleObjects( 00761 (CCHAR)MemPrintSubbufferCount, 00762 waitObjects, 00763 WaitAny, 00764 Executive, 00765 KernelMode, 00766 TRUE, 00767 NULL, 00768 waitBlockArray 00769 ); 00770 00771 if ( !NT_SUCCESS(waitStatus) ) { 00772 DbgPrint( "KeWaitForMultipleObjects failed: %X\n", waitStatus ); 00773 NtTerminateThread( NtCurrentThread(), waitStatus ); 00774 } //else { 00775 //DbgPrint( "Writing subbuffer %ld...\n", waitStatus ); 00776 //} 00777 00778 ASSERT( (CCHAR)waitStatus < (CCHAR)MemPrintSubbufferCount ); 00779 00780 // 00781 // Check the DbgPrint flags to see if we really want to write 00782 // this. 00783 // 00784 00785 if ( (MemPrintFlags & MEM_PRINT_FLAG_FILE) == 0 ) { 00786 00787 KIRQL oldIrql; 00788 00789 KeAcquireSpinLock( &MemPrintSpinLock, &oldIrql ); 00790 MemPrintSubbufferWriting[ waitStatus ] = FALSE; 00791 KeReleaseSpinLock( &MemPrintSpinLock, oldIrql ); 00792 00793 continue; 00794 } 00795 00796 // 00797 // Start the write operation. The APC routine will handle 00798 // checking the return status from the write and resetting 00799 // the MemPrintSubbufferWriting boolean. 00800 // 00801 00802 status = NtWriteFile( 00803 fileHandle, 00804 NULL, 00805 MemPrintWriteCompleteApc, 00806 (PVOID)waitStatus, 00807 &ioStatusBlock[waitStatus], 00808 &MemPrintBuffer[waitStatus * MEM_PRINT_SUBBUFFER_SIZE], 00809 MEM_PRINT_SUBBUFFER_SIZE, 00810 &totalBytesWritten, 00811 NULL 00812 ); 00813 00814 if ( !NT_SUCCESS(status) ) { 00815 DbgPrint( "NtWriteFile for log file failed: %X\n", status ); 00816 } 00817 00818 // 00819 // Update the count of bytes written to the log file. 00820 // 00821 00822 totalBytesWritten.QuadPart = totalBytesWritten.QuadPart + writeSize.QuadPart; 00823 00824 // 00825 // Extend the file if we have reached the end of what we have 00826 // thus far allocated for the file. This increases performance 00827 // by extending the file here rather than in the file system, 00828 // which would have to extend it each time a write past end of 00829 // file comes in. 00830 // 00831 00832 if ( totalBytesWritten.QuadPart >= fileAllocation.QuadPart ) { 00833 00834 fileAllocation.QuadPart = 00835 fileAllocation.QuadPart + fileAllocationIncrement.QuadPart; 00836 00837 DbgPrint( "Enlarging log file to %ld bytes.\n", 00838 fileAllocation.LowPart ); 00839 00840 status = NtSetInformationFile( 00841 fileHandle, 00842 &localIoStatusBlock, 00843 &fileAllocation, 00844 sizeof(fileAllocation), 00845 FileAllocationInformation 00846 ); 00847 00848 if ( !NT_SUCCESS(status) ) { 00849 DbgPrint( "Attempt to extend log file failed: %X\n", status ); 00850 fileAllocation.QuadPart = 00851 fileAllocation.QuadPart - fileAllocationIncrement.QuadPart; 00852 } 00853 } 00854 } 00855 00856 return; 00857 00858 } // MemPrintWriteThread


Variable Documentation

PCHAR MemPrintBuffer
 

Definition at line 80 of file memprint.c.

Referenced by MemPrint(), MemPrintFlush(), MemPrintInitialize(), and MemPrintWriteThread().

CLONG MemPrintBufferSize = MEM_PRINT_DEF_BUFFER_SIZE
 

Definition at line 78 of file memprint.c.

Referenced by MemPrint(), MemPrintFlush(), MemPrintInitialize(), and MemPrintWriteThread().

CLONG MemPrintCurrentSubbuffer = 0
 

Definition at line 102 of file memprint.c.

Referenced by MemPrint(), and MemPrintFlush().

ULONG MemPrintFlags = MEM_PRINT_FLAG_CONSOLE
 

Definition at line 82 of file memprint.c.

Referenced by MemPrint(), and MemPrintWriteThread().

CLONG MemPrintIndex = 0
 

Definition at line 94 of file memprint.c.

Referenced by MemPrint(), and MemPrintFlush().

BOOLEAN MemPrintInitialized = FALSE
 

Definition at line 88 of file memprint.c.

Referenced by MemPrint(), and MemPrintInitialize().

KSPIN_LOCK MemPrintSpinLock
 

Definition at line 84 of file memprint.c.

Referenced by MemPrint(), MemPrintFlush(), MemPrintInitialize(), MemPrintWriteCompleteApc(), and MemPrintWriteThread().

CLONG MemPrintSubbufferCount = MEM_PRINT_DEF_SUBBUFFER_COUNT
 

Definition at line 79 of file memprint.c.

Referenced by MemPrint(), MemPrintInitialize(), and MemPrintWriteThread().

KEVENT MemPrintSubbufferFullEvent[MEM_PRINT_MAX_SUBBUFFER_COUNT]
 

Definition at line 120 of file memprint.c.

Referenced by MemPrint(), MemPrintFlush(), MemPrintInitialize(), and MemPrintWriteThread().

BOOLEAN MemPrintSubbufferWriting[MEM_PRINT_MAX_SUBBUFFER_COUNT]
 

Definition at line 110 of file memprint.c.

Referenced by MemPrint(), MemPrintFlush(), MemPrintInitialize(), MemPrintWriteCompleteApc(), and MemPrintWriteThread().

CHAR MemPrintTempBuffer[MEM_PRINT_MAX_MESSAGE_SIZE]
 

Definition at line 86 of file memprint.c.


Generated on Sat May 15 19:44:37 2004 for test by doxygen 1.3.7