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

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: Updates following VM testing 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
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 <errno.h>
18 #include <fcntl.h>
19 #include <stdint.h>
20
21 #include <algorithm>
22
23 #include "base/logging.h"
24 #include "gtest/gtest.h"
25 #include "util/file/fd_io.h"
26 #include "util/misc/clock.h"
27 #include "util/posix/scoped_fcntl_flags.h"
28 #include "util/test/errors.h"
29 #include "util/test/mac/mach_multiprocess.h"
30
31 namespace crashpad {
32 namespace test {
33 namespace {
34
35 // Reads a byte from |fd|. Returns |true| if a byte could be read, and |false|
36 // otherwise. If |fd| is a file descriptor set to O_NONBLOCK mode, this will
37 // return |false| immediately if no more data is available to be read.
38 // Otherwise, this will only return false when |fd| is at end-of-file.
39 // Terminates execution if an error condition is detected.
40 bool ReadByte(int fd) {
41 char c;
42 ssize_t rv = ReadFD(fd, &c, sizeof(c));
43 if (rv < 0 && errno == EAGAIN) {
44 rv = 0;
45 }
46 PCHECK(rv >= 0) << "read";
47 CHECK(rv <= static_cast<ssize_t>(sizeof(c))) << "read";
48
49 return rv > 0;
50 }
51
52 // Reads all data from |fd| until there is no more data to be read. If |fd| is
53 // a file descriptor set to O_NONBLOCK mode, this will return as soon as no more
54 // data is available to be read. Otherwise, this will not return until |fd| is
55 // at end-of-file.
56 void DrainPipe(int fd) {
57 while (ReadByte(fd)) {
58 }
59 }
60
61 class ScopedTaskSuspendTest final : public MachMultiprocess {
62 public:
63 ScopedTaskSuspendTest() : MachMultiprocess() {}
64 ~ScopedTaskSuspendTest() {}
65
66 private:
67 // MachMultiprocess:
68
69 virtual void MachMultiprocessParent() override {
70 int read_fd = ReadPipeFD();
71
72 // Make sure that the child is running. This is a blocking read, because the
73 // parent should wait for the child to start sending data.
74 char c;
75 CheckedReadFD(read_fd, &c, sizeof(c));
76
77 {
78 // Suspend the child process.
79 ScopedTaskSuspend suspend(ChildTask());
80
81 // Make the read pipe non-blocking so that it can be drained and tested
82 // for EOF.
83 ScopedFcntlFlags fcntl_flags(read_fd, O_NONBLOCK, 0);
84
85 DrainPipe(read_fd);
86
87 // This extra sleep and drain shouldn’t be necessary, but there seem to
88 // be scheduling bugs or delays in data appearing on the pipe.
89 SleepNanoseconds(1E5); // 100 microseconds
90 DrainPipe(read_fd);
91
92 EXPECT_FALSE(ReadByte(read_fd));
93
94 // Sleep for a little while, giving the child process a chance to measure
95 // that one of its loop iterations took a long time.
96 SleepNanoseconds(1E7); // 10 milliseconds
97
98 // Make sure that the child hasn’t sent anything else while it was
99 // supposed to be suspended.
100 EXPECT_FALSE(ReadByte(read_fd));
101 }
102
103 // Make sure that the child has resumed. This is a blocking read, because
104 // the parent should wait for the child to resume sending data.
105 CheckedReadFD(read_fd, &c, sizeof(c));
106
107 // Tell the child that it’s permitted to leave its loop.
108 CheckedWriteFD(WritePipeFD(), &c, sizeof(c));
109
110 // This is a blocking drain, which waits for read_fd to reach EOF.
111 DrainPipe(read_fd);
112 CheckedReadFDAtEOF(read_fd);
113 }
114
115 virtual void MachMultiprocessChild() override {
116 int read_fd = ReadPipeFD();
117 int write_fd = WritePipeFD();
118
119 // Make the read pipe non-blocking so that it can be monitored to read the
120 // byte that will cause the loop to terminate.
121 ScopedFcntlFlags fcntl_flags(read_fd, O_NONBLOCK, 0);
122
123 // Loop for a while, computing the longest duration for an iteration of the
124 // loop. Inside each loop, send a byte to the parent process via the pipe,
125 // so that the parent will be able to tell when the child is running and
126 // when it is suspended.
127 uint64_t now = ClockMonotonicNanoseconds();
128 uint64_t last = now;
129 uint64_t max_delay = 0;
130 do {
131 char c = '\0';
132 CheckedWriteFD(write_fd, &c, sizeof(c));
133
134 uint64_t delay = now - last;
135 max_delay = std::max(max_delay, delay);
136 last = now;
137 now = ClockMonotonicNanoseconds();
138 } while (!ReadByte(read_fd));
139
140 // The longest iteration of the loop should be at least as long as the time
141 // that the parent process had this process suspended, but because of the
142 // tricky nature of scheduling, just make sure that the longest iteration
143 // took a perceptible amount of time.
144 EXPECT_GE(max_delay, 1E4); // 10 microseconds
145 }
146
147 DISALLOW_COPY_AND_ASSIGN(ScopedTaskSuspendTest);
148 };
149
150 TEST(ScopedTaskSuspend, ScopedTaskSuspend) {
151 ScopedTaskSuspendTest scoped_task_suspend_test;
152 scoped_task_suspend_test.Run();
153 }
154
155 } // namespace
156 } // namespace test
157 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698