OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // The memory_watcher.dll is hooked by simply linking it. When we get the | |
6 // windows notification that this DLL is loaded, we do a few things: | |
7 // 1) Register a Hot Key. | |
8 // Only one process can hook the Hot Key, so one will get it, and the | |
9 // others will silently fail. | |
10 // 2) Create a thread to wait on an event. | |
11 // Since only one process will get the HotKey, it will be responsible for | |
12 // notifying all process when it's time to do something. Each process | |
13 // will have a thread waiting for communication from the master to dump | |
14 // the callstacks. | |
15 | |
16 #include <windows.h> | |
17 | |
18 #include "base/at_exit.h" | |
19 #include "tools/memory_watcher/memory_watcher.h" | |
20 #include "tools/memory_watcher/hotkey.h" | |
21 | |
22 class MemoryWatcherDumpKey; // Defined below. | |
23 | |
24 static wchar_t* kDumpEvent = L"MemWatcher.DumpEvent"; | |
25 static base::AtExitManager* g_memory_watcher_exit_manager = NULL; | |
26 static MemoryWatcher* g_memory_watcher = NULL; | |
27 static MemoryWatcherDumpKey* g_hotkey_handler = NULL; | |
28 static HANDLE g_dump_event = INVALID_HANDLE_VALUE; | |
29 static HANDLE g_quit_event = INVALID_HANDLE_VALUE; | |
30 static HANDLE g_watcher_thread = INVALID_HANDLE_VALUE; | |
31 | |
32 // A HotKey to dump the memory statistics. | |
33 class MemoryWatcherDumpKey : public HotKeyHandler { | |
34 public: | |
35 MemoryWatcherDumpKey(UINT modifiers, UINT vkey) | |
36 : HotKeyHandler(modifiers, vkey) {} | |
37 | |
38 virtual void OnHotKey(UINT, WPARAM, LPARAM) { | |
39 SetEvent(g_dump_event); | |
40 } | |
41 }; | |
42 | |
43 // Creates the global memory watcher. | |
44 void CreateMemoryWatcher() { | |
45 g_memory_watcher_exit_manager = new base::AtExitManager(); | |
46 g_memory_watcher = new MemoryWatcher(); | |
47 // Register ALT-CONTROL-D to Dump Memory stats. | |
48 g_hotkey_handler = new MemoryWatcherDumpKey(MOD_ALT|MOD_CONTROL, 0x44); | |
49 } | |
50 | |
51 // Deletes the global memory watcher. | |
52 void DeleteMemoryWatcher() { | |
53 if (g_hotkey_handler) | |
54 delete g_hotkey_handler; | |
55 g_hotkey_handler = NULL; | |
56 if (g_memory_watcher) | |
57 delete g_memory_watcher; | |
58 g_memory_watcher = NULL; | |
59 | |
60 // Intentionly leak g_memory_watcher_exit_manager. | |
61 } | |
62 | |
63 // Thread for watching for key events. | |
64 DWORD WINAPI ThreadMain(LPVOID) { | |
65 bool stopping = false; | |
66 HANDLE events[2] = { g_dump_event, g_quit_event }; | |
67 while (!stopping) { | |
68 DWORD rv = WaitForMultipleObjects(2, events, FALSE, INFINITE); | |
69 switch (rv) { | |
70 case WAIT_OBJECT_0: | |
71 if (g_memory_watcher) { | |
72 g_memory_watcher->DumpLeaks(); | |
73 } | |
74 stopping = true; | |
75 break; | |
76 case WAIT_OBJECT_0 + 1: | |
77 stopping = true; | |
78 break; | |
79 default: | |
80 NOTREACHED(); | |
81 break; | |
82 } | |
83 } | |
84 return 0; | |
85 } | |
86 | |
87 // Creates the background thread | |
88 void CreateBackgroundThread() { | |
89 // Create a named event which can be used to notify | |
90 // all watched processes. | |
91 g_dump_event = CreateEvent(0, TRUE, FALSE, kDumpEvent); | |
92 DCHECK(g_dump_event != NULL); | |
93 | |
94 // Create a local event which can be used to kill our | |
95 // background thread. | |
96 g_quit_event = CreateEvent(0, TRUE, FALSE, NULL); | |
97 DCHECK(g_quit_event != NULL); | |
98 | |
99 // Create the background thread. | |
100 g_watcher_thread = CreateThread(0, | |
101 0, | |
102 ThreadMain, | |
103 0, | |
104 0, | |
105 0); | |
106 DCHECK(g_watcher_thread != NULL); | |
107 } | |
108 | |
109 // Tell the background thread to stop. | |
110 void StopBackgroundThread() { | |
111 // Send notification to our background thread. | |
112 SetEvent(g_quit_event); | |
113 | |
114 // Wait for our background thread to die. | |
115 DWORD rv = WaitForSingleObject(g_watcher_thread, INFINITE); | |
116 DCHECK(rv == WAIT_OBJECT_0); | |
117 | |
118 // Cleanup our global handles. | |
119 CloseHandle(g_quit_event); | |
120 CloseHandle(g_dump_event); | |
121 CloseHandle(g_watcher_thread); | |
122 } | |
123 | |
124 bool IsChromeExe() { | |
125 return GetModuleHandleA("chrome.exe") != NULL; | |
126 } | |
127 | |
128 extern "C" { | |
129 // DllMain is the windows entry point to this DLL. | |
130 // We use the entry point as the mechanism for starting and stopping | |
131 // the MemoryWatcher. | |
132 BOOL WINAPI DllMain(HINSTANCE dll_instance, DWORD reason, | |
133 LPVOID reserved) { | |
134 if (!IsChromeExe()) | |
135 return FALSE; | |
136 | |
137 switch (reason) { | |
138 case DLL_PROCESS_ATTACH: | |
139 CreateMemoryWatcher(); | |
140 CreateBackgroundThread(); | |
141 break; | |
142 case DLL_PROCESS_DETACH: | |
143 DeleteMemoryWatcher(); | |
144 StopBackgroundThread(); | |
145 break; | |
146 } | |
147 return TRUE; | |
148 } | |
149 | |
150 __declspec(dllexport) void __cdecl SetLogName(char* name) { | |
151 g_memory_watcher->SetLogName(name); | |
152 } | |
153 | |
154 } // extern "C" | |
OLD | NEW |