EXTERN_C void LogIrpShutdownHandler() { PAGED_CODE(); LOG_DEBUG("Flushing... (Max log usage = %08x bytes)", g_LogpLogBufferInfo.LogMaximumUsage); LOG_INFO("Bye!"); g_LogpDebugFlag = LOG_PUT_LEVEL_DISABLE; // Wait until the log buffer is emptied. auto &info = g_LogpLogBufferInfo; while (info.LogBufferHead[0]) { LogpSleep(LOGP_AUTO_FLUSH_INTERVAL_MSEC); } }
// Terminates the log functions without releasing resources. _Use_decl_annotations_ void LogIrpShutdownHandler() { PAGED_CODE(); HYPERPLATFORM_LOG_DEBUG("Flushing... (Max log usage = %08x bytes)", g_logp_log_buffer_info.log_max_usage); HYPERPLATFORM_LOG_INFO("Bye!"); g_logp_debug_flag = kLogPutLevelDisable; // Wait until the log buffer is emptied. auto &info = g_logp_log_buffer_info; while (info.log_buffer_head[0]) { LogpSleep(kLogpLogFlushIntervalMsec); } }
// Initializes a log file and startes a log buffer thread. _Use_decl_annotations_ static NTSTATUS LogpInitializeLogFile( LogBufferInfo *info) { PAGED_CODE(); if (info->log_file_handle) { return STATUS_SUCCESS; } // Initialize a log file UNICODE_STRING log_file_path_u = {}; RtlInitUnicodeString(&log_file_path_u, info->log_file_path); OBJECT_ATTRIBUTES oa = {}; InitializeObjectAttributes(&oa, &log_file_path_u, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, nullptr, nullptr); IO_STATUS_BLOCK io_status = {}; auto status = ZwCreateFile( &info->log_file_handle, FILE_APPEND_DATA | SYNCHRONIZE, &oa, &io_status, nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, nullptr, 0); if (!NT_SUCCESS(status)) { return status; } // Initialize a log buffer flush thread. info->buffer_flush_thread_should_be_alive = true; status = PsCreateSystemThread(&info->buffer_flush_thread_handle, GENERIC_ALL, nullptr, nullptr, nullptr, LogpBufferFlushThreadRoutine, info); if (!NT_SUCCESS(status)) { ZwClose(info->log_file_handle); info->log_file_handle = nullptr; info->buffer_flush_thread_should_be_alive = false; return status; } // Wait until the thead has started while (!info->buffer_flush_thread_started) { LogpSleep(100); } return status; }
EXTERN_C static VOID LogpBufferFlushThreadRoutine(_In_ void *StartContext) { PAGED_CODE(); auto status = STATUS_SUCCESS; auto info = reinterpret_cast<LogBufferInfo *>(StartContext); LOG_DEBUG("Log thread started."); NT_ASSERT(LogpIsLogFileEnabled(*info)); while (info->BufferFlushThreadShouldBeAlive) { LogpSleep(LOGP_AUTO_FLUSH_INTERVAL_MSEC); if (info->LogBufferHead[0]) { NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); NT_ASSERT(!KeAreAllApcsDisabled()); status = LogpWriteLogBufferToFile(info); // Do not flush the file for overall performance. Even a case of // bug check, we should be able to recover logs by looking at both // log buffers. } } LOG_DEBUG("Log thread is ending."); PsTerminateSystemThread(status); }
// A thread runs as long as info.buffer_flush_thread_should_be_alive is true and // flushes a log buffer to a log file every kLogpLogFlushIntervalMsec msec. _Use_decl_annotations_ static VOID LogpBufferFlushThreadRoutine( void *start_context) { PAGED_CODE(); auto status = STATUS_SUCCESS; auto info = reinterpret_cast<LogBufferInfo *>(start_context); info->buffer_flush_thread_started = true; HYPERPLATFORM_LOG_DEBUG("Log thread started (TID= %p).", PsGetCurrentThreadId()); while (info->buffer_flush_thread_should_be_alive) { NT_ASSERT(LogpIsLogFileActivated(*info)); if (info->log_buffer_head[0]) { NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); NT_ASSERT(!KeAreAllApcsDisabled()); status = LogpFlushLogBuffer(info); // Do not flush the file for overall performance. Even a case of // bug check, we should be able to recover logs by looking at both // log buffers. } LogpSleep(kLogpLogFlushIntervalMsec); } PsTerminateSystemThread(status); }