• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "utils/PlatformDebugLogger.h"
16 
17 #include "common/Assert.h"
18 #include "common/windows_with_undefs.h"
19 
20 #include <array>
21 #include <thread>
22 
23 namespace utils {
24 
25     class WindowsDebugLogger : public PlatformDebugLogger {
26       public:
WindowsDebugLogger()27         WindowsDebugLogger() : PlatformDebugLogger() {
28             if (IsDebuggerPresent()) {
29                 // This condition is true when running inside Visual Studio or some other debugger.
30                 // Messages are already printed there so we don't need to do anything.
31                 return;
32             }
33 
34             mShouldExitHandle = CreateEventA(nullptr, TRUE, FALSE, nullptr);
35             ASSERT(mShouldExitHandle != nullptr);
36 
37             mThread = std::thread(
38                 [](HANDLE shouldExit) {
39                     // https://blogs.msdn.microsoft.com/reiley/2011/07/29/a-debugging-approach-to-outputdebugstring/
40                     // for the layout of this struct.
41                     struct {
42                         DWORD process_id;
43                         char data[4096 - sizeof(DWORD)];
44                     }* dbWinBuffer = nullptr;
45 
46                     HANDLE file = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE,
47                                                      0, sizeof(*dbWinBuffer), "DBWIN_BUFFER");
48                     ASSERT(file != nullptr);
49                     ASSERT(file != INVALID_HANDLE_VALUE);
50 
51                     dbWinBuffer = static_cast<decltype(dbWinBuffer)>(
52                         MapViewOfFile(file, SECTION_MAP_READ, 0, 0, 0));
53                     ASSERT(dbWinBuffer != nullptr);
54 
55                     HANDLE dbWinBufferReady =
56                         CreateEventA(nullptr, FALSE, FALSE, "DBWIN_BUFFER_READY");
57                     ASSERT(dbWinBufferReady != nullptr);
58 
59                     HANDLE dbWinDataReady = CreateEventA(nullptr, FALSE, FALSE, "DBWIN_DATA_READY");
60                     ASSERT(dbWinDataReady != nullptr);
61 
62                     std::array<HANDLE, 2> waitHandles = {shouldExit, dbWinDataReady};
63                     while (true) {
64                         SetEvent(dbWinBufferReady);
65                         DWORD wait = WaitForMultipleObjects(waitHandles.size(), waitHandles.data(),
66                                                             FALSE, INFINITE);
67                         if (wait == WAIT_OBJECT_0) {
68                             break;
69                         }
70                         ASSERT(wait == WAIT_OBJECT_0 + 1);
71                         fprintf(stderr, "%.*s\n", static_cast<int>(sizeof(dbWinBuffer->data)),
72                                 dbWinBuffer->data);
73                         fflush(stderr);
74                     }
75 
76                     CloseHandle(dbWinDataReady);
77                     CloseHandle(dbWinBufferReady);
78                     UnmapViewOfFile(dbWinBuffer);
79                     CloseHandle(file);
80                 },
81                 mShouldExitHandle);
82         }
83 
~WindowsDebugLogger()84         ~WindowsDebugLogger() override {
85             if (IsDebuggerPresent()) {
86                 // This condition is true when running inside Visual Studio or some other debugger.
87                 // Messages are already printed there so we don't need to do anything.
88                 return;
89             }
90 
91             if (mShouldExitHandle != nullptr) {
92                 BOOL result = SetEvent(mShouldExitHandle);
93                 ASSERT(result != 0);
94                 CloseHandle(mShouldExitHandle);
95             }
96 
97             if (mThread.joinable()) {
98                 mThread.join();
99             }
100         }
101 
102       private:
103         std::thread mThread;
104         HANDLE mShouldExitHandle = INVALID_HANDLE_VALUE;
105     };
106 
CreatePlatformDebugLogger()107     PlatformDebugLogger* CreatePlatformDebugLogger() {
108         return new WindowsDebugLogger();
109     }
110 
111 }  // namespace utils
112