1 // Copyright 2013 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 
5 // NOTE(vtl): Some of these tests are inherently flaky (e.g., if run on a
6 // heavily-loaded system). Sorry. |test::EpsilonDeadline()| may be increased to
7 // increase tolerance and reduce observed flakiness (though doing so reduces the
8 // meaningfulness of the test).
9 
10 #include "mojo/edk/system/awakable_list.h"
11 
12 #include "mojo/edk/system/handle_signals_state.h"
13 #include "mojo/edk/system/test_utils.h"
14 #include "mojo/edk/system/waiter.h"
15 #include "mojo/edk/system/waiter_test_utils.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace mojo {
19 namespace edk {
20 namespace {
21 
TEST(AwakableListTest,BasicCancel)22 TEST(AwakableListTest, BasicCancel) {
23   MojoResult result;
24   uintptr_t context;
25 
26   // Cancel immediately after thread start.
27   {
28     AwakableList awakable_list;
29     test::SimpleWaiterThread thread(&result, &context);
30     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
31     thread.Start();
32     awakable_list.CancelAll();
33     // Double-remove okay:
34     awakable_list.Remove(thread.waiter());
35   }  // Join |thread|.
36   EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
37   EXPECT_EQ(1u, context);
38 
39   // Cancel before after thread start.
40   {
41     AwakableList awakable_list;
42     test::SimpleWaiterThread thread(&result, &context);
43     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
44     awakable_list.CancelAll();
45     thread.Start();
46   }  // Join |thread|.
47   EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
48   EXPECT_EQ(2u, context);
49 
50   // Cancel some time after thread start.
51   {
52     AwakableList awakable_list;
53     test::SimpleWaiterThread thread(&result, &context);
54     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
55     thread.Start();
56     test::Sleep(2 * test::EpsilonDeadline());
57     awakable_list.CancelAll();
58   }  // Join |thread|.
59   EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
60   EXPECT_EQ(3u, context);
61 }
62 
TEST(AwakableListTest,BasicAwakeSatisfied)63 TEST(AwakableListTest, BasicAwakeSatisfied) {
64   MojoResult result;
65   uintptr_t context;
66 
67   // Awake immediately after thread start.
68   {
69     AwakableList awakable_list;
70     test::SimpleWaiterThread thread(&result, &context);
71     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
72     thread.Start();
73     awakable_list.AwakeForStateChange(HandleSignalsState(
74         MOJO_HANDLE_SIGNAL_READABLE,
75         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
76     awakable_list.Remove(thread.waiter());
77   }  // Join |thread|.
78   EXPECT_EQ(MOJO_RESULT_OK, result);
79   EXPECT_EQ(1u, context);
80 
81   // Awake before after thread start.
82   {
83     AwakableList awakable_list;
84     test::SimpleWaiterThread thread(&result, &context);
85     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
86     awakable_list.AwakeForStateChange(HandleSignalsState(
87         MOJO_HANDLE_SIGNAL_WRITABLE,
88         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
89     awakable_list.Remove(thread.waiter());
90     // Double-remove okay:
91     awakable_list.Remove(thread.waiter());
92     thread.Start();
93   }  // Join |thread|.
94   EXPECT_EQ(MOJO_RESULT_OK, result);
95   EXPECT_EQ(2u, context);
96 
97   // Awake some time after thread start.
98   {
99     AwakableList awakable_list;
100     test::SimpleWaiterThread thread(&result, &context);
101     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
102     thread.Start();
103     test::Sleep(2 * test::EpsilonDeadline());
104     awakable_list.AwakeForStateChange(HandleSignalsState(
105         MOJO_HANDLE_SIGNAL_READABLE,
106         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
107     awakable_list.Remove(thread.waiter());
108   }  // Join |thread|.
109   EXPECT_EQ(MOJO_RESULT_OK, result);
110   EXPECT_EQ(3u, context);
111 }
112 
TEST(AwakableListTest,BasicAwakeUnsatisfiable)113 TEST(AwakableListTest, BasicAwakeUnsatisfiable) {
114   MojoResult result;
115   uintptr_t context;
116 
117   // Awake (for unsatisfiability) immediately after thread start.
118   {
119     AwakableList awakable_list;
120     test::SimpleWaiterThread thread(&result, &context);
121     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
122     thread.Start();
123     awakable_list.AwakeForStateChange(HandleSignalsState(
124         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE));
125     awakable_list.Remove(thread.waiter());
126   }  // Join |thread|.
127   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
128   EXPECT_EQ(1u, context);
129 
130   // Awake (for unsatisfiability) before after thread start.
131   {
132     AwakableList awakable_list;
133     test::SimpleWaiterThread thread(&result, &context);
134     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
135     awakable_list.AwakeForStateChange(HandleSignalsState(
136         MOJO_HANDLE_SIGNAL_READABLE, MOJO_HANDLE_SIGNAL_READABLE));
137     awakable_list.Remove(thread.waiter());
138     thread.Start();
139   }  // Join |thread|.
140   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
141   EXPECT_EQ(2u, context);
142 
143   // Awake (for unsatisfiability) some time after thread start.
144   {
145     AwakableList awakable_list;
146     test::SimpleWaiterThread thread(&result, &context);
147     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
148     thread.Start();
149     test::Sleep(2 * test::EpsilonDeadline());
150     awakable_list.AwakeForStateChange(HandleSignalsState(
151         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE));
152     awakable_list.Remove(thread.waiter());
153     // Double-remove okay:
154     awakable_list.Remove(thread.waiter());
155   }  // Join |thread|.
156   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
157   EXPECT_EQ(3u, context);
158 }
159 
TEST(AwakableListTest,MultipleAwakables)160 TEST(AwakableListTest, MultipleAwakables) {
161   MojoResult result1;
162   MojoResult result2;
163   MojoResult result3;
164   MojoResult result4;
165   uintptr_t context1;
166   uintptr_t context2;
167   uintptr_t context3;
168   uintptr_t context4;
169 
170   // Cancel two awakables.
171   {
172     AwakableList awakable_list;
173     test::SimpleWaiterThread thread1(&result1, &context1);
174     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
175     thread1.Start();
176     test::SimpleWaiterThread thread2(&result2, &context2);
177     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
178     thread2.Start();
179     test::Sleep(2 * test::EpsilonDeadline());
180     awakable_list.CancelAll();
181   }  // Join threads.
182   EXPECT_EQ(MOJO_RESULT_CANCELLED, result1);
183   EXPECT_EQ(1u, context1);
184   EXPECT_EQ(MOJO_RESULT_CANCELLED, result2);
185   EXPECT_EQ(2u, context2);
186 
187   // Awake one awakable, cancel other.
188   {
189     AwakableList awakable_list;
190     test::SimpleWaiterThread thread1(&result1, &context1);
191     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
192     thread1.Start();
193     test::SimpleWaiterThread thread2(&result2, &context2);
194     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 4);
195     thread2.Start();
196     test::Sleep(2 * test::EpsilonDeadline());
197     awakable_list.AwakeForStateChange(HandleSignalsState(
198         MOJO_HANDLE_SIGNAL_READABLE,
199         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
200     awakable_list.Remove(thread1.waiter());
201     awakable_list.CancelAll();
202   }  // Join threads.
203   EXPECT_EQ(MOJO_RESULT_OK, result1);
204   EXPECT_EQ(3u, context1);
205   EXPECT_EQ(MOJO_RESULT_CANCELLED, result2);
206   EXPECT_EQ(4u, context2);
207 
208   // Cancel one awakable, awake other for unsatisfiability.
209   {
210     AwakableList awakable_list;
211     test::SimpleWaiterThread thread1(&result1, &context1);
212     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 5);
213     thread1.Start();
214     test::SimpleWaiterThread thread2(&result2, &context2);
215     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 6);
216     thread2.Start();
217     test::Sleep(2 * test::EpsilonDeadline());
218     awakable_list.AwakeForStateChange(HandleSignalsState(
219         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE));
220     awakable_list.Remove(thread2.waiter());
221     awakable_list.CancelAll();
222   }  // Join threads.
223   EXPECT_EQ(MOJO_RESULT_CANCELLED, result1);
224   EXPECT_EQ(5u, context1);
225   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2);
226   EXPECT_EQ(6u, context2);
227 
228   // Cancel one awakable, awake other for unsatisfiability.
229   {
230     AwakableList awakable_list;
231     test::SimpleWaiterThread thread1(&result1, &context1);
232     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 7);
233     thread1.Start();
234 
235     test::Sleep(1 * test::EpsilonDeadline());
236 
237     // Should do nothing.
238     awakable_list.AwakeForStateChange(HandleSignalsState(
239         MOJO_HANDLE_SIGNAL_NONE,
240         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
241 
242     test::SimpleWaiterThread thread2(&result2, &context2);
243     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 8);
244     thread2.Start();
245 
246     test::Sleep(1 * test::EpsilonDeadline());
247 
248     // Awake #1.
249     awakable_list.AwakeForStateChange(HandleSignalsState(
250         MOJO_HANDLE_SIGNAL_READABLE,
251         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
252     awakable_list.Remove(thread1.waiter());
253 
254     test::Sleep(1 * test::EpsilonDeadline());
255 
256     test::SimpleWaiterThread thread3(&result3, &context3);
257     awakable_list.Add(thread3.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 9);
258     thread3.Start();
259 
260     test::SimpleWaiterThread thread4(&result4, &context4);
261     awakable_list.Add(thread4.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 10);
262     thread4.Start();
263 
264     test::Sleep(1 * test::EpsilonDeadline());
265 
266     // Awake #2 and #3 for unsatisfiability.
267     awakable_list.AwakeForStateChange(HandleSignalsState(
268         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE));
269     awakable_list.Remove(thread2.waiter());
270     awakable_list.Remove(thread3.waiter());
271 
272     // Cancel #4.
273     awakable_list.CancelAll();
274   }  // Join threads.
275   EXPECT_EQ(MOJO_RESULT_OK, result1);
276   EXPECT_EQ(7u, context1);
277   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2);
278   EXPECT_EQ(8u, context2);
279   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result3);
280   EXPECT_EQ(9u, context3);
281   EXPECT_EQ(MOJO_RESULT_CANCELLED, result4);
282   EXPECT_EQ(10u, context4);
283 }
284 
285 class KeepAwakable : public Awakable {
286  public:
KeepAwakable()287   KeepAwakable() : awake_count(0) {}
288 
Awake(MojoResult result,uintptr_t context)289   bool Awake(MojoResult result, uintptr_t context) override {
290     awake_count++;
291     return true;
292   }
293 
294   int awake_count;
295 
296   DISALLOW_COPY_AND_ASSIGN(KeepAwakable);
297 };
298 
299 class RemoveAwakable : public Awakable {
300  public:
RemoveAwakable()301   RemoveAwakable() : awake_count(0) {}
302 
Awake(MojoResult result,uintptr_t context)303   bool Awake(MojoResult result, uintptr_t context) override {
304     awake_count++;
305     return false;
306   }
307 
308   int awake_count;
309 
310   DISALLOW_COPY_AND_ASSIGN(RemoveAwakable);
311 };
312 
TEST(AwakableListTest,KeepAwakablesReturningTrue)313 TEST(AwakableListTest, KeepAwakablesReturningTrue) {
314   KeepAwakable keep0;
315   KeepAwakable keep1;
316   RemoveAwakable remove0;
317   RemoveAwakable remove1;
318   RemoveAwakable remove2;
319 
320   HandleSignalsState hss(MOJO_HANDLE_SIGNAL_WRITABLE,
321                          MOJO_HANDLE_SIGNAL_WRITABLE);
322 
323   AwakableList remove_all;
324   remove_all.Add(&remove0, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
325   remove_all.Add(&remove1, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
326 
327   remove_all.AwakeForStateChange(hss);
328   EXPECT_EQ(remove0.awake_count, 1);
329   EXPECT_EQ(remove1.awake_count, 1);
330 
331   remove_all.AwakeForStateChange(hss);
332   EXPECT_EQ(remove0.awake_count, 1);
333   EXPECT_EQ(remove1.awake_count, 1);
334 
335   AwakableList remove_first;
336   remove_first.Add(&remove2, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
337   remove_first.Add(&keep0, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
338   remove_first.Add(&keep1, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
339 
340   remove_first.AwakeForStateChange(hss);
341   EXPECT_EQ(keep0.awake_count, 1);
342   EXPECT_EQ(keep1.awake_count, 1);
343   EXPECT_EQ(remove2.awake_count, 1);
344 
345   remove_first.AwakeForStateChange(hss);
346   EXPECT_EQ(keep0.awake_count, 2);
347   EXPECT_EQ(keep1.awake_count, 2);
348   EXPECT_EQ(remove2.awake_count, 1);
349 
350   remove_first.Remove(&keep0);
351   remove_first.Remove(&keep1);
352 }
353 
354 }  // namespace
355 }  // namespace edk
356 }  // namespace mojo
357