diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-13 23:12:50 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-13 23:12:50 +0000 |
commit | 1389053dca9b296f74d5704c62f6494aef1cbb63 (patch) | |
tree | f1bed144cf559be845c4c031a6ebbf9869b9e70f /mojo | |
parent | 4540d58b344a1e284c5fa0224b748612fa9d84c3 (diff) | |
download | chromium_src-1389053dca9b296f74d5704c62f6494aef1cbb63.zip chromium_src-1389053dca9b296f74d5704c62f6494aef1cbb63.tar.gz chromium_src-1389053dca9b296f74d5704c62f6494aef1cbb63.tar.bz2 |
Mojo: Update Waiter::Wait() to not put the context into the return value.
(Instead, it puts it into an out parameter.)
Also reverse the order of the arguments to Waiter::Awake().
R=davemoore@chromium.org
Review URL: https://codereview.chromium.org/337803002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277119 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/system/channel_unittest.cc | 2 | ||||
-rw-r--r-- | mojo/system/core.cc | 10 | ||||
-rw-r--r-- | mojo/system/local_data_pipe_unittest.cc | 32 | ||||
-rw-r--r-- | mojo/system/message_pipe_dispatcher_unittest.cc | 32 | ||||
-rw-r--r-- | mojo/system/message_pipe_unittest.cc | 20 | ||||
-rw-r--r-- | mojo/system/multiprocess_message_pipe_unittest.cc | 2 | ||||
-rw-r--r-- | mojo/system/remote_message_pipe_unittest.cc | 39 | ||||
-rw-r--r-- | mojo/system/simple_dispatcher_unittest.cc | 163 | ||||
-rw-r--r-- | mojo/system/waiter.cc | 27 | ||||
-rw-r--r-- | mojo/system/waiter.h | 44 | ||||
-rw-r--r-- | mojo/system/waiter_list.cc | 6 | ||||
-rw-r--r-- | mojo/system/waiter_list_unittest.cc | 112 | ||||
-rw-r--r-- | mojo/system/waiter_test_utils.cc | 17 | ||||
-rw-r--r-- | mojo/system/waiter_test_utils.h | 10 | ||||
-rw-r--r-- | mojo/system/waiter_unittest.cc | 100 |
15 files changed, 380 insertions, 236 deletions
diff --git a/mojo/system/channel_unittest.cc b/mojo/system/channel_unittest.cc index 200e7fa..e8c8260 100644 --- a/mojo/system/channel_unittest.cc +++ b/mojo/system/channel_unittest.cc @@ -273,7 +273,7 @@ TEST_F(ChannelTest, ShutdownAfterAttach) { // ... since this |Wait()| should fail once the channel is shut down. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + waiter.Wait(MOJO_DEADLINE_INDEFINITE, NULL)); mp->RemoveWaiter(0, &waiter); mp->Close(0); diff --git a/mojo/system/core.cc b/mojo/system/core.cc index cfa4db7..f670272 100644 --- a/mojo/system/core.cc +++ b/mojo/system/core.cc @@ -539,10 +539,14 @@ MojoResult Core::WaitManyInternal(const MojoHandle* handles, } uint32_t num_added = i; - if (rv == MOJO_RESULT_ALREADY_EXISTS) + if (rv == MOJO_RESULT_ALREADY_EXISTS) { rv = static_cast<MojoResult>(i); // The i-th one is already "triggered". - else if (rv == MOJO_RESULT_OK) - rv = waiter.Wait(deadline); + } else if (rv == MOJO_RESULT_OK) { + uint32_t context = static_cast<uint32_t>(-1); + rv = waiter.Wait(deadline, &context); + if (rv == MOJO_RESULT_OK) + rv = static_cast<MojoResult>(context); + } // Make sure no other dispatchers try to wake |waiter| for the current // |Wait()|/|WaitMany()| call. (Only after doing this can |waiter| be diff --git a/mojo/system/local_data_pipe_unittest.cc b/mojo/system/local_data_pipe_unittest.cc index 3477d65f..391f001 100644 --- a/mojo/system/local_data_pipe_unittest.cc +++ b/mojo/system/local_data_pipe_unittest.cc @@ -201,6 +201,7 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); Waiter waiter; + uint32_t context = 0; // Never readable. waiter.Init(); @@ -223,7 +224,7 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 56)); // And it shouldn't be writable yet. - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); dp->ProducerRemoveWaiter(&waiter); // Do it again. @@ -241,7 +242,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { EXPECT_EQ(-1, elements[1]); // Waiting should now succeed. - EXPECT_EQ(78, waiter.Wait(1000)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); + EXPECT_EQ(78u, context); dp->ProducerRemoveWaiter(&waiter); // Try writing, using a two-phase write. @@ -278,7 +280,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { static_cast<uint32_t>(1u * sizeof(elements[0])))); // Waiting should succeed. - EXPECT_EQ(90, waiter.Wait(1000)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); + EXPECT_EQ(90u, context); dp->ProducerRemoveWaiter(&waiter); // Write one element. @@ -296,7 +299,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { dp->ConsumerClose(); // It should now be never-writable. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000, &context)); + EXPECT_EQ(12u, context); dp->ProducerRemoveWaiter(&waiter); dp->ProducerClose(); @@ -316,6 +320,7 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { { scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); Waiter waiter; + uint32_t context = 0; // Never writable. waiter.Init(); @@ -326,7 +331,7 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 34)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); dp->ConsumerRemoveWaiter(&waiter); // Write two elements. @@ -372,7 +377,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { dp->ProducerWriteData(elements, &num_bytes, true)); // Waiting should now succeed. - EXPECT_EQ(90, waiter.Wait(1000)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); + EXPECT_EQ(90u, context); dp->ConsumerRemoveWaiter(&waiter); // Close the producer. @@ -405,6 +411,7 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { { scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); Waiter waiter; + uint32_t context = 0; // Write two elements. int32_t* elements = NULL; @@ -469,7 +476,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { dp->ProducerClose(); // Should be never-readable. - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, waiter.Wait(1000, &context)); + EXPECT_EQ(56u, context); dp->ConsumerRemoveWaiter(&waiter); dp->ConsumerClose(); @@ -507,14 +515,14 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerAddWaiter(&waiter, MOJO_WAIT_FLAG_WRITABLE, 1)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); dp->ProducerRemoveWaiter(&waiter); // It shouldn't be readable yet either. waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 2)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); dp->ConsumerRemoveWaiter(&waiter); static_cast<int32_t*>(write_ptr)[0] = 123; @@ -566,7 +574,7 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 7)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); dp->ConsumerRemoveWaiter(&waiter); // End the two-phase read without reading anything. @@ -605,7 +613,7 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 1)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); dp->ConsumerRemoveWaiter(&waiter); uint32_t num_bytes = static_cast<uint32_t>(sizeof(int32_t)); @@ -658,7 +666,7 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerAddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 7)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); dp->ConsumerRemoveWaiter(&waiter); dp->ProducerClose(); diff --git a/mojo/system/message_pipe_dispatcher_unittest.cc b/mojo/system/message_pipe_dispatcher_unittest.cc index 2fc6469..127e34e 100644 --- a/mojo/system/message_pipe_dispatcher_unittest.cc +++ b/mojo/system/message_pipe_dispatcher_unittest.cc @@ -48,6 +48,7 @@ TEST(MessagePipeDispatcherTest, Basic) { d1->Init(mp, i ^ 1); // 1, 0. } Waiter w; + uint32_t context = 0; // Try adding a writable waiter when already writable. w.Init(); @@ -66,7 +67,8 @@ TEST(MessagePipeDispatcherTest, Basic) { NULL, MOJO_WRITE_MESSAGE_FLAG_NONE)); stopwatch.Start(); - EXPECT_EQ(1, w.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(1u, context); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); d0->RemoveWaiter(&w); @@ -91,7 +93,7 @@ TEST(MessagePipeDispatcherTest, Basic) { EXPECT_EQ(MOJO_RESULT_OK, d0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 3)); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, NULL)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); d0->RemoveWaiter(&w); @@ -101,7 +103,7 @@ TEST(MessagePipeDispatcherTest, Basic) { d0->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 3)); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - w.Wait(2 * test::EpsilonTimeout().InMicroseconds())); + w.Wait(2 * test::EpsilonTimeout().InMicroseconds(), NULL)); base::TimeDelta elapsed = stopwatch.Elapsed(); EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); @@ -264,6 +266,7 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) { base::TimeDelta elapsed; bool did_wait; MojoResult result; + uint32_t context; // Run this test both with |d0| as port 0, |d1| as port 1 and vice versa. for (unsigned i = 0; i < 2; i++) { @@ -282,8 +285,8 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) { test::WaiterThread thread(d1, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 0, - &did_wait, &result); + 1, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -298,15 +301,16 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) { EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); EXPECT_TRUE(did_wait); - EXPECT_EQ(0, result); + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(1u, context); // Now |d1| is already readable. Try waiting for it again. { test::WaiterThread thread(d1, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 1, - &did_wait, &result); + 2, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); } // Joins the thread. @@ -330,8 +334,8 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) { test::WaiterThread thread(d1, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 0, - &did_wait, &result); + 3, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -342,6 +346,7 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) { EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); EXPECT_TRUE(did_wait); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(3u, context); EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); } @@ -363,8 +368,8 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) { test::WaiterThread thread(d1, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 0, - &did_wait, &result); + 4, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -375,6 +380,7 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) { EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); EXPECT_TRUE(did_wait); EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(4u, context); EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); } @@ -469,7 +475,7 @@ class ReaderThread : public base::SimpleThread { result == MOJO_RESULT_ALREADY_EXISTS) << "result: " << result; if (result == MOJO_RESULT_OK) { // Actually need to wait. - EXPECT_EQ(0, w.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, NULL)); read_dispatcher_->RemoveWaiter(&w); } diff --git a/mojo/system/message_pipe_unittest.cc b/mojo/system/message_pipe_unittest.cc index 8708d9f..73c310f 100644 --- a/mojo/system/message_pipe_unittest.cc +++ b/mojo/system/message_pipe_unittest.cc @@ -378,7 +378,7 @@ TEST(MessagePipeTest, BasicWaiting) { waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, mp->AddWaiter(0, &waiter, MOJO_WAIT_FLAG_READABLE, 1)); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, NULL)); mp->RemoveWaiter(0, &waiter); // Write from port 0 (to port 1), to make port 1 readable. @@ -440,15 +440,16 @@ TEST(MessagePipeTest, ThreadedWaiting) { const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); MojoResult result; + uint32_t context; // Write to wake up waiter waiting for read. { scoped_refptr<MessagePipe> mp(new MessagePipe()); - test::SimpleWaiterThread thread(&result); + test::SimpleWaiterThread thread(&result, &context); thread.waiter()->Init(); EXPECT_EQ(MOJO_RESULT_OK, - mp->AddWaiter(1, thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0)); + mp->AddWaiter(1, thread.waiter(), MOJO_WAIT_FLAG_READABLE, 1)); thread.Start(); buffer[0] = 123456789; @@ -465,16 +466,17 @@ TEST(MessagePipeTest, ThreadedWaiting) { mp->Close(1); } // Joins |thread|. // The waiter should have woken up successfully. - EXPECT_EQ(0, result); + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(1u, context); // Close to cancel waiter. { scoped_refptr<MessagePipe> mp(new MessagePipe()); - test::SimpleWaiterThread thread(&result); + test::SimpleWaiterThread thread(&result, &context); thread.waiter()->Init(); EXPECT_EQ(MOJO_RESULT_OK, - mp->AddWaiter(1, thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0)); + mp->AddWaiter(1, thread.waiter(), MOJO_WAIT_FLAG_READABLE, 2)); thread.Start(); // Close port 1 first -- this should result in the waiter being cancelled. @@ -487,15 +489,16 @@ TEST(MessagePipeTest, ThreadedWaiting) { mp->Close(0); } // Joins |thread|. EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(2u, context); // Close to make waiter un-wake-up-able. { scoped_refptr<MessagePipe> mp(new MessagePipe()); - test::SimpleWaiterThread thread(&result); + test::SimpleWaiterThread thread(&result, &context); thread.waiter()->Init(); EXPECT_EQ(MOJO_RESULT_OK, - mp->AddWaiter(1, thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0)); + mp->AddWaiter(1, thread.waiter(), MOJO_WAIT_FLAG_READABLE, 3)); thread.Start(); // Close port 0 first -- this should wake the waiter up, since port 1 will @@ -509,6 +512,7 @@ TEST(MessagePipeTest, ThreadedWaiting) { mp->Close(1); } // Joins |thread|. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(3u, context); } } // namespace diff --git a/mojo/system/multiprocess_message_pipe_unittest.cc b/mojo/system/multiprocess_message_pipe_unittest.cc index 8279196..fa16996 100644 --- a/mojo/system/multiprocess_message_pipe_unittest.cc +++ b/mojo/system/multiprocess_message_pipe_unittest.cc @@ -135,7 +135,7 @@ MojoResult WaitIfNecessary(scoped_refptr<MessagePipe> mp, MojoWaitFlags flags) { add_result; } - MojoResult wait_result = waiter.Wait(MOJO_DEADLINE_INDEFINITE); + MojoResult wait_result = waiter.Wait(MOJO_DEADLINE_INDEFINITE, NULL); mp->RemoveWaiter(0, &waiter); return wait_result; } diff --git a/mojo/system/remote_message_pipe_unittest.cc b/mojo/system/remote_message_pipe_unittest.cc index 3c5e2a4..f6db49f 100644 --- a/mojo/system/remote_message_pipe_unittest.cc +++ b/mojo/system/remote_message_pipe_unittest.cc @@ -177,6 +177,7 @@ TEST_F(RemoteMessagePipeTest, Basic) { char buffer[100] = { 0 }; uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer)); Waiter waiter; + uint32_t context = 0; // Connect message pipes. MP 0, port 1 will be attached to channel 0 and // connected to MP 1, port 0, which will be attached to channel 1. This leaves @@ -206,7 +207,8 @@ TEST_F(RemoteMessagePipeTest, Basic) { MOJO_WRITE_MESSAGE_FLAG_NONE)); // Wait. - EXPECT_EQ(123, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(123u, context); mp1->RemoveWaiter(1, &waiter); // Read from MP 1, port 1. @@ -230,7 +232,8 @@ TEST_F(RemoteMessagePipeTest, Basic) { NULL, MOJO_WRITE_MESSAGE_FLAG_NONE)); - EXPECT_EQ(456, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(456u, context); mp0->RemoveWaiter(0, &waiter); buffer_size = static_cast<uint32_t>(sizeof(buffer)); @@ -252,7 +255,8 @@ TEST_F(RemoteMessagePipeTest, Basic) { MojoResult result = mp1->AddWaiter(1, &waiter, MOJO_WAIT_FLAG_READABLE, 789); if (result == MOJO_RESULT_OK) { EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(789u, context); mp1->RemoveWaiter(1, &waiter); } else { EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); @@ -268,6 +272,7 @@ TEST_F(RemoteMessagePipeTest, Multiplex) { char buffer[100] = { 0 }; uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer)); Waiter waiter; + uint32_t context = 0; // Connect message pipes as in the |Basic| test. @@ -301,7 +306,8 @@ TEST_F(RemoteMessagePipeTest, Multiplex) { NULL, MOJO_WRITE_MESSAGE_FLAG_NONE)); - EXPECT_EQ(789, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(789u, context); mp3->RemoveWaiter(1, &waiter); // Make sure there's nothing on MP 0, port 0 or MP 1, port 1 or MP 2, port 0. @@ -346,7 +352,8 @@ TEST_F(RemoteMessagePipeTest, Multiplex) { NULL, MOJO_WRITE_MESSAGE_FLAG_NONE)); - EXPECT_EQ(123, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(123u, context); mp1->RemoveWaiter(1, &waiter); // Make sure there's nothing on the other ports. @@ -389,6 +396,7 @@ TEST_F(RemoteMessagePipeTest, CloseBeforeConnect) { char buffer[100] = { 0 }; uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer)); Waiter waiter; + uint32_t context = 0; // Connect message pipes. MP 0, port 1 will be attached to channel 0 and // connected to MP 1, port 0, which will be attached to channel 1. This leaves @@ -424,7 +432,8 @@ TEST_F(RemoteMessagePipeTest, CloseBeforeConnect) { BootstrapMessagePipeNoWait(1, mp1); // Wait. - EXPECT_EQ(123, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(123u, context); mp1->RemoveWaiter(1, &waiter); // Read from MP 1, port 1. @@ -443,6 +452,7 @@ TEST_F(RemoteMessagePipeTest, CloseBeforeConnect) { TEST_F(RemoteMessagePipeTest, HandlePassing) { static const char kHello[] = "hello"; Waiter waiter; + uint32_t context = 0; scoped_refptr<MessagePipe> mp0(new MessagePipe( scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), @@ -484,7 +494,8 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { } // Wait. - EXPECT_EQ(123, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(123u, context); mp1->RemoveWaiter(1, &waiter); // Read from MP 1, port 1. @@ -518,7 +529,8 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { waiter.Init(); EXPECT_EQ(MOJO_RESULT_OK, dispatcher->AddWaiter(&waiter, MOJO_WAIT_FLAG_READABLE, 456)); - EXPECT_EQ(456, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(456u, context); dispatcher->RemoveWaiter(&waiter); // Read from the dispatcher. @@ -541,7 +553,8 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { MOJO_WRITE_MESSAGE_FLAG_NONE)); // Wait. - EXPECT_EQ(789, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(789u, context); local_mp->RemoveWaiter(1, &waiter); // Read from "local_mp", port 1. @@ -573,6 +586,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { TEST_F(RemoteMessagePipeTest, MAYBE_SharedBufferPassing) { static const char kHello[] = "hello"; Waiter waiter; + uint32_t context = 0; scoped_refptr<MessagePipe> mp0(new MessagePipe( scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), @@ -628,7 +642,8 @@ TEST_F(RemoteMessagePipeTest, MAYBE_SharedBufferPassing) { } // Wait. - EXPECT_EQ(123, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(123u, context); mp1->RemoveWaiter(1, &waiter); // Read from MP 1, port 1. @@ -693,6 +708,7 @@ TEST_F(RemoteMessagePipeTest, MAYBE_PlatformHandlePassing) { static const char kHello[] = "hello"; static const char kWorld[] = "world"; Waiter waiter; + uint32_t context = 0; scoped_refptr<MessagePipe> mp0(new MessagePipe( scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()), @@ -737,7 +753,8 @@ TEST_F(RemoteMessagePipeTest, MAYBE_PlatformHandlePassing) { } // Wait. - EXPECT_EQ(123, waiter.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(123u, context); mp1->RemoveWaiter(1, &waiter); // Read from MP 1, port 1. diff --git a/mojo/system/simple_dispatcher_unittest.cc b/mojo/system/simple_dispatcher_unittest.cc index 26fc277..3b292ddd 100644 --- a/mojo/system/simple_dispatcher_unittest.cc +++ b/mojo/system/simple_dispatcher_unittest.cc @@ -92,6 +92,7 @@ TEST(SimpleDispatcherTest, Basic) { scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher()); Waiter w; + uint32_t context = 0; // Try adding a readable waiter when already readable. w.Init(); @@ -106,8 +107,9 @@ TEST(SimpleDispatcherTest, Basic) { EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 1)); d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE); stopwatch.Start(); - EXPECT_EQ(1, w.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(1u, context); d->RemoveWaiter(&w); // Wait for zero time for writable when already writable. @@ -116,8 +118,9 @@ TEST(SimpleDispatcherTest, Basic) { EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 2)); d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE); stopwatch.Start(); - EXPECT_EQ(2, w.Wait(0)); + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(0, &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(2u, context); d->RemoveWaiter(&w); // Wait for non-zero, finite time for writable when already writable. @@ -126,8 +129,10 @@ TEST(SimpleDispatcherTest, Basic) { EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 3)); d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE); stopwatch.Start(); - EXPECT_EQ(3, w.Wait(2 * test::EpsilonTimeout().InMicroseconds())); + EXPECT_EQ(MOJO_RESULT_OK, + w.Wait(2 * test::EpsilonTimeout().InMicroseconds(), &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(3u, context); d->RemoveWaiter(&w); // Wait for zero time for writable when not writable (will time out). @@ -135,7 +140,7 @@ TEST(SimpleDispatcherTest, Basic) { d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE); EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4)); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, NULL)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); d->RemoveWaiter(&w); @@ -143,10 +148,10 @@ TEST(SimpleDispatcherTest, Basic) { // out). w.Init(); d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE); - EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4)); + EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 5)); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - w.Wait(2 * test::EpsilonTimeout().InMicroseconds())); + w.Wait(2 * test::EpsilonTimeout().InMicroseconds(), NULL)); base::TimeDelta elapsed = stopwatch.Elapsed(); EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); @@ -160,45 +165,50 @@ TEST(SimpleDispatcherTest, BasicUnsatisfiable) { scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher()); Waiter w; + uint32_t context = 0; // Try adding a writable waiter when it can never be writable. w.Init(); d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE); d->SetSatisfiedFlags(0); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 5)); + d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 1)); // Shouldn't need to remove the waiter (it was not added). // Wait (forever) for writable and then it becomes never writable. w.Init(); d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE); - EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 6)); + EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 2)); d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(2u, context); d->RemoveWaiter(&w); // Wait for zero time for writable and then it becomes never writable. w.Init(); d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE); - EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 6)); + EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 3)); d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(0)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(0, &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(3u, context); d->RemoveWaiter(&w); // Wait for non-zero, finite time for writable and then it becomes never // writable. w.Init(); d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE); - EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 7)); + EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4)); d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - w.Wait(2 * test::EpsilonTimeout().InMicroseconds())); + w.Wait(2 * test::EpsilonTimeout().InMicroseconds(), &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(4u, context); d->RemoveWaiter(&w); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); @@ -209,45 +219,49 @@ TEST(SimpleDispatcherTest, BasicClosed) { scoped_refptr<MockSimpleDispatcher> d; Waiter w; + uint32_t context = 0; // Try adding a writable waiter when the dispatcher has been closed. d = new MockSimpleDispatcher(); w.Init(); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 8)); + d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 1)); // Shouldn't need to remove the waiter (it was not added). // Wait (forever) for writable and then the dispatcher is closed. d = new MockSimpleDispatcher(); w.Init(); - EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 9)); + EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 2)); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(2u, context); // Don't need to remove waiters from closed dispatchers. // Wait for zero time for writable and then the dispatcher is closed. d = new MockSimpleDispatcher(); w.Init(); - EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 10)); + EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 3)); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(0)); + EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(0, &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(3u, context); // Don't need to remove waiters from closed dispatchers. // Wait for non-zero, finite time for writable and then the dispatcher is // closed. d = new MockSimpleDispatcher(); w.Init(); - EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 11)); + EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4)); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_CANCELLED, - w.Wait(2 * test::EpsilonTimeout().InMicroseconds())); + w.Wait(2 * test::EpsilonTimeout().InMicroseconds(), &context)); EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); + EXPECT_EQ(4u, context); // Don't need to remove waiters from closed dispatchers. } @@ -255,6 +269,7 @@ TEST(SimpleDispatcherTest, BasicThreaded) { test::Stopwatch stopwatch; bool did_wait; MojoResult result; + uint32_t context; // Wait for readable (already readable). { @@ -264,8 +279,8 @@ TEST(SimpleDispatcherTest, BasicThreaded) { test::WaiterThread thread(d, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 0, - &did_wait, &result); + 1, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); } // Joins the thread. @@ -282,8 +297,8 @@ TEST(SimpleDispatcherTest, BasicThreaded) { test::WaiterThread thread(d, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 1, - &did_wait, &result); + 2, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -294,7 +309,8 @@ TEST(SimpleDispatcherTest, BasicThreaded) { EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); EXPECT_TRUE(did_wait); - EXPECT_EQ(1, result); + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(2u, context); // Wait for readable and becomes never-readable after some time. { @@ -302,8 +318,8 @@ TEST(SimpleDispatcherTest, BasicThreaded) { test::WaiterThread thread(d, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 2, - &did_wait, &result); + 3, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -315,6 +331,7 @@ TEST(SimpleDispatcherTest, BasicThreaded) { EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); EXPECT_TRUE(did_wait); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(3u, context); // Wait for readable and dispatcher gets closed. { @@ -322,8 +339,8 @@ TEST(SimpleDispatcherTest, BasicThreaded) { test::WaiterThread thread(d, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - 3, - &did_wait, &result); + 4, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -334,6 +351,7 @@ TEST(SimpleDispatcherTest, BasicThreaded) { EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); EXPECT_TRUE(did_wait); EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(4u, context); // Wait for readable and times out. { @@ -342,8 +360,8 @@ TEST(SimpleDispatcherTest, BasicThreaded) { test::WaiterThread thread(d, MOJO_WAIT_FLAG_READABLE, 2 * test::EpsilonTimeout().InMicroseconds(), - 4, - &did_wait, &result); + 5, + &did_wait, &result, &context); stopwatch.Start(); thread.Start(); base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); @@ -361,30 +379,34 @@ TEST(SimpleDispatcherTest, BasicThreaded) { } TEST(SimpleDispatcherTest, MultipleWaiters) { - static const size_t kNumWaiters = 20; + static const uint32_t kNumWaiters = 20; bool did_wait[kNumWaiters]; MojoResult result[kNumWaiters]; + uint32_t context[kNumWaiters]; // All wait for readable and becomes readable after some time. { scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher()); ScopedVector<test::WaiterThread> threads; - for (size_t i = 0; i < kNumWaiters; i++) { + for (uint32_t i = 0; i < kNumWaiters; i++) { threads.push_back(new test::WaiterThread(d, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - static_cast<MojoResult>(i), - &did_wait[i], &result[i])); + i, + &did_wait[i], + &result[i], + &context[i])); threads.back()->Start(); } base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } // Joins the threads. - for (size_t i = 0; i < kNumWaiters; i++) { + for (uint32_t i = 0; i < kNumWaiters; i++) { EXPECT_TRUE(did_wait[i]); - EXPECT_EQ(static_cast<MojoResult>(i), result[i]); + EXPECT_EQ(MOJO_RESULT_OK, result[i]); + EXPECT_EQ(i, context[i]); } // Some wait for readable, some for writable, and becomes readable after some @@ -392,20 +414,24 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { { scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher()); ScopedVector<test::WaiterThread> threads; - for (size_t i = 0; i < kNumWaiters / 2; i++) { + for (uint32_t i = 0; i < kNumWaiters / 2; i++) { threads.push_back(new test::WaiterThread(d, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - static_cast<MojoResult>(i), - &did_wait[i], &result[i])); + i, + &did_wait[i], + &result[i], + &context[i])); threads.back()->Start(); } - for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) { + for (uint32_t i = kNumWaiters / 2; i < kNumWaiters; i++) { threads.push_back(new test::WaiterThread(d, MOJO_WAIT_FLAG_WRITABLE, MOJO_DEADLINE_INDEFINITE, - static_cast<MojoResult>(i), - &did_wait[i], &result[i])); + i, + &did_wait[i], + &result[i], + &context[i])); threads.back()->Start(); } base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -413,13 +439,15 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { // This will wake up the ones waiting to write. EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } // Joins the threads. - for (size_t i = 0; i < kNumWaiters / 2; i++) { + for (uint32_t i = 0; i < kNumWaiters / 2; i++) { EXPECT_TRUE(did_wait[i]); - EXPECT_EQ(static_cast<MojoResult>(i), result[i]); + EXPECT_EQ(MOJO_RESULT_OK, result[i]); + EXPECT_EQ(i, context[i]); } - for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) { + for (uint32_t i = kNumWaiters / 2; i < kNumWaiters; i++) { EXPECT_TRUE(did_wait[i]); EXPECT_EQ(MOJO_RESULT_CANCELLED, result[i]); + EXPECT_EQ(i, context[i]); } // Some wait for readable, some for writable, and becomes readable and @@ -427,20 +455,24 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { { scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher()); ScopedVector<test::WaiterThread> threads; - for (size_t i = 0; i < kNumWaiters / 2; i++) { + for (uint32_t i = 0; i < kNumWaiters / 2; i++) { threads.push_back(new test::WaiterThread(d, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - static_cast<MojoResult>(i), - &did_wait[i], &result[i])); + i, + &did_wait[i], + &result[i], + &context[i])); threads.back()->Start(); } - for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) { + for (uint32_t i = kNumWaiters / 2; i < kNumWaiters; i++) { threads.push_back(new test::WaiterThread(d, MOJO_WAIT_FLAG_WRITABLE, MOJO_DEADLINE_INDEFINITE, - static_cast<MojoResult>(i), - &did_wait[i], &result[i])); + i, + &did_wait[i], + &result[i], + &context[i])); threads.back()->Start(); } base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); @@ -449,13 +481,15 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } // Joins the threads. - for (size_t i = 0; i < kNumWaiters / 2; i++) { + for (uint32_t i = 0; i < kNumWaiters / 2; i++) { EXPECT_TRUE(did_wait[i]); - EXPECT_EQ(static_cast<MojoResult>(i), result[i]); + EXPECT_EQ(MOJO_RESULT_OK, result[i]); + EXPECT_EQ(i, context[i]); } - for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) { + for (uint32_t i = kNumWaiters / 2; i < kNumWaiters; i++) { EXPECT_TRUE(did_wait[i]); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result[i]); + EXPECT_EQ(i, context[i]); } // Some wait for readable, some for writable, and becomes readable after some @@ -463,22 +497,22 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { { scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher()); ScopedVector<test::WaiterThread> threads; - for (size_t i = 0; i < kNumWaiters / 2; i++) { + for (uint32_t i = 0; i < kNumWaiters / 2; i++) { threads.push_back( new test::WaiterThread(d, MOJO_WAIT_FLAG_READABLE, 3 * test::EpsilonTimeout().InMicroseconds(), - static_cast<MojoResult>(i), - &did_wait[i], &result[i])); + i, + &did_wait[i], &result[i], &context[i])); threads.back()->Start(); } - for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) { + for (uint32_t i = kNumWaiters / 2; i < kNumWaiters; i++) { threads.push_back( new test::WaiterThread(d, MOJO_WAIT_FLAG_WRITABLE, 1 * test::EpsilonTimeout().InMicroseconds(), - static_cast<MojoResult>(i), - &did_wait[i], &result[i])); + i, + &did_wait[i], &result[i], &context[i])); threads.back()->Start(); } base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); @@ -486,11 +520,12 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { // All those waiting for writable should have timed out. EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } // Joins the threads. - for (size_t i = 0; i < kNumWaiters / 2; i++) { + for (uint32_t i = 0; i < kNumWaiters / 2; i++) { EXPECT_TRUE(did_wait[i]); - EXPECT_EQ(static_cast<MojoResult>(i), result[i]); + EXPECT_EQ(MOJO_RESULT_OK, result[i]); + EXPECT_EQ(i, context[i]); } - for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) { + for (uint32_t i = kNumWaiters / 2; i < kNumWaiters; i++) { EXPECT_TRUE(did_wait[i]); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result[i]); } diff --git a/mojo/system/waiter.cc b/mojo/system/waiter.cc index a7d18d3..5a3150d 100644 --- a/mojo/system/waiter.cc +++ b/mojo/system/waiter.cc @@ -18,8 +18,8 @@ Waiter::Waiter() initialized_(false), #endif awoken_(false), - awake_context_(static_cast<uint32_t>(-1)), - awake_result_(MOJO_RESULT_INTERNAL) { + awake_result_(MOJO_RESULT_INTERNAL), + awake_context_(static_cast<uint32_t>(-1)) { } Waiter::~Waiter() { @@ -36,7 +36,7 @@ void Waiter::Init() { } // TODO(vtl): Fast-path the |deadline == 0| case? -MojoResult Waiter::Wait(MojoDeadline deadline) { +MojoResult Waiter::Wait(MojoDeadline deadline, uint32_t* context) { base::AutoLock locker(lock_); #ifndef NDEBUG @@ -48,10 +48,9 @@ MojoResult Waiter::Wait(MojoDeadline deadline) { // Fast-path the already-awoken case: if (awoken_) { DCHECK_NE(awake_result_, MOJO_RESULT_INTERNAL); - // TODO(vtl): This is a temporary hack until I add a |context| out parameter - // and update all the call sites. - return (awake_result_ == MOJO_RESULT_OK) ? - static_cast<MojoResult>(awake_context_) : awake_result_; + if (context) + *context = awake_context_; + return awake_result_; } // |MojoDeadline| is actually a |uint64_t|, but we need a signed quantity. @@ -69,30 +68,28 @@ MojoResult Waiter::Wait(MojoDeadline deadline) { base::TimeDelta::FromMicroseconds(static_cast<int64_t>(deadline)); do { base::TimeTicks now_time = base::TimeTicks::HighResNow(); - if (now_time >= end_time) { + if (now_time >= end_time) return MOJO_RESULT_DEADLINE_EXCEEDED; - } cv_.TimedWait(end_time - now_time); } while (!awoken_); } DCHECK_NE(awake_result_, MOJO_RESULT_INTERNAL); - // TODO(vtl): This is a temporary hack until I add a |context| out parameter - // and update all the call sites. - return (awake_result_ == MOJO_RESULT_OK) ? - static_cast<MojoResult>(awake_context_) : awake_result_; + if (context) + *context = awake_context_; + return awake_result_; } -void Waiter::Awake(uint32_t context, MojoResult result) { +void Waiter::Awake(MojoResult result, uint32_t context) { base::AutoLock locker(lock_); if (awoken_) return; awoken_ = true; - awake_context_ = context; awake_result_ = result; + awake_context_ = context; cv_.Signal(); // |cv_.Wait()|/|cv_.TimedWait()| will return after |lock_| is released. } diff --git a/mojo/system/waiter.h b/mojo/system/waiter.h index e36cdd1..66fe6e7 100644 --- a/mojo/system/waiter.h +++ b/mojo/system/waiter.h @@ -29,23 +29,35 @@ class MOJO_SYSTEM_IMPL_EXPORT Waiter { // each time it's used. void Init(); - // TODO(vtl): FIXME -- Replace this with a version that has a |context| out - // parameter (which also doesn't turn the context into a result on success). - // Waits until a suitable |Awake()| is called. + // Waits until a suitable |Awake()| is called. (|context| may be null, in + // which case, obviously no context is ever returned.) // Returns: - // - The |context| passed to |Dispatcher::AddWaiter()| if it was woken up - // by that dispatcher for the reason specified by |flags| (in the call to - // |AddWaiter()|). - // - |MOJO_RESULT_CANCELLED| if a handle (on which |MojoWait()| was called) - // was closed; and - // - |MOJO_RESULT_FAILED_PRECONDITION| if the reasons for being awoken given - // by |flags| cannot (or can no longer) be satisfied (e.g., if the other - // end of a pipe is closed). - MojoResult Wait(MojoDeadline deadline); + // - The result given to the first call to |Awake()| (possibly before this + // call to |Wait()|); in this case, |*context| is set to the value passed + // to that call to |Awake()|. + // - |MOJO_RESULT_DEADLINE_EXCEEDED| if the deadline was exceeded; in this + // case |*context| is not modified. + // + // Usually, the context passed to |Awake()| will be the value passed to + // |Dispatcher::AddWaiter()|, which is usually the index to the array of + // handles passed to |MojoWaitMany()| (or 0 for |MojoWait()|). + // + // Typical |Awake()| results are: + // - |MOJO_RESULT_OK| if one of the flags passed to + // |MojoWait()|/|MojoWaitMany()| (hence |Dispatcher::AddWaiter()|) was + // satisfied; + // - |MOJO_RESULT_CANCELLED| if a handle (on which + // |MojoWait()|/|MojoWaitMany()| was called) was closed (hence the + // dispatcher closed); and + // - |MOJO_RESULT_FAILED_PRECONDITION| if one of the set of flags passed to + // |MojoWait()|/|MojoWaitMany()| cannot or can no longer be satisfied by + // the corresponding handle (e.g., if the other end of a message or data + // pipe is closed). + MojoResult Wait(MojoDeadline deadline, uint32_t* context); - // Wake the waiter up with the given result (or no-op if it's been woken up - // already). - void Awake(uint32_t context, MojoResult result); + // Wake the waiter up with the given result and context (or no-op if it's been + // woken up already). + void Awake(MojoResult result, uint32_t context); private: base::ConditionVariable cv_; // Associated to |lock_|. @@ -54,11 +66,11 @@ class MOJO_SYSTEM_IMPL_EXPORT Waiter { bool initialized_; #endif bool awoken_; + MojoResult awake_result_; // This is a |uint32_t| because we really only need to store an index (for // |MojoWaitMany()|). But in tests, it's convenient to use this for other // purposes (e.g., to distinguish between different wake-up reasons). uint32_t awake_context_; - MojoResult awake_result_; DISALLOW_COPY_AND_ASSIGN(Waiter); }; diff --git a/mojo/system/waiter_list.cc b/mojo/system/waiter_list.cc index 1a54b0d..e286543 100644 --- a/mojo/system/waiter_list.cc +++ b/mojo/system/waiter_list.cc @@ -22,16 +22,16 @@ void WaiterList::AwakeWaitersForStateChange(const WaitFlagsState& state) { for (WaiterInfoList::iterator it = waiters_.begin(); it != waiters_.end(); ++it) { if (state.satisfies(it->flags)) - it->waiter->Awake(it->context, MOJO_RESULT_OK); + it->waiter->Awake(MOJO_RESULT_OK, it->context); else if (!state.can_satisfy(it->flags)) - it->waiter->Awake(it->context, MOJO_RESULT_FAILED_PRECONDITION); + it->waiter->Awake(MOJO_RESULT_FAILED_PRECONDITION, it->context); } } void WaiterList::CancelAllWaiters() { for (WaiterInfoList::iterator it = waiters_.begin(); it != waiters_.end(); ++it) { - it->waiter->Awake(it->context, MOJO_RESULT_CANCELLED); + it->waiter->Awake(MOJO_RESULT_CANCELLED, it->context); } waiters_.clear(); } diff --git a/mojo/system/waiter_list_unittest.cc b/mojo/system/waiter_list_unittest.cc index eb77681..8b9714b 100644 --- a/mojo/system/waiter_list_unittest.cc +++ b/mojo/system/waiter_list_unittest.cc @@ -23,61 +23,67 @@ namespace { TEST(WaiterListTest, BasicCancel) { MojoResult result; + uint32_t context; // Cancel immediately after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 1); thread.Start(); waiter_list.CancelAllWaiters(); waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. } // Join |thread|. EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(1u, context); // Cancel before after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 1); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 2); waiter_list.CancelAllWaiters(); thread.Start(); } // Join |thread|. EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(2u, context); // Cancel some time after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 2); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 3); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); waiter_list.CancelAllWaiters(); } // Join |thread|. EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(3u, context); } TEST(WaiterListTest, BasicAwakeSatisfied) { MojoResult result; + uint32_t context; // Awake immediately after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 1); thread.Start(); waiter_list.AwakeWaitersForStateChange( WaitFlagsState(MOJO_WAIT_FLAG_READABLE, MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE)); waiter_list.RemoveWaiter(thread.waiter()); } // Join |thread|. - EXPECT_EQ(0, result); + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(1u, context); // Awake before after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 1); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 2); waiter_list.AwakeWaitersForStateChange( WaitFlagsState(MOJO_WAIT_FLAG_WRITABLE, MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE)); @@ -85,13 +91,14 @@ TEST(WaiterListTest, BasicAwakeSatisfied) { waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. thread.Start(); } // Join |thread|. - EXPECT_EQ(1, result); + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(2u, context); // Awake some time after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 2); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 3); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); waiter_list.AwakeWaitersForStateChange( @@ -99,41 +106,45 @@ TEST(WaiterListTest, BasicAwakeSatisfied) { MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE)); waiter_list.RemoveWaiter(thread.waiter()); } // Join |thread|. - EXPECT_EQ(2, result); + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(3u, context); } TEST(WaiterListTest, BasicAwakeUnsatisfiable) { MojoResult result; + uint32_t context; // Awake (for unsatisfiability) immediately after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 1); thread.Start(); waiter_list.AwakeWaitersForStateChange( WaitFlagsState(MOJO_WAIT_FLAG_NONE, MOJO_WAIT_FLAG_WRITABLE)); waiter_list.RemoveWaiter(thread.waiter()); } // Join |thread|. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(1u, context); // Awake (for unsatisfiability) before after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 1); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 2); waiter_list.AwakeWaitersForStateChange( WaitFlagsState(MOJO_WAIT_FLAG_READABLE, MOJO_WAIT_FLAG_READABLE)); waiter_list.RemoveWaiter(thread.waiter()); thread.Start(); } // Join |thread|. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(2u, context); // Awake (for unsatisfiability) some time after thread start. { WaiterList waiter_list; - test::SimpleWaiterThread thread(&result); - waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 2); + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 3); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); waiter_list.AwakeWaitersForStateChange( @@ -142,6 +153,7 @@ TEST(WaiterListTest, BasicAwakeUnsatisfiable) { waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. } // Join |thread|. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(3u, context); } TEST(WaiterListTest, MultipleWaiters) { @@ -149,30 +161,36 @@ TEST(WaiterListTest, MultipleWaiters) { MojoResult result2; MojoResult result3; MojoResult result4; + uint32_t context1; + uint32_t context2; + uint32_t context3; + uint32_t context4; // Cancel two waiters. { WaiterList waiter_list; - test::SimpleWaiterThread thread1(&result1); - waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 0); + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 1); thread1.Start(); - test::SimpleWaiterThread thread2(&result2); - waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 1); + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 2); thread2.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); waiter_list.CancelAllWaiters(); } // Join threads. EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); + EXPECT_EQ(1u, context1); EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); + EXPECT_EQ(2u, context2); // Awake one waiter, cancel other. { WaiterList waiter_list; - test::SimpleWaiterThread thread1(&result1); - waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 2); + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 3); thread1.Start(); - test::SimpleWaiterThread thread2(&result2); - waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 3); + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 4); thread2.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); waiter_list.AwakeWaitersForStateChange( @@ -181,17 +199,19 @@ TEST(WaiterListTest, MultipleWaiters) { waiter_list.RemoveWaiter(thread1.waiter()); waiter_list.CancelAllWaiters(); } // Join threads. - EXPECT_EQ(2, result1); + EXPECT_EQ(MOJO_RESULT_OK, result1); + EXPECT_EQ(3u, context1); EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); + EXPECT_EQ(4u, context2); // Cancel one waiter, awake other for unsatisfiability. { WaiterList waiter_list; - test::SimpleWaiterThread thread1(&result1); - waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 4); + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 5); thread1.Start(); - test::SimpleWaiterThread thread2(&result2); - waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 5); + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 6); thread2.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); waiter_list.AwakeWaitersForStateChange( @@ -200,13 +220,15 @@ TEST(WaiterListTest, MultipleWaiters) { waiter_list.CancelAllWaiters(); } // Join threads. EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); + EXPECT_EQ(5u, context1); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); + EXPECT_EQ(6u, context2); // Cancel one waiter, awake other for unsatisfiability. { WaiterList waiter_list; - test::SimpleWaiterThread thread1(&result1); - waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 6); + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_WAIT_FLAG_READABLE, 7); thread1.Start(); base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); @@ -216,8 +238,8 @@ TEST(WaiterListTest, MultipleWaiters) { WaitFlagsState(MOJO_WAIT_FLAG_NONE, MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE)); - test::SimpleWaiterThread thread2(&result2); - waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 7); + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 8); thread2.Start(); base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); @@ -230,12 +252,12 @@ TEST(WaiterListTest, MultipleWaiters) { base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); - test::SimpleWaiterThread thread3(&result3); - waiter_list.AddWaiter(thread3.waiter(), MOJO_WAIT_FLAG_WRITABLE, 8); + test::SimpleWaiterThread thread3(&result3, &context3); + waiter_list.AddWaiter(thread3.waiter(), MOJO_WAIT_FLAG_WRITABLE, 9); thread3.Start(); - test::SimpleWaiterThread thread4(&result4); - waiter_list.AddWaiter(thread4.waiter(), MOJO_WAIT_FLAG_READABLE, 9); + test::SimpleWaiterThread thread4(&result4, &context4); + waiter_list.AddWaiter(thread4.waiter(), MOJO_WAIT_FLAG_READABLE, 10); thread4.Start(); base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); @@ -249,10 +271,14 @@ TEST(WaiterListTest, MultipleWaiters) { // Cancel #4. waiter_list.CancelAllWaiters(); } // Join threads. - EXPECT_EQ(6, result1); + EXPECT_EQ(MOJO_RESULT_OK, result1); + EXPECT_EQ(7u, context1); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); + EXPECT_EQ(8u, context2); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result3); + EXPECT_EQ(9u, context3); EXPECT_EQ(MOJO_RESULT_CANCELLED, result4); + EXPECT_EQ(10u, context4); } } // namespace diff --git a/mojo/system/waiter_test_utils.cc b/mojo/system/waiter_test_utils.cc index 94cd930..23c8e3e 100644 --- a/mojo/system/waiter_test_utils.cc +++ b/mojo/system/waiter_test_utils.cc @@ -8,11 +8,13 @@ namespace mojo { namespace system { namespace test { -SimpleWaiterThread::SimpleWaiterThread(MojoResult* result) +SimpleWaiterThread::SimpleWaiterThread(MojoResult* result, uint32_t* context) : base::SimpleThread("waiter_thread"), - result_(result) { + result_(result), + context_(context) { waiter_.Init(); *result_ = -5420734; // Totally invalid result. + *context_ = 23489023; // "Random". } SimpleWaiterThread::~SimpleWaiterThread() { @@ -20,7 +22,7 @@ SimpleWaiterThread::~SimpleWaiterThread() { } void SimpleWaiterThread::Run() { - *result_ = waiter_.Wait(MOJO_DEADLINE_INDEFINITE); + *result_ = waiter_.Wait(MOJO_DEADLINE_INDEFINITE, context_); } WaiterThread::WaiterThread(scoped_refptr<Dispatcher> dispatcher, @@ -28,16 +30,19 @@ WaiterThread::WaiterThread(scoped_refptr<Dispatcher> dispatcher, MojoDeadline deadline, uint32_t context, bool* did_wait_out, - MojoResult* result_out) + MojoResult* result_out, + uint32_t* context_out) : base::SimpleThread("waiter_thread"), dispatcher_(dispatcher), wait_flags_(wait_flags), deadline_(deadline), context_(context), did_wait_out_(did_wait_out), - result_out_(result_out) { + result_out_(result_out), + context_out_(context_out) { *did_wait_out_ = false; *result_out_ = -8542346; // Totally invalid result. + *context_out_ = 89023444; // "Random". } WaiterThread::~WaiterThread() { @@ -52,7 +57,7 @@ void WaiterThread::Run() { return; *did_wait_out_ = true; - *result_out_ = waiter_.Wait(deadline_); + *result_out_ = waiter_.Wait(deadline_, context_out_); dispatcher_->RemoveWaiter(&waiter_); } diff --git a/mojo/system/waiter_test_utils.h b/mojo/system/waiter_test_utils.h index d4f1fa1..26dd747 100644 --- a/mojo/system/waiter_test_utils.h +++ b/mojo/system/waiter_test_utils.h @@ -47,7 +47,7 @@ class SimpleWaiterThread : public base::SimpleThread { public: // For the duration of the lifetime of this object, |*result| belongs to it // (in the sense that it will write to it whenever it wants). - explicit SimpleWaiterThread(MojoResult* result); + SimpleWaiterThread(MojoResult* result, uint32_t* context); virtual ~SimpleWaiterThread(); // Joins the thread. Waiter* waiter() { return &waiter_; } @@ -56,6 +56,7 @@ class SimpleWaiterThread : public base::SimpleThread { virtual void Run() OVERRIDE; MojoResult* const result_; + uint32_t* const context_; Waiter waiter_; DISALLOW_COPY_AND_ASSIGN(SimpleWaiterThread); @@ -66,13 +67,15 @@ class SimpleWaiterThread : public base::SimpleThread { // |SimpleWaiterThread|, it requires the machinery of |Dispatcher|. class WaiterThread : public base::SimpleThread { public: - // Note: |*did_wait_out| and |*result| belong to this object while it's alive. + // Note: |*did_wait_out|, |*result_out|, and |*context_out| "belong" to this + // object (i.e., may be modified by, on some other thread) while it's alive. WaiterThread(scoped_refptr<Dispatcher> dispatcher, MojoWaitFlags wait_flags, MojoDeadline deadline, uint32_t context, bool* did_wait_out, - MojoResult* result_out); + MojoResult* result_out, + uint32_t* context_out); virtual ~WaiterThread(); private: @@ -84,6 +87,7 @@ class WaiterThread : public base::SimpleThread { const uint32_t context_; bool* const did_wait_out_; MojoResult* const result_out_; + uint32_t* const context_out_; Waiter waiter_; diff --git a/mojo/system/waiter_unittest.cc b/mojo/system/waiter_unittest.cc index 22237de..3afef28 100644 --- a/mojo/system/waiter_unittest.cc +++ b/mojo/system/waiter_unittest.cc @@ -31,7 +31,8 @@ class WaitingThread : public base::SimpleThread { : base::SimpleThread("waiting_thread"), deadline_(deadline), done_(false), - result_(MOJO_RESULT_UNKNOWN) { + result_(MOJO_RESULT_UNKNOWN), + context_(static_cast<uint32_t>(-1)) { waiter_.Init(); } @@ -39,12 +40,15 @@ class WaitingThread : public base::SimpleThread { Join(); } - void WaitUntilDone(MojoResult* result, base::TimeDelta* elapsed) { + void WaitUntilDone(MojoResult* result, + uint32_t* context, + base::TimeDelta* elapsed) { for (;;) { { base::AutoLock locker(lock_); if (done_) { *result = result_; + *context = context_; *elapsed = elapsed_; break; } @@ -61,16 +65,18 @@ class WaitingThread : public base::SimpleThread { virtual void Run() OVERRIDE { test::Stopwatch stopwatch; MojoResult result; + uint32_t context = static_cast<uint32_t>(-1); base::TimeDelta elapsed; stopwatch.Start(); - result = waiter_.Wait(deadline_); + result = waiter_.Wait(deadline_, &context); elapsed = stopwatch.Elapsed(); { base::AutoLock locker(lock_); done_ = true; result_ = result; + context_ = context; elapsed_ = elapsed; } } @@ -81,6 +87,7 @@ class WaitingThread : public base::SimpleThread { base::Lock lock_; // Protects the following members. bool done_; MojoResult result_; + uint32_t context_; base::TimeDelta elapsed_; DISALLOW_COPY_AND_ASSIGN(WaitingThread); @@ -88,6 +95,7 @@ class WaitingThread : public base::SimpleThread { TEST(WaiterTest, Basic) { MojoResult result; + uint32_t context; base::TimeDelta elapsed; // Finite deadline. @@ -96,19 +104,21 @@ TEST(WaiterTest, Basic) { { WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds()); thread.Start(); - thread.waiter()->Awake(0, MOJO_RESULT_OK); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(MOJO_RESULT_OK, 1); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(1u, context); EXPECT_LT(elapsed, test::EpsilonTimeout()); } // Awake before after thread start. { WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds()); - thread.waiter()->Awake(0, MOJO_RESULT_CANCELLED); + thread.waiter()->Awake(MOJO_RESULT_CANCELLED, 2); thread.Start(); - thread.WaitUntilDone(&result, &elapsed); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(2u, context); EXPECT_LT(elapsed, test::EpsilonTimeout()); } @@ -117,9 +127,10 @@ TEST(WaiterTest, Basic) { WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds()); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - thread.waiter()->Awake(0, 1); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(1, 3); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(1, result); + EXPECT_EQ(3u, context); EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); } @@ -129,9 +140,10 @@ TEST(WaiterTest, Basic) { WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds()); thread.Start(); base::PlatformThread::Sleep(5 * test::EpsilonTimeout()); - thread.waiter()->Awake(0, 1); - thread.WaitUntilDone(&result, &elapsed); - EXPECT_EQ(1, result); + thread.waiter()->Awake(2, 4); + thread.WaitUntilDone(&result, &context, &elapsed); + EXPECT_EQ(2, result); + EXPECT_EQ(4u, context); EXPECT_GT(elapsed, (5-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (5+1) * test::EpsilonTimeout()); } @@ -140,8 +152,9 @@ TEST(WaiterTest, Basic) { { WaitingThread thread(2 * test::EpsilonTimeout().InMicroseconds()); thread.Start(); - thread.WaitUntilDone(&result, &elapsed); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); + EXPECT_EQ(static_cast<uint32_t>(-1), context); EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); } @@ -152,19 +165,21 @@ TEST(WaiterTest, Basic) { { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); - thread.waiter()->Awake(0, MOJO_RESULT_OK); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(MOJO_RESULT_OK, 5); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(5u, context); EXPECT_LT(elapsed, test::EpsilonTimeout()); } // Awake before after thread start. { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); - thread.waiter()->Awake(0, MOJO_RESULT_CANCELLED); + thread.waiter()->Awake(MOJO_RESULT_CANCELLED, 6); thread.Start(); - thread.WaitUntilDone(&result, &elapsed); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(6u, context); EXPECT_LT(elapsed, test::EpsilonTimeout()); } @@ -173,9 +188,10 @@ TEST(WaiterTest, Basic) { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - thread.waiter()->Awake(0, 1); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(1, 7); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(1, result); + EXPECT_EQ(7u, context); EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); } @@ -185,9 +201,10 @@ TEST(WaiterTest, Basic) { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); base::PlatformThread::Sleep(5 * test::EpsilonTimeout()); - thread.waiter()->Awake(0, 1); - thread.WaitUntilDone(&result, &elapsed); - EXPECT_EQ(1, result); + thread.waiter()->Awake(2, 8); + thread.WaitUntilDone(&result, &context, &elapsed); + EXPECT_EQ(2, result); + EXPECT_EQ(8u, context); EXPECT_GT(elapsed, (5-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (5+1) * test::EpsilonTimeout()); } @@ -198,63 +215,71 @@ TEST(WaiterTest, TimeOut) { base::TimeDelta elapsed; Waiter waiter; + uint32_t context = 123; waiter.Init(); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, &context)); elapsed = stopwatch.Elapsed(); EXPECT_LT(elapsed, test::EpsilonTimeout()); + EXPECT_EQ(123u, context); waiter.Init(); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - waiter.Wait(2 * test::EpsilonTimeout().InMicroseconds())); + waiter.Wait(2 * test::EpsilonTimeout().InMicroseconds(), &context)); elapsed = stopwatch.Elapsed(); EXPECT_GT(elapsed, (2-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (2+1) * test::EpsilonTimeout()); + EXPECT_EQ(123u, context); waiter.Init(); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - waiter.Wait(5 * test::EpsilonTimeout().InMicroseconds())); + waiter.Wait(5 * test::EpsilonTimeout().InMicroseconds(), &context)); elapsed = stopwatch.Elapsed(); EXPECT_GT(elapsed, (5-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (5+1) * test::EpsilonTimeout()); + EXPECT_EQ(123u, context); } // The first |Awake()| should always win. TEST(WaiterTest, MultipleAwakes) { MojoResult result; + uint32_t context; base::TimeDelta elapsed; { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); - thread.waiter()->Awake(0, MOJO_RESULT_OK); - thread.waiter()->Awake(0, 1); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(MOJO_RESULT_OK, 1); + thread.waiter()->Awake(1, 2); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(1u, context); EXPECT_LT(elapsed, test::EpsilonTimeout()); } { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); - thread.waiter()->Awake(0, 1); + thread.waiter()->Awake(1, 3); thread.Start(); - thread.waiter()->Awake(0, MOJO_RESULT_OK); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(MOJO_RESULT_OK, 4); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(1, result); + EXPECT_EQ(3u, context); EXPECT_LT(elapsed, test::EpsilonTimeout()); } { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); - thread.waiter()->Awake(0, 10); + thread.waiter()->Awake(10, 5); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - thread.waiter()->Awake(0, 20); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(20, 6); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(10, result); + EXPECT_EQ(5u, context); EXPECT_LT(elapsed, test::EpsilonTimeout()); } @@ -262,11 +287,12 @@ TEST(WaiterTest, MultipleAwakes) { WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds()); thread.Start(); base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); - thread.waiter()->Awake(0, MOJO_RESULT_FAILED_PRECONDITION); + thread.waiter()->Awake(MOJO_RESULT_FAILED_PRECONDITION, 7); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - thread.waiter()->Awake(0, MOJO_RESULT_OK); - thread.WaitUntilDone(&result, &elapsed); + thread.waiter()->Awake(MOJO_RESULT_OK, 8); + thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(7u, context); EXPECT_GT(elapsed, (1-1) * test::EpsilonTimeout()); EXPECT_LT(elapsed, (1+1) * test::EpsilonTimeout()); } |