OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 #include "base/debug/gdi_debug_util_win.h" | |
5 | |
6 #include <cmath> | |
7 | |
8 #include <psapi.h> | |
9 #include <TlHelp32.h> | |
10 | |
11 #include "base/debug/alias.h" | |
12 #include "base/logging.h" | |
13 #include "base/win/scoped_handle.h" | |
14 | |
15 namespace { | |
16 | |
17 void CollectChildGDIUsageAndDie(DWORD parent_pid) { | |
18 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); | |
19 CHECK_NE(INVALID_HANDLE_VALUE, snapshot); | |
20 | |
21 int child_count = 0; | |
22 base::debug::Alias(&child_count); | |
23 int peak_gdi_count = 0; | |
24 base::debug::Alias(&peak_gdi_count); | |
25 int sum_gdi_count = 0; | |
26 base::debug::Alias(&sum_gdi_count); | |
27 int sum_user_count = 0; | |
28 base::debug::Alias(&sum_user_count); | |
29 | |
30 PROCESSENTRY32 proc_entry = {0}; | |
31 proc_entry.dwSize = sizeof(PROCESSENTRY32); | |
32 CHECK(Process32First(snapshot, &proc_entry)); | |
33 | |
34 do { | |
35 if (parent_pid != proc_entry.th32ParentProcessID) | |
36 continue; | |
37 // Got a child process. Compute GDI usage. | |
38 base::win::ScopedHandle process( | |
39 OpenProcess(PROCESS_QUERY_INFORMATION, | |
40 FALSE, | |
41 proc_entry.th32ParentProcessID)); | |
42 if (!process.IsValid()) | |
43 continue; | |
44 | |
45 int num_gdi_handles = GetGuiResources(process.Get(), GR_GDIOBJECTS); | |
46 int num_user_handles = GetGuiResources(process.Get(), GR_USEROBJECTS); | |
47 | |
48 // Compute sum and peak counts. | |
49 ++child_count; | |
50 sum_user_count += num_user_handles; | |
51 sum_gdi_count += num_gdi_handles; | |
52 if (peak_gdi_count < num_gdi_handles) | |
53 peak_gdi_count = num_gdi_handles; | |
54 | |
55 } while (Process32Next(snapshot, &proc_entry)); | |
56 | |
57 CloseHandle(snapshot); | |
58 CHECK(false); | |
59 } | |
60 | |
61 } // namespace | |
62 | |
63 namespace base { | |
64 namespace debug { | |
65 | |
66 void GDIBitmapAllocFailure(BITMAPINFOHEADER* header, HANDLE shared_section) { | |
67 // Make sure parameters are saved in the minidump. | |
68 DWORD last_error = GetLastError(); | |
69 | |
70 LONG width = header->biWidth; | |
71 LONG heigth = header->biHeight; | |
72 | |
73 base::debug::Alias(&last_error); | |
74 base::debug::Alias(&width); | |
75 base::debug::Alias(&heigth); | |
76 base::debug::Alias(&shared_section); | |
77 | |
78 int num_user_handles = GetGuiResources(GetCurrentProcess(), | |
79 GR_USEROBJECTS); | |
80 | |
81 int num_gdi_handles = GetGuiResources(GetCurrentProcess(), | |
82 GR_GDIOBJECTS); | |
83 if (num_gdi_handles == 0) { | |
84 DWORD get_gui_resources_error = GetLastError(); | |
85 base::debug::Alias(&get_gui_resources_error); | |
86 CHECK(false); | |
87 } | |
88 | |
89 base::debug::Alias(&num_gdi_handles); | |
90 base::debug::Alias(&num_user_handles); | |
91 | |
92 const DWORD kLotsOfHandles = 9990; | |
93 CHECK_LE(num_gdi_handles, kLotsOfHandles); | |
94 | |
95 PROCESS_MEMORY_COUNTERS_EX pmc; | |
96 pmc.cb = sizeof(pmc); | |
97 CHECK(GetProcessMemoryInfo(GetCurrentProcess(), | |
98 reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc), | |
99 sizeof(pmc))); | |
100 const size_t kLotsOfMemory = 1500 * 1024 * 1024; // 1.5GB | |
101 CHECK_LE(pmc.PagefileUsage, kLotsOfMemory); | |
102 CHECK_LE(pmc.PrivateUsage, kLotsOfMemory); | |
103 | |
104 void* small_data = NULL; | |
105 base::debug::Alias(&small_data); | |
106 | |
107 if (std::abs(heigth) * width > 100) { | |
108 // Huh, that's weird. We don't have crazy handle count, we don't have | |
109 // ridiculous memory usage. Try to allocate a small bitmap and see if that | |
110 // fails too. | |
111 header->biWidth = 5; | |
112 header->biHeight = -5; | |
113 HBITMAP small_bitmap = CreateDIBSection( | |
114 NULL, reinterpret_cast<BITMAPINFO*>(&header), | |
115 0, &small_data, shared_section, 0); | |
116 CHECK(small_bitmap != NULL); | |
117 DeleteObject(small_bitmap); | |
118 } | |
119 // Maybe the child processes are the ones leaking GDI or USER resouces. | |
120 CollectChildGDIUsageAndDie(GetCurrentProcessId()); | |
121 } | |
122 | |
123 } // namespace debug | |
124 } // namespace base | |
OLD | NEW |