Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: util/mach/scoped_task_suspend_test.cc

Issue 649693002: Add ScopedTaskSuspend and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « util/mach/scoped_task_suspend.cc ('k') | util/util.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. 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 #include "util/mach/scoped_task_suspend.h"
16
17 #include <mach/mach.h>
18 #include <stdint.h>
19
20 #include <algorithm>
21
22 #include "gtest/gtest.h"
23 #include "util/file/fd_io.h"
24 #include "util/mach/task_memory.h"
25 #include "util/misc/clock.h"
26 #include "util/test/mac/mach_multiprocess.h"
27
28 namespace crashpad {
29 namespace test {
30 namespace {
31
32 class ScopedTaskSuspendTest final : public MachMultiprocess {
33 public:
34 ScopedTaskSuspendTest() : MachMultiprocess() {}
35 ~ScopedTaskSuspendTest() {}
36
37 private:
38 // Reads the int at |address| from the child process’ memory at |task_memory|.
39 static int CounterValue(TaskMemory* task_memory, mach_vm_address_t address) {
Robert Sesek 2014/10/13 15:01:37 Does this test really need to use TaskMemory? Coul
40 int counter = 0;
41 EXPECT_TRUE(task_memory->Read(address, sizeof(counter), &counter));
42 return counter;
43 }
44
45 // Determines whether the child process is updating its counter. The counter
46 // is expected to be updated while the child process is running, but should
47 // appear frozen while the child process is suspended.
48 static bool CounterIsRunning(
49 TaskMemory* task_memory, mach_vm_address_t address) {
50 int initial_counter = CounterValue(task_memory, address);
51
52 // Look for any change in the counter. If there is any change, the counter
53 // is running. If there is no change, it doesn’t necessarily mean that the
54 // child process is suspended, because it may not have been scheduled for
55 // another reason. Retry a few times in a loop with a delay.
56 for (size_t tries = 10; tries > 0; --tries) {
57 SleepNanoseconds(1E5); // 100 microseconds
58
59 int counter = CounterValue(task_memory, address);
60 if (counter != initial_counter) {
61 return true;
62 }
63 }
64
65 return false;
66 }
67
68 // MachMultiprocess:
69
70 virtual void MachMultiprocessParent() override {
71 int read_fd = ReadPipeFD();
72
73 // Get the address of the counter in the child process.
74 mach_vm_address_t address;
75 CheckedReadFD(read_fd, &address, sizeof(address));
76
77 task_t child_task = ChildTask();
78 TaskMemory task_memory(child_task);
79
80 // In the initial state, the child process should be scheduled, and it
81 // should be updating its counter.
82 EXPECT_TRUE(CounterIsRunning(&task_memory, address));
83
84 {
85 // Suspend the child process.
86 ScopedTaskSuspend suspend(child_task);
87
88 // CounterIsRunning() just makes sure that the child process is not
89 // running within a short duration. Checking the counter value before and
90 // after the sleep ensures that the child process has not run during a
91 // larger period that it was expected to be suspended.
92 int initial_value = CounterValue(&task_memory, address);
93
94 EXPECT_FALSE(CounterIsRunning(&task_memory, address));
95
96 // Sleep for a little while, giving the child process a chance to measure
97 // that one of its loop iterations took a long time.
98 SleepNanoseconds(1E6); // 1 millisecond
99
100 EXPECT_FALSE(CounterIsRunning(&task_memory, address));
101
102 // Make sure that the child process hasn’t had a chance to run at all.
103 int final_value = CounterValue(&task_memory, address);
104 EXPECT_EQ(initial_value, final_value);
105 }
106
107 // The suspension should no longer be placed, and the child process should
108 // be running again. This makes sure that when the counter was seen as
109 // stopped before, it’s because the child process was really suspended, and
110 // not because it had exited its loop.
111 EXPECT_TRUE(CounterIsRunning(&task_memory, address));
112
113 // Get the child’s idea of its final counter value, and compare that against
114 // this process’ idea of the same value. This tests that CounterValue() was
115 // in fact reading the right value from the child process.
116 int expect_counter;
117 CheckedReadFD(read_fd, &expect_counter, sizeof(expect_counter));
118
119 int counter = CounterValue(&task_memory, address);
120 EXPECT_EQ(expect_counter, counter);
121 }
122
123 virtual void MachMultiprocessChild() override {
124 int write_fd = WritePipeFD();
125
126 // Tell the parent process where to find the counter in this process’
127 // address space.
128 volatile int counter = 0;
129 mach_vm_address_t address = reinterpret_cast<mach_vm_address_t>(&counter);
130 CheckedWriteFD(write_fd, &address, sizeof(address));
131
132 // Loop for a while, computing the longest duration for an iteration of the
133 // loop. Inside each loop, update the counter, which the parent process can
134 // examine to see whether the loop is running from its perspective.
135 uint64_t start = ClockMonotonicNanoseconds();
136 uint64_t deadline = start + 1E8; // 100 milliseconds
137 uint64_t now = start;
138 uint64_t last = now;
139 uint64_t max_delay = 0;
140 do {
141 ++counter;
142 uint64_t delay = now - last;
143 max_delay = std::max(max_delay, delay);
144 last = now;
145 } while ((now = ClockMonotonicNanoseconds()) < deadline);
146
147 // The longest iteration of the loop should be at least as long as the time
148 // that the parent process had this process suspended, but because of the
149 // tricky nature of scheduling, just make sure that the longest iteration
150 // took a perceptible amount of time.
151 EXPECT_GE(max_delay, 1E5); // 100 microseconds
152
153 // Tell the parent process where the counter ended up.
154 CheckedWriteFD(write_fd, const_cast<int*>(&counter), sizeof(counter));
155
156 // Wait for the parent process to finish reading this process’ memory.
157 CheckedReadFDAtEOF(ReadPipeFD());
158 }
159
160 DISALLOW_COPY_AND_ASSIGN(ScopedTaskSuspendTest);
161 };
162
163 TEST(ScopedTaskSuspend, ScopedTaskSuspend) {
164 ScopedTaskSuspendTest scoped_task_suspend_test;
165 scoped_task_suspend_test.Run();
166 }
167
168 } // namespace
169 } // namespace test
170 } // namespace crashpad
OLDNEW
« no previous file with comments | « util/mach/scoped_task_suspend.cc ('k') | util/util.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698