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 : // 0: create heap 0 create heap 3
25 : // 1: create alloc 0 on heap 0 create alloc 3 on heap 3
26 : // 2: create heap 1 --------------------> create alloc 4 on heap 1
27 : // 3: create alloc 1 on heap 1 ---------> get size of alloc 1 on heap 1
28 : // 4: create alloc 2 on heap 1 realloc alloc 1 on heap 1
29 : // 5: free alloc 2 on heap 1 -----+ free alloc 1 on heap 1
30 : // 6: set info on heap 2 | free alloc 4 on heap 1
31 : // 7: free alloc 0 on heap 0 +-----> destroy heap 1
32 : // 8: destroy heap 0 free alloc 3 on heap 3
33 : // 9: destroy heap 3
34 : //
35 : // The mutexes ensure that the sequence of events happens as follows:
36 : //
37 : // Phase 0: Thread1: 0, 1, 2, 3, 4
38 : // Phase 1: Thread2: 0, 1, 2, 3, 4, 5, 6
39 : // Phase 2: Thread1: 5, 6, 7, 8
40 : // Phase 3: Thread2: 7, 8, 9
41 :
42 : #include <assert.h>
43 : #include <windows.h>
44 :
45 m : namespace {
46 :
47 : // Mutex synchronizing access to shared_heap and shared_alloc.
48 m : HANDLE shared_mutex = nullptr;
49 :
50 : // The current 'phase'. This is used to coordinate the sequence of events
51 : // across the two threads. This is necessary to ensure the dependencies are
52 : // exactly as wanted, without unintentional dependencies caused by allocation
53 : // reuse in a heap. Modified under |shared_mutex|.
54 m : size_t phase = 0;
55 :
56 : // Heap that has shared use across two threads. Modified under |shared_mutex|.
57 m : HANDLE shared_heap = nullptr;
58 :
59 : // Allocation that has shared use across two threads. Allocated from
60 : // shared_heap. Modified under |shared_mutex|.
61 m : void* shared_alloc = nullptr;
62 :
63 : // Helper function for acquiring |shared_mutex| on the current thread and in
64 : // the desired phase.
65 m : void AcquireMutex(size_t desired_phase) {
66 m : while (true) {
67 m : while (::WaitForSingleObject(shared_mutex, INFINITE) != WAIT_OBJECT_0) {}
68 m : if (desired_phase == phase)
69 m : return;
70 m : ::ReleaseMutex(shared_mutex);
71 m : ::Sleep(10);
72 m : }
73 m : }
74 :
75 : // Releases the mutex and increments the phase.
76 m : void ReleaseMutex() {
77 m : ++phase;
78 m : ::ReleaseMutex(shared_mutex);
79 m : }
80 :
81 : // Body of the first worker thread. This thread is responsible for creating the
82 : // shared heap and allocation.
83 m : DWORD WINAPI WorkerThread1Main(LPVOID param) {
84 m : AcquireMutex(0);
85 m : assert(shared_heap == nullptr);
86 m : assert(shared_alloc == nullptr);
87 :
88 : // Allocate a heap and a buffer on this thread.
89 m : HANDLE heap = ::HeapCreate(0, 0, 0); // 0
90 m : void* alloc1 = ::HeapAlloc(heap, HEAP_ZERO_MEMORY, 42); // 1
91 :
92 m : shared_heap = ::HeapCreate(0, 0, 0); // 2
93 m : shared_alloc = ::HeapAlloc(shared_heap, 0, 1 << 20); // 3
94 :
95 m : void* alloc2 = ::HeapAlloc(shared_heap, 0, 16); // 4
96 :
97 m : ReleaseMutex();
98 m : AcquireMutex(2);
99 :
100 m : ::HeapFree(shared_heap, 0, alloc2); // 5
101 :
102 : // Tinker with the process heap a bit.
103 m : HANDLE process_heap = ::GetProcessHeap();
104 m : ::HeapSetInformation(process_heap, HeapEnableTerminationOnCorruption, // 6
105 m : 0, 0);
106 :
107 : // Free the allocation and heap made on this thread.
108 m : ::HeapFree(heap, 0, alloc1); // 7
109 m : alloc1 = nullptr;
110 m : ::HeapDestroy(heap); // 8
111 m : heap = nullptr;
112 :
113 m : ReleaseMutex();
114 :
115 m : return 0;
116 m : }
117 :
118 : // Body of the second worker thread. This thread is responsible for releasing
119 : // the shared heap and allocation.
120 m : DWORD WINAPI WorkerThread2Main(LPVOID param) {
121 m : AcquireMutex(1);
122 m : assert(shared_heap != nullptr);
123 m : assert(shared_alloc != nullptr);
124 :
125 : // Allocate a heap and a buffer on this thread.
126 m : HANDLE heap = ::HeapCreate(0, 0, 0); // 0
127 m : void* alloc1 = ::HeapAlloc(heap, HEAP_ZERO_MEMORY, 1024); // 1
128 :
129 : // Create an allocation on this thread that is only used on this thread,
130 : // but which references the shared heap.
131 m : HANDLE alloc2 = ::HeapAlloc(shared_heap, 0, 347); // 2
132 :
133 : // Query and then free the shared allocation.
134 m : ::HeapSize(shared_heap, 0, shared_alloc); // 3
135 m : shared_alloc = ::HeapReAlloc(shared_heap, 0, shared_alloc, 500); // 4
136 m : ::HeapFree(shared_heap, 0, shared_alloc); // 5
137 m : shared_alloc = nullptr;
138 :
139 : // Free the shared_heap allocation made on this thread.
140 m : ::HeapFree(shared_heap, 0, alloc2); // 6
141 :
142 m : ReleaseMutex();
143 m : AcquireMutex(3);
144 :
145 : // Free the shared heap.
146 m : ::HeapDestroy(shared_heap); // 7
147 m : shared_heap = nullptr;
148 :
149 m : ::HeapFree(heap, 0, alloc1); // 8
150 m : alloc1 = nullptr;
151 m : ::HeapDestroy(heap); // 9
152 m : heap = nullptr;
153 :
154 m : ::ReleaseMutex(shared_mutex);
155 :
156 m : return 0;
157 m : }
158 :
159 m : } // namespace
160 :
161 m : int main(int argc, const char* const* argv) {
162 : // The controlled tests (with known expectations) are run on independent
163 : // threads. This keeps them separated from the CRT code that runs on the main
164 : // thread and which we don't directly control.
165 :
166 : // Create a mutex not owned by anyone.
167 m : shared_mutex = ::CreateMutex(NULL, FALSE, NULL);
168 :
169 : // Run the two threads simultaneously and wait for them both to finish.
170 m : DWORD worker_thread_1_id = 0;
171 m : HANDLE worker_thread_1 = ::CreateThread(nullptr, 0, WorkerThread1Main,
172 m : nullptr, 0, &worker_thread_1_id);
173 m : DWORD worker_thread_2_id = 0;
174 m : HANDLE worker_thread_2 = ::CreateThread(nullptr, 0, WorkerThread2Main,
175 m : nullptr, 0, &worker_thread_2_id);
176 m : ::WaitForSingleObject(worker_thread_1, INFINITE);
177 m : ::WaitForSingleObject(worker_thread_2, INFINITE);
178 :
179 : // Destroy the mutex.
180 m : ::CloseHandle(shared_mutex);
181 :
182 m : return 0;
183 m : }
|