1 : // Copyright 2015 Google Inc. All Rights Reserved.
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 : // A minimal test harness that invokes all of the functions that are observed
16 : // by the memory profiler. The harness also uses threading so that the traces
17 : // produced by profiling this harness put the grinder through its paces.
18 : //
19 : // The output of the grinder should look like the following (with a minimal set
20 : // of dependencies drawn as arrows):
21 : //
22 : // WorkerThread1 WorkerThread2
23 : // ------------- -------------
24 : // 1: create heap 0 create heap 3
25 : // 2: create alloc 0 on heap 0 create alloc 3 on heap 3
26 : // 3: create heap 1 --------------------> create alloc 4 on heap 1
27 : // 4: create alloc 1 on heap 1 ---------> get size of alloc 1 on heap 1
28 : // 5: create alloc 2 on heap 1 realloc alloc 1 on heap 1
29 : // 6: free alloc 2 on heap 1 free alloc 1 on heap 1
30 : // 7: set info on heap 2 free alloc 4 on heap 1
31 : // 8: free alloc 0 on heap 0 destroy heap 1
32 : // 9: destroy heap 0 free alloc 3 on heap 3
33 : // 10: destroy heap 3
34 :
35 : #include "windows.h"
36 :
37 m : namespace {
38 :
39 : // Mutex synchronizing access to shared_heap and shared_alloc.
40 m : HANDLE shared_mutex = nullptr;
41 :
42 : // Heap that has shared use across two threads.
43 m : HANDLE shared_heap = nullptr;
44 :
45 : // Allocation that has shared use across two threads. Allocated from
46 : // shared_heap.
47 m : void* shared_alloc = nullptr;
48 :
49 : // Helper function for acquiring |shared_mutex| on the current thread.
50 m : void AcquireMutex() {
51 m : while (::WaitForSingleObject(shared_mutex, INFINITE) != WAIT_OBJECT_0) {}
52 m : }
53 :
54 : // Body of the first worker thread. This thread is responsible for creating the
55 : // shared heap and allocation.
56 m : DWORD WINAPI WorkerThread1Main(LPVOID param) {
57 : // Allocate a heap and a buffer on this thread.
58 m : HANDLE heap = ::HeapCreate(0, 0, 0); // 1
59 m : void* alloc1 = ::HeapAlloc(heap, HEAP_ZERO_MEMORY, 42); // 2
60 :
61 m : AcquireMutex();
62 :
63 m : shared_heap = ::HeapCreate(0, 0, 0); // 3
64 m : shared_alloc = ::HeapAlloc(shared_heap, 0, 1 << 20); // 4
65 :
66 m : void* alloc2 = ::HeapAlloc(shared_heap, 0, 16); // 5
67 m : ::HeapFree(shared_heap, 0, alloc2); // 6
68 :
69 m : ::ReleaseMutex(shared_mutex);
70 :
71 : // Tinker with the process heap a bit.
72 m : HANDLE process_heap = ::GetProcessHeap();
73 m : ::HeapSetInformation(process_heap, HeapEnableTerminationOnCorruption, // 7
74 m : 0, 0);
75 :
76 : // Free the allocation and heap made on this thread.
77 m : ::HeapFree(heap, 0, alloc1); // 8
78 m : alloc1 = nullptr;
79 m : ::HeapDestroy(heap); // 9
80 m : heap = nullptr;
81 :
82 : // Wait for the shared_heap to be cleaned up. This ensures that the two
83 : // threads do run simultaneously and get distinct thread IDs.
84 m : while (true) {
85 m : AcquireMutex();
86 m : if (shared_heap == nullptr)
87 m : break;
88 m : ::ReleaseMutex(shared_mutex);
89 m : }
90 m : ::ReleaseMutex(shared_mutex);
91 :
92 m : return 0;
93 m : }
94 :
95 : // Body of the second worker thread. This thread is responsible for releasing
96 : // the shared heap and allocation.
97 m : DWORD WINAPI WorkerThread2Main(LPVOID param) {
98 : // Allocate a heap and a buffer on this thread.
99 m : HANDLE heap = ::HeapCreate(0, 0, 0); // 1
100 m : void* alloc1 = ::HeapAlloc(heap, HEAP_ZERO_MEMORY, 1024); // 2
101 :
102 : // Wait until the shared heap is initialized.
103 m : while (true) {
104 m : AcquireMutex();
105 m : if (shared_heap != nullptr)
106 m : break;
107 m : ::ReleaseMutex(shared_mutex);
108 m : }
109 :
110 : // Create an allocation on this thread that is only used on this thread,
111 : // but which references the shared heap.
112 m : HANDLE alloc2 = ::HeapAlloc(shared_heap, 0, 347); // 3
113 :
114 : // Query and then free the shared allocation.
115 m : ::HeapSize(shared_heap, 0, shared_alloc); // 4
116 m : shared_alloc = ::HeapReAlloc(shared_heap, 0, shared_alloc, 500); // 5
117 m : ::HeapFree(shared_heap, 0, shared_alloc); // 6
118 m : shared_alloc = nullptr;
119 :
120 : // Free the shared_heap allocation made on this thread.
121 m : ::HeapFree(shared_heap, 0, alloc2); // 7
122 :
123 : // Free the shared heap.
124 m : ::HeapDestroy(shared_heap); // 8
125 m : shared_heap = nullptr;
126 :
127 m : ::ReleaseMutex(shared_mutex);
128 :
129 m : ::HeapFree(heap, 0, alloc1); // 9
130 m : alloc1 = nullptr;
131 m : ::HeapDestroy(heap); // 10
132 m : heap = nullptr;
133 :
134 m : return 0;
135 m : }
136 :
137 m : } // namespace
138 :
139 m : int main(int argc, const char* const* argv) {
140 : // The controlled tests (with known expectations) are run on independent
141 : // threads. This keeps them separated from the CRT code that runs on the main
142 : // thread and which we don't directly control.
143 :
144 : // Create a mutex not owned by anyone.
145 m : shared_mutex = ::CreateMutex(NULL, FALSE, NULL);
146 :
147 : // Run the two threads simultaneously and wait for them both to finish.
148 m : DWORD worker_thread_1_id = 0;
149 m : HANDLE worker_thread_1 = ::CreateThread(nullptr, 0, WorkerThread1Main,
150 m : nullptr, 0, &worker_thread_1_id);
151 m : DWORD worker_thread_2_id = 0;
152 m : HANDLE worker_thread_2 = ::CreateThread(nullptr, 0, WorkerThread2Main,
153 m : nullptr, 0, &worker_thread_2_id);
154 m : ::WaitForSingleObject(worker_thread_1, INFINITE);
155 m : ::WaitForSingleObject(worker_thread_2, INFINITE);
156 :
157 : // Destroy the mutex.
158 m : ::CloseHandle(shared_mutex);
159 :
160 m : return 0;
161 m : }
|