6bd91535d506d6b20dac593d80da371a52e9803a
[platform/framework/web/crosswalk.git] / src / tools / memory_watcher / dllmain.cc
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 LRESULT OnHotKey(UINT, WPARAM, LPARAM, BOOL& bHandled) {
39     SetEvent(g_dump_event);
40     return 1;
41   }
42 };
43
44 // Creates the global memory watcher.
45 void CreateMemoryWatcher() {
46   g_memory_watcher_exit_manager = new base::AtExitManager();
47   g_memory_watcher = new MemoryWatcher();
48   // Register ALT-CONTROL-D to Dump Memory stats.
49   g_hotkey_handler = new MemoryWatcherDumpKey(MOD_ALT|MOD_CONTROL, 0x44);
50 }
51
52 // Deletes the global memory watcher.
53 void DeleteMemoryWatcher() {
54   if (g_hotkey_handler)
55     delete g_hotkey_handler;
56   g_hotkey_handler = NULL;
57   if (g_memory_watcher)
58     delete g_memory_watcher;
59   g_memory_watcher = NULL;
60
61   // Intentionly leak g_memory_watcher_exit_manager.
62 }
63
64 // Thread for watching for key events.
65 DWORD WINAPI ThreadMain(LPVOID) {
66   bool stopping = false;
67   HANDLE events[2] =  { g_dump_event, g_quit_event };
68   while (!stopping) {
69     DWORD rv = WaitForMultipleObjects(2, events, FALSE, INFINITE);
70     switch (rv) {
71       case WAIT_OBJECT_0:
72         if (g_memory_watcher) {
73           g_memory_watcher->DumpLeaks();
74         }
75         stopping = true;
76         break;
77       case WAIT_OBJECT_0 + 1:
78         stopping = true;
79         break;
80       default:
81         NOTREACHED();
82         break;
83     }
84   }
85   return 0;
86 }
87
88 // Creates the background thread
89 void CreateBackgroundThread() {
90   // Create a named event which can be used to notify
91   // all watched processes.
92   g_dump_event = CreateEvent(0, TRUE, FALSE, kDumpEvent);
93   DCHECK(g_dump_event != NULL);
94
95   // Create a local event which can be used to kill our
96   // background thread.
97   g_quit_event = CreateEvent(0, TRUE, FALSE, NULL);
98   DCHECK(g_quit_event != NULL);
99
100   // Create the background thread.
101   g_watcher_thread = CreateThread(0,
102                                 0,
103                                 ThreadMain,
104                                 0,
105                                 0,
106                                 0);
107   DCHECK(g_watcher_thread != NULL);
108 }
109
110 // Tell the background thread to stop.
111 void StopBackgroundThread() {
112   // Send notification to our background thread.
113   SetEvent(g_quit_event);
114
115   // Wait for our background thread to die.
116   DWORD rv = WaitForSingleObject(g_watcher_thread, INFINITE);
117   DCHECK(rv == WAIT_OBJECT_0);
118
119   // Cleanup our global handles.
120   CloseHandle(g_quit_event);
121   CloseHandle(g_dump_event);
122   CloseHandle(g_watcher_thread);
123 }
124
125 bool IsChromeExe() {
126   return GetModuleHandleA("chrome.exe") != NULL;
127 }
128
129 extern "C" {
130 // DllMain is the windows entry point to this DLL.
131 // We use the entry point as the mechanism for starting and stopping
132 // the MemoryWatcher.
133 BOOL WINAPI DllMain(HINSTANCE dll_instance, DWORD reason,
134                               LPVOID reserved) {
135   if (!IsChromeExe())
136     return FALSE;
137
138   switch (reason) {
139     case DLL_PROCESS_ATTACH:
140       CreateMemoryWatcher();
141       CreateBackgroundThread();
142       break;
143     case DLL_PROCESS_DETACH:
144       DeleteMemoryWatcher();
145       StopBackgroundThread();
146       break;
147   }
148   return TRUE;
149 }
150
151 __declspec(dllexport) void __cdecl SetLogName(char* name) {
152   g_memory_watcher->SetLogName(name);
153 }
154
155 }  // extern "C"