blob: bcf967038a45b7bf12a1a612093a3529fd547363 [file] [log] [blame]
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "utils/PlatformDebugLogger.h"
#include "common/Assert.h"
#include "common/windows_with_undefs.h"
#include <array>
#include <thread>
namespace utils {
class WindowsDebugLogger : public PlatformDebugLogger {
public:
WindowsDebugLogger() : PlatformDebugLogger() {
if (IsDebuggerPresent()) {
// This condition is true when running inside Visual Studio or some other debugger.
// Messages are already printed there so we don't need to do anything.
return;
}
mShouldExitHandle = CreateEventA(nullptr, TRUE, FALSE, nullptr);
ASSERT(mShouldExitHandle != nullptr);
mThread = std::thread(
[](HANDLE shouldExit) {
// https://blogs.msdn.microsoft.com/reiley/2011/07/29/a-debugging-approach-to-outputdebugstring/
// for the layout of this struct.
struct {
DWORD process_id;
char data[4096 - sizeof(DWORD)];
}* dbWinBuffer = nullptr;
HANDLE file = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE,
0, sizeof(*dbWinBuffer), "DBWIN_BUFFER");
ASSERT(file != nullptr);
ASSERT(file != INVALID_HANDLE_VALUE);
dbWinBuffer = static_cast<decltype(dbWinBuffer)>(
MapViewOfFile(file, SECTION_MAP_READ, 0, 0, 0));
ASSERT(dbWinBuffer != nullptr);
HANDLE dbWinBufferReady =
CreateEventA(nullptr, FALSE, FALSE, "DBWIN_BUFFER_READY");
ASSERT(dbWinBufferReady != nullptr);
HANDLE dbWinDataReady = CreateEventA(nullptr, FALSE, FALSE, "DBWIN_DATA_READY");
ASSERT(dbWinDataReady != nullptr);
std::array<HANDLE, 2> waitHandles = {shouldExit, dbWinDataReady};
while (true) {
SetEvent(dbWinBufferReady);
DWORD wait = WaitForMultipleObjects(waitHandles.size(), waitHandles.data(),
FALSE, INFINITE);
if (wait == WAIT_OBJECT_0) {
break;
}
ASSERT(wait == WAIT_OBJECT_0 + 1);
fprintf(stderr, "%.*s\n", static_cast<int>(sizeof(dbWinBuffer->data)),
dbWinBuffer->data);
fflush(stderr);
}
CloseHandle(dbWinDataReady);
CloseHandle(dbWinBufferReady);
UnmapViewOfFile(dbWinBuffer);
CloseHandle(file);
},
mShouldExitHandle);
}
~WindowsDebugLogger() override {
if (IsDebuggerPresent()) {
// This condition is true when running inside Visual Studio or some other debugger.
// Messages are already printed there so we don't need to do anything.
return;
}
if (mShouldExitHandle != nullptr) {
BOOL result = SetEvent(mShouldExitHandle);
ASSERT(result != 0);
CloseHandle(mShouldExitHandle);
}
if (mThread.joinable()) {
mThread.join();
}
}
private:
std::thread mThread;
HANDLE mShouldExitHandle = INVALID_HANDLE_VALUE;
};
PlatformDebugLogger* CreatePlatformDebugLogger() {
return new WindowsDebugLogger();
}
} // namespace utils