diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 16:31:16 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 16:31:16 +0000 |
commit | 22184780a9a695c2e9b1f5dc600598627ea32a33 (patch) | |
tree | 45f3e863cb98470f7ebc679261a1d9b1674b8441 /mojo | |
parent | b93e93b9f04ac8167e52211fe33a3e4b6d752030 (diff) | |
download | chromium_src-22184780a9a695c2e9b1f5dc600598627ea32a33.zip chromium_src-22184780a9a695c2e9b1f5dc600598627ea32a33.tar.gz chromium_src-22184780a9a695c2e9b1f5dc600598627ea32a33.tar.bz2 |
Mojo: Wrap the satisfied/unsatisfied wait flags state in a single object.
First, add a struct (MojoWaitFlagsState) to the public C API. We'll use
this to report additional (e.g., per-handle) information in
MojoWait()/MojoWaitMany().
Second, make a subclass struct (mojo::system::WaitFlagsState) that adds
a constructor and some simple methods for convenience (but adding no
overhead).
Third, convert our various separate handling of satisfied/satisfiable
state to use the new combined struct.
R=sky@chromium.org, darin@chromium.org
Review URL: https://codereview.chromium.org/325213004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276708 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/mojo.gyp | 1 | ||||
-rw-r--r-- | mojo/public/c/system/types.h | 13 | ||||
-rw-r--r-- | mojo/system/data_pipe.cc | 44 | ||||
-rw-r--r-- | mojo/system/data_pipe.h | 7 | ||||
-rw-r--r-- | mojo/system/local_data_pipe.cc | 41 | ||||
-rw-r--r-- | mojo/system/local_data_pipe.h | 6 | ||||
-rw-r--r-- | mojo/system/local_message_pipe_endpoint.cc | 54 | ||||
-rw-r--r-- | mojo/system/local_message_pipe_endpoint.h | 4 | ||||
-rw-r--r-- | mojo/system/platform_handle_dispatcher.cc | 8 | ||||
-rw-r--r-- | mojo/system/platform_handle_dispatcher.h | 5 | ||||
-rw-r--r-- | mojo/system/shared_buffer_dispatcher.cc | 9 | ||||
-rw-r--r-- | mojo/system/shared_buffer_dispatcher.h | 5 | ||||
-rw-r--r-- | mojo/system/simple_dispatcher.cc | 10 | ||||
-rw-r--r-- | mojo/system/simple_dispatcher.h | 18 | ||||
-rw-r--r-- | mojo/system/simple_dispatcher_unittest.cc | 40 | ||||
-rw-r--r-- | mojo/system/wait_flags_state.h | 48 | ||||
-rw-r--r-- | mojo/system/waiter_list.cc | 12 | ||||
-rw-r--r-- | mojo/system/waiter_list.h | 3 | ||||
-rw-r--r-- | mojo/system/waiter_list_unittest.cc | 53 |
19 files changed, 216 insertions, 165 deletions
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index ab0ef19..6bbe32f 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -216,6 +216,7 @@ 'system/simple_dispatcher.h', 'system/transport_data.cc', 'system/transport_data.h', + 'system/wait_flags_state.h', 'system/waiter.cc', 'system/waiter.h', 'system/waiter_list.cc', diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h index da4577a..655e302 100644 --- a/mojo/public/c/system/types.h +++ b/mojo/public/c/system/types.h @@ -12,6 +12,8 @@ #include <stdint.h> +#include "mojo/public/c/system/macros.h" + // TODO(vtl): Notes: Use of undefined flags will lead to undefined behavior // (typically they'll be ignored), not necessarily an error. @@ -162,4 +164,15 @@ const MojoWaitFlags MOJO_WAIT_FLAG_EVERYTHING = ~0; #define MOJO_WAIT_FLAG_EVERYTHING (~((MojoWaitFlags) 0)) #endif +// TODO(vtl): Add out parameters with this to MojoWait/MojoWaitMany. +// Note: This struct is not extensible (and only has 32-bit quantities), so it's +// 32-bit-aligned. +MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int32_t) == 4, int32_t_has_weird_alignment); +struct MOJO_ALIGNAS(4) MojoWaitFlagsState { + MojoWaitFlags satisfied_flags; + MojoWaitFlags satisfiable_flags; +}; +MOJO_COMPILE_ASSERT(sizeof(MojoWaitFlagsState) == 8, + MojoWaitFlagsState_has_wrong_size); + #endif // MOJO_PUBLIC_C_SYSTEM_TYPES_H_ diff --git a/mojo/system/data_pipe.cc b/mojo/system/data_pipe.cc index 7f05c04..2af15be 100644 --- a/mojo/system/data_pipe.cc +++ b/mojo/system/data_pipe.cc @@ -111,9 +111,10 @@ MojoResult DataPipe::ProducerWriteData(const void* elements, if (*num_bytes == 0) return MOJO_RESULT_OK; // Nothing to do. - MojoWaitFlags old_consumer_satisfied_flags = ConsumerSatisfiedFlagsNoLock(); + WaitFlagsState old_consumer_state = ConsumerGetWaitFlagsStateNoLock(); MojoResult rv = ProducerWriteDataImplNoLock(elements, num_bytes, all_or_none); - if (ConsumerSatisfiedFlagsNoLock() != old_consumer_satisfied_flags) + WaitFlagsState new_consumer_state = ConsumerGetWaitFlagsStateNoLock(); + if (!new_consumer_state.equals(old_consumer_state)) AwakeConsumerWaitersForStateChangeNoLock(); return rv; } @@ -153,7 +154,7 @@ MojoResult DataPipe::ProducerEndWriteData(uint32_t num_bytes_written) { // Note: Allow successful completion of the two-phase write even if the // consumer has been closed. - MojoWaitFlags old_consumer_satisfied_flags = ConsumerSatisfiedFlagsNoLock(); + WaitFlagsState old_consumer_state = ConsumerGetWaitFlagsStateNoLock(); MojoResult rv; if (num_bytes_written > producer_two_phase_max_num_bytes_written_ || num_bytes_written % element_num_bytes_ != 0) { @@ -166,9 +167,10 @@ MojoResult DataPipe::ProducerEndWriteData(uint32_t num_bytes_written) { DCHECK(!producer_in_two_phase_write_no_lock()); // If we're now writable, we *became* writable (since we weren't writable // during the two-phase write), so awake producer waiters. - if ((ProducerSatisfiedFlagsNoLock() & MOJO_WAIT_FLAG_WRITABLE)) + if (ProducerGetWaitFlagsStateNoLock().satisfies(MOJO_WAIT_FLAG_WRITABLE)) AwakeProducerWaitersForStateChangeNoLock(); - if (ConsumerSatisfiedFlagsNoLock() != old_consumer_satisfied_flags) + WaitFlagsState new_consumer_state = ConsumerGetWaitFlagsStateNoLock(); + if (!new_consumer_state.equals(old_consumer_state)) AwakeConsumerWaitersForStateChangeNoLock(); return rv; } @@ -179,9 +181,10 @@ MojoResult DataPipe::ProducerAddWaiter(Waiter* waiter, base::AutoLock locker(lock_); DCHECK(has_local_producer_no_lock()); - if ((flags & ProducerSatisfiedFlagsNoLock())) + WaitFlagsState producer_state = ProducerGetWaitFlagsStateNoLock(); + if (producer_state.satisfies(flags)) return MOJO_RESULT_ALREADY_EXISTS; - if (!(flags & ProducerSatisfiableFlagsNoLock())) + if (!producer_state.can_satisfy(flags)) return MOJO_RESULT_FAILED_PRECONDITION; producer_waiter_list_->AddWaiter(waiter, flags, wake_result); @@ -234,9 +237,10 @@ MojoResult DataPipe::ConsumerReadData(void* elements, if (*num_bytes == 0) return MOJO_RESULT_OK; // Nothing to do. - MojoWaitFlags old_producer_satisfied_flags = ProducerSatisfiedFlagsNoLock(); + WaitFlagsState old_producer_state = ProducerGetWaitFlagsStateNoLock(); MojoResult rv = ConsumerReadDataImplNoLock(elements, num_bytes, all_or_none); - if (ProducerSatisfiedFlagsNoLock() != old_producer_satisfied_flags) + WaitFlagsState new_producer_state = ProducerGetWaitFlagsStateNoLock(); + if (!new_producer_state.equals(old_producer_state)) AwakeProducerWaitersForStateChangeNoLock(); return rv; } @@ -255,9 +259,10 @@ MojoResult DataPipe::ConsumerDiscardData(uint32_t* num_bytes, if (*num_bytes == 0) return MOJO_RESULT_OK; // Nothing to do. - MojoWaitFlags old_producer_satisfied_flags = ProducerSatisfiedFlagsNoLock(); + WaitFlagsState old_producer_state = ProducerGetWaitFlagsStateNoLock(); MojoResult rv = ConsumerDiscardDataImplNoLock(num_bytes, all_or_none); - if (ProducerSatisfiedFlagsNoLock() != old_producer_satisfied_flags) + WaitFlagsState new_producer_state = ProducerGetWaitFlagsStateNoLock(); + if (!new_producer_state.equals(old_producer_state)) AwakeProducerWaitersForStateChangeNoLock(); return rv; } @@ -300,7 +305,7 @@ MojoResult DataPipe::ConsumerEndReadData(uint32_t num_bytes_read) { if (!consumer_in_two_phase_read_no_lock()) return MOJO_RESULT_FAILED_PRECONDITION; - MojoWaitFlags old_producer_satisfied_flags = ProducerSatisfiedFlagsNoLock(); + WaitFlagsState old_producer_state = ProducerGetWaitFlagsStateNoLock(); MojoResult rv; if (num_bytes_read > consumer_two_phase_max_num_bytes_read_ || num_bytes_read % element_num_bytes_ != 0) { @@ -313,9 +318,11 @@ MojoResult DataPipe::ConsumerEndReadData(uint32_t num_bytes_read) { DCHECK(!consumer_in_two_phase_read_no_lock()); // If we're now readable, we *became* readable (since we weren't readable // during the two-phase read), so awake consumer waiters. - if ((ConsumerSatisfiedFlagsNoLock() & MOJO_WAIT_FLAG_READABLE)) + WaitFlagsState new_consumer_state = ConsumerGetWaitFlagsStateNoLock(); + if (new_consumer_state.satisfies(MOJO_WAIT_FLAG_READABLE)) AwakeConsumerWaitersForStateChangeNoLock(); - if (ProducerSatisfiedFlagsNoLock() != old_producer_satisfied_flags) + WaitFlagsState new_producer_state = ProducerGetWaitFlagsStateNoLock(); + if (!new_producer_state.equals(old_producer_state)) AwakeProducerWaitersForStateChangeNoLock(); return rv; } @@ -326,9 +333,10 @@ MojoResult DataPipe::ConsumerAddWaiter(Waiter* waiter, base::AutoLock locker(lock_); DCHECK(has_local_consumer_no_lock()); - if ((flags & ConsumerSatisfiedFlagsNoLock())) + WaitFlagsState consumer_state = ConsumerGetWaitFlagsStateNoLock(); + if (consumer_state.satisfies(flags)) return MOJO_RESULT_ALREADY_EXISTS; - if (!(flags & ConsumerSatisfiableFlagsNoLock())) + if (!consumer_state.can_satisfy(flags)) return MOJO_RESULT_FAILED_PRECONDITION; consumer_waiter_list_->AddWaiter(waiter, flags, wake_result); @@ -377,7 +385,7 @@ void DataPipe::AwakeProducerWaitersForStateChangeNoLock() { if (!has_local_producer_no_lock()) return; producer_waiter_list_->AwakeWaitersForStateChange( - ProducerSatisfiedFlagsNoLock(), ProducerSatisfiableFlagsNoLock()); + ProducerGetWaitFlagsStateNoLock()); } void DataPipe::AwakeConsumerWaitersForStateChangeNoLock() { @@ -385,7 +393,7 @@ void DataPipe::AwakeConsumerWaitersForStateChangeNoLock() { if (!has_local_consumer_no_lock()) return; consumer_waiter_list_->AwakeWaitersForStateChange( - ConsumerSatisfiedFlagsNoLock(), ConsumerSatisfiableFlagsNoLock()); + ConsumerGetWaitFlagsStateNoLock()); } } // namespace system diff --git a/mojo/system/data_pipe.h b/mojo/system/data_pipe.h index a4a903b..a1d95ad 100644 --- a/mojo/system/data_pipe.h +++ b/mojo/system/data_pipe.h @@ -12,6 +12,7 @@ #include "mojo/public/c/system/data_pipe.h" #include "mojo/public/c/system/types.h" #include "mojo/system/system_impl_export.h" +#include "mojo/system/wait_flags_state.h" namespace mojo { namespace system { @@ -105,8 +106,7 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipe : virtual MojoResult ProducerEndWriteDataImplNoLock( uint32_t num_bytes_written) = 0; // Note: A producer should not be writable during a two-phase write. - virtual MojoWaitFlags ProducerSatisfiedFlagsNoLock() = 0; - virtual MojoWaitFlags ProducerSatisfiableFlagsNoLock() = 0; + virtual WaitFlagsState ProducerGetWaitFlagsStateNoLock() const = 0; virtual void ConsumerCloseImplNoLock() = 0; // |*num_bytes| will be a nonzero multiple of |element_num_bytes_|. @@ -122,8 +122,7 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipe : bool all_or_none) = 0; virtual MojoResult ConsumerEndReadDataImplNoLock(uint32_t num_bytes_read) = 0; // Note: A consumer should not be writable during a two-phase read. - virtual MojoWaitFlags ConsumerSatisfiedFlagsNoLock() = 0; - virtual MojoWaitFlags ConsumerSatisfiableFlagsNoLock() = 0; + virtual WaitFlagsState ConsumerGetWaitFlagsStateNoLock() const = 0; // Thread-safe and fast (they don't take the lock): bool may_discard() const { return may_discard_; } diff --git a/mojo/system/local_data_pipe.cc b/mojo/system/local_data_pipe.cc index 942e4be..d98ccf4 100644 --- a/mojo/system/local_data_pipe.cc +++ b/mojo/system/local_data_pipe.cc @@ -151,19 +151,14 @@ MojoResult LocalDataPipe::ProducerEndWriteDataImplNoLock( return MOJO_RESULT_OK; } -MojoWaitFlags LocalDataPipe::ProducerSatisfiedFlagsNoLock() { - MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; - if (consumer_open_no_lock() && - (may_discard() || current_num_bytes_ < capacity_num_bytes()) && - !producer_in_two_phase_write_no_lock()) - rv |= MOJO_WAIT_FLAG_WRITABLE; - return rv; -} - -MojoWaitFlags LocalDataPipe::ProducerSatisfiableFlagsNoLock() { - MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; - if (consumer_open_no_lock()) - rv |= MOJO_WAIT_FLAG_WRITABLE; +WaitFlagsState LocalDataPipe::ProducerGetWaitFlagsStateNoLock() const { + WaitFlagsState rv; + if (consumer_open_no_lock()) { + if ((may_discard() || current_num_bytes_ < capacity_num_bytes()) && + !producer_in_two_phase_write_no_lock()) + rv.satisfied_flags |= MOJO_WAIT_FLAG_WRITABLE; + rv.satisfiable_flags |= MOJO_WAIT_FLAG_WRITABLE; + } return rv; } @@ -278,17 +273,15 @@ MojoResult LocalDataPipe::ConsumerEndReadDataImplNoLock( return MOJO_RESULT_OK; } -MojoWaitFlags LocalDataPipe::ConsumerSatisfiedFlagsNoLock() { - MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; - if (current_num_bytes_ > 0 && !consumer_in_two_phase_read_no_lock()) - rv |= MOJO_WAIT_FLAG_READABLE; - return rv; -} - -MojoWaitFlags LocalDataPipe::ConsumerSatisfiableFlagsNoLock() { - MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; - if (current_num_bytes_ > 0 || producer_open_no_lock()) - rv |= MOJO_WAIT_FLAG_READABLE; +WaitFlagsState LocalDataPipe::ConsumerGetWaitFlagsStateNoLock() const { + WaitFlagsState rv; + if (current_num_bytes_ > 0) { + if (!consumer_in_two_phase_read_no_lock()) + rv.satisfied_flags |= MOJO_WAIT_FLAG_READABLE; + rv.satisfiable_flags |= MOJO_WAIT_FLAG_READABLE; + } else if (producer_open_no_lock()) { + rv.satisfiable_flags |= MOJO_WAIT_FLAG_READABLE; + } return rv; } diff --git a/mojo/system/local_data_pipe.h b/mojo/system/local_data_pipe.h index 973ab68..7eb0f5f 100644 --- a/mojo/system/local_data_pipe.h +++ b/mojo/system/local_data_pipe.h @@ -40,8 +40,7 @@ class MOJO_SYSTEM_IMPL_EXPORT LocalDataPipe : public DataPipe { bool all_or_none) OVERRIDE; virtual MojoResult ProducerEndWriteDataImplNoLock( uint32_t num_bytes_written) OVERRIDE; - virtual MojoWaitFlags ProducerSatisfiedFlagsNoLock() OVERRIDE; - virtual MojoWaitFlags ProducerSatisfiableFlagsNoLock() OVERRIDE; + virtual WaitFlagsState ProducerGetWaitFlagsStateNoLock() const OVERRIDE; virtual void ConsumerCloseImplNoLock() OVERRIDE; virtual MojoResult ConsumerReadDataImplNoLock(void* elements, uint32_t* num_bytes, @@ -54,8 +53,7 @@ class MOJO_SYSTEM_IMPL_EXPORT LocalDataPipe : public DataPipe { bool all_or_none) OVERRIDE; virtual MojoResult ConsumerEndReadDataImplNoLock( uint32_t num_bytes_read) OVERRIDE; - virtual MojoWaitFlags ConsumerSatisfiedFlagsNoLock() OVERRIDE; - virtual MojoWaitFlags ConsumerSatisfiableFlagsNoLock() OVERRIDE; + virtual WaitFlagsState ConsumerGetWaitFlagsStateNoLock() const OVERRIDE; void EnsureBufferNoLock(); void DestroyBufferNoLock(); diff --git a/mojo/system/local_message_pipe_endpoint.cc b/mojo/system/local_message_pipe_endpoint.cc index 606ffa9..e3deb32 100644 --- a/mojo/system/local_message_pipe_endpoint.cc +++ b/mojo/system/local_message_pipe_endpoint.cc @@ -31,17 +31,12 @@ bool LocalMessagePipeEndpoint::OnPeerClose() { DCHECK(is_open_); DCHECK(is_peer_open_); - MojoWaitFlags old_satisfied_flags = SatisfiedFlags(); - MojoWaitFlags old_satisfiable_flags = SatisfiableFlags(); + WaitFlagsState old_state = GetWaitFlagsState(); is_peer_open_ = false; - MojoWaitFlags new_satisfied_flags = SatisfiedFlags(); - MojoWaitFlags new_satisfiable_flags = SatisfiableFlags(); + WaitFlagsState new_state = GetWaitFlagsState(); - if (new_satisfied_flags != old_satisfied_flags || - new_satisfiable_flags != old_satisfiable_flags) { - waiter_list_.AwakeWaitersForStateChange(new_satisfied_flags, - new_satisfiable_flags); - } + if (!new_state.equals(old_state)) + waiter_list_.AwakeWaitersForStateChange(new_state); return true; } @@ -53,10 +48,8 @@ void LocalMessagePipeEndpoint::EnqueueMessage( bool was_empty = message_queue_.IsEmpty(); message_queue_.AddMessage(message.Pass()); - if (was_empty) { - waiter_list_.AwakeWaitersForStateChange(SatisfiedFlags(), - SatisfiableFlags()); - } + if (was_empty) + waiter_list_.AwakeWaitersForStateChange(GetWaitFlagsState()); } void LocalMessagePipeEndpoint::Close() { @@ -124,8 +117,7 @@ MojoResult LocalMessagePipeEndpoint::ReadMessage(void* bytes, if (message_queue_.IsEmpty()) { // It's currently not possible to wait for non-readability, but we should // do the state change anyway. - waiter_list_.AwakeWaitersForStateChange(SatisfiedFlags(), - SatisfiableFlags()); + waiter_list_.AwakeWaitersForStateChange(GetWaitFlagsState()); } } @@ -140,9 +132,10 @@ MojoResult LocalMessagePipeEndpoint::AddWaiter(Waiter* waiter, MojoResult wake_result) { DCHECK(is_open_); - if ((flags & SatisfiedFlags())) + WaitFlagsState state = GetWaitFlagsState(); + if (state.satisfies(flags)) return MOJO_RESULT_ALREADY_EXISTS; - if (!(flags & SatisfiableFlags())) + if (!state.can_satisfy(flags)) return MOJO_RESULT_FAILED_PRECONDITION; waiter_list_.AddWaiter(waiter, flags, wake_result); @@ -154,22 +147,17 @@ void LocalMessagePipeEndpoint::RemoveWaiter(Waiter* waiter) { waiter_list_.RemoveWaiter(waiter); } -MojoWaitFlags LocalMessagePipeEndpoint::SatisfiedFlags() { - MojoWaitFlags satisfied_flags = 0; - if (!message_queue_.IsEmpty()) - satisfied_flags |= MOJO_WAIT_FLAG_READABLE; - if (is_peer_open_) - satisfied_flags |= MOJO_WAIT_FLAG_WRITABLE; - return satisfied_flags; -} - -MojoWaitFlags LocalMessagePipeEndpoint::SatisfiableFlags() { - MojoWaitFlags satisfiable_flags = 0; - if (!message_queue_.IsEmpty() || is_peer_open_) - satisfiable_flags |= MOJO_WAIT_FLAG_READABLE; - if (is_peer_open_) - satisfiable_flags |= MOJO_WAIT_FLAG_WRITABLE; - return satisfiable_flags; +WaitFlagsState LocalMessagePipeEndpoint::GetWaitFlagsState() { + WaitFlagsState rv; + if (!message_queue_.IsEmpty()) { + rv.satisfied_flags |= MOJO_WAIT_FLAG_READABLE; + rv.satisfiable_flags |= MOJO_WAIT_FLAG_READABLE; + } + if (is_peer_open_) { + rv.satisfied_flags |= MOJO_WAIT_FLAG_WRITABLE; + rv.satisfiable_flags |= MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE; + } + return rv; } } // namespace system diff --git a/mojo/system/local_message_pipe_endpoint.h b/mojo/system/local_message_pipe_endpoint.h index fdc3211..89dca4e 100644 --- a/mojo/system/local_message_pipe_endpoint.h +++ b/mojo/system/local_message_pipe_endpoint.h @@ -10,6 +10,7 @@ #include "mojo/system/message_in_transit_queue.h" #include "mojo/system/message_pipe_endpoint.h" #include "mojo/system/system_impl_export.h" +#include "mojo/system/wait_flags_state.h" #include "mojo/system/waiter_list.h" namespace mojo { @@ -44,8 +45,7 @@ class MOJO_SYSTEM_IMPL_EXPORT LocalMessagePipeEndpoint MessageInTransitQueue* message_queue() { return &message_queue_; } private: - MojoWaitFlags SatisfiedFlags(); - MojoWaitFlags SatisfiableFlags(); + WaitFlagsState GetWaitFlagsState(); bool is_open_; bool is_peer_open_; diff --git a/mojo/system/platform_handle_dispatcher.cc b/mojo/system/platform_handle_dispatcher.cc index e9b8af0..294a548 100644 --- a/mojo/system/platform_handle_dispatcher.cc +++ b/mojo/system/platform_handle_dispatcher.cc @@ -114,12 +114,8 @@ bool PlatformHandleDispatcher::EndSerializeAndCloseImplNoLock( return true; } -MojoWaitFlags PlatformHandleDispatcher::SatisfiedFlagsNoLock() const { - return MOJO_WAIT_FLAG_NONE; -} - -MojoWaitFlags PlatformHandleDispatcher::SatisfiableFlagsNoLock() const { - return MOJO_WAIT_FLAG_NONE; +WaitFlagsState PlatformHandleDispatcher::GetWaitFlagsStateNoLock() const { + return WaitFlagsState(); } } // namespace system diff --git a/mojo/system/platform_handle_dispatcher.h b/mojo/system/platform_handle_dispatcher.h index 2bf4d19..2e61098 100644 --- a/mojo/system/platform_handle_dispatcher.h +++ b/mojo/system/platform_handle_dispatcher.h @@ -50,9 +50,8 @@ class MOJO_SYSTEM_IMPL_EXPORT PlatformHandleDispatcher size_t* actual_size, embedder::PlatformHandleVector* platform_handles) OVERRIDE; - // |SimpleDispatcher| methods: - virtual MojoWaitFlags SatisfiedFlagsNoLock() const OVERRIDE; - virtual MojoWaitFlags SatisfiableFlagsNoLock() const OVERRIDE; + // |SimpleDispatcher| method: + virtual WaitFlagsState GetWaitFlagsStateNoLock() const OVERRIDE; embedder::ScopedPlatformHandle platform_handle_; diff --git a/mojo/system/shared_buffer_dispatcher.cc b/mojo/system/shared_buffer_dispatcher.cc index 57f0b6e..4400b8a 100644 --- a/mojo/system/shared_buffer_dispatcher.cc +++ b/mojo/system/shared_buffer_dispatcher.cc @@ -263,14 +263,9 @@ bool SharedBufferDispatcher::EndSerializeAndCloseImplNoLock( return true; } -MojoWaitFlags SharedBufferDispatcher::SatisfiedFlagsNoLock() const { +WaitFlagsState SharedBufferDispatcher::GetWaitFlagsStateNoLock() const { // TODO(vtl): Add transferrable flag. - return MOJO_WAIT_FLAG_NONE; -} - -MojoWaitFlags SharedBufferDispatcher::SatisfiableFlagsNoLock() const { - // TODO(vtl): Add transferrable flag. - return MOJO_WAIT_FLAG_NONE; + return WaitFlagsState(); } } // namespace system diff --git a/mojo/system/shared_buffer_dispatcher.h b/mojo/system/shared_buffer_dispatcher.h index f7c4d1b..097bfa2 100644 --- a/mojo/system/shared_buffer_dispatcher.h +++ b/mojo/system/shared_buffer_dispatcher.h @@ -84,9 +84,8 @@ class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher : public SimpleDispatcher { size_t* actual_size, embedder::PlatformHandleVector* platform_handles) OVERRIDE; - // |SimpleDispatcher| methods: - virtual MojoWaitFlags SatisfiedFlagsNoLock() const OVERRIDE; - virtual MojoWaitFlags SatisfiableFlagsNoLock() const OVERRIDE; + // |SimpleDispatcher| method: + virtual WaitFlagsState GetWaitFlagsStateNoLock() const OVERRIDE; scoped_refptr<RawSharedBuffer> shared_buffer_; diff --git a/mojo/system/simple_dispatcher.cc b/mojo/system/simple_dispatcher.cc index ce2baef..717ac00 100644 --- a/mojo/system/simple_dispatcher.cc +++ b/mojo/system/simple_dispatcher.cc @@ -15,10 +15,9 @@ SimpleDispatcher::SimpleDispatcher() { SimpleDispatcher::~SimpleDispatcher() { } -void SimpleDispatcher::StateChangedNoLock() { +void SimpleDispatcher::WaitFlagsStateChangedNoLock() { lock().AssertAcquired(); - waiter_list_.AwakeWaitersForStateChange(SatisfiedFlagsNoLock(), - SatisfiableFlagsNoLock()); + waiter_list_.AwakeWaitersForStateChange(GetWaitFlagsStateNoLock()); } void SimpleDispatcher::CancelAllWaitersNoLock() { @@ -31,9 +30,10 @@ MojoResult SimpleDispatcher::AddWaiterImplNoLock(Waiter* waiter, MojoResult wake_result) { lock().AssertAcquired(); - if ((flags & SatisfiedFlagsNoLock())) + WaitFlagsState state(GetWaitFlagsStateNoLock()); + if (state.satisfies(flags)) return MOJO_RESULT_ALREADY_EXISTS; - if (!(flags & SatisfiableFlagsNoLock())) + if (!state.can_satisfy(flags)) return MOJO_RESULT_FAILED_PRECONDITION; waiter_list_.AddWaiter(waiter, flags, wake_result); diff --git a/mojo/system/simple_dispatcher.h b/mojo/system/simple_dispatcher.h index 15a64d5..8258c2a 100644 --- a/mojo/system/simple_dispatcher.h +++ b/mojo/system/simple_dispatcher.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "mojo/system/dispatcher.h" #include "mojo/system/system_impl_export.h" +#include "mojo/system/wait_flags_state.h" #include "mojo/system/waiter_list.h" namespace mojo { @@ -25,17 +26,12 @@ class MOJO_SYSTEM_IMPL_EXPORT SimpleDispatcher : public Dispatcher { virtual ~SimpleDispatcher(); // To be called by subclasses when the state changes (so - // |SatisfiedFlagsNoLock()| and |SatisfiableFlagsNoLock()| should be checked - // again). Must be called under lock. - void StateChangedNoLock(); - - // These should return the wait flags that are satisfied by the object's - // current state and those that may eventually be satisfied by this object's - // state, respectively. They should be overridden by subclasses to reflect - // their notion of state. They are never called after the dispatcher has been - // closed. They are called under |lock_|. - virtual MojoWaitFlags SatisfiedFlagsNoLock() const = 0; - virtual MojoWaitFlags SatisfiableFlagsNoLock() const = 0; + // |GetWaitFlagsStateNoLock()| should be checked again). Must be called under + // lock. + void WaitFlagsStateChangedNoLock(); + + // Never called after the dispatcher has been closed; called under |lock_|. + virtual WaitFlagsState GetWaitFlagsStateNoLock() const = 0; // |Dispatcher| protected methods: virtual void CancelAllWaitersNoLock() OVERRIDE; diff --git a/mojo/system/simple_dispatcher_unittest.cc b/mojo/system/simple_dispatcher_unittest.cc index 6f232693..26fc277 100644 --- a/mojo/system/simple_dispatcher_unittest.cc +++ b/mojo/system/simple_dispatcher_unittest.cc @@ -28,31 +28,36 @@ namespace { class MockSimpleDispatcher : public SimpleDispatcher { public: MockSimpleDispatcher() - : satisfied_flags_(MOJO_WAIT_FLAG_NONE), - satisfiable_flags_(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE) {} + : state_(MOJO_WAIT_FLAG_NONE, + MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE) {} void SetSatisfiedFlags(MojoWaitFlags new_satisfied_flags) { base::AutoLock locker(lock()); // Any new flags that are set should be satisfiable. - CHECK_EQ(new_satisfied_flags & ~satisfied_flags_, - new_satisfied_flags & ~satisfied_flags_ & satisfiable_flags_); + CHECK_EQ(new_satisfied_flags & ~state_.satisfied_flags, + new_satisfied_flags & ~state_.satisfied_flags & + state_.satisfiable_flags); - if (new_satisfied_flags == satisfied_flags_) + if (new_satisfied_flags == state_.satisfied_flags) return; - satisfied_flags_ = new_satisfied_flags; - StateChangedNoLock(); + state_.satisfied_flags = new_satisfied_flags; + WaitFlagsStateChangedNoLock(); } void SetSatisfiableFlags(MojoWaitFlags new_satisfiable_flags) { base::AutoLock locker(lock()); - if (new_satisfiable_flags == satisfiable_flags_) + // Satisfied implies satisfiable. + CHECK_EQ(new_satisfiable_flags & state_.satisfied_flags, + state_.satisfied_flags); + + if (new_satisfiable_flags == state_.satisfiable_flags) return; - satisfiable_flags_ = new_satisfiable_flags; - StateChangedNoLock(); + state_.satisfiable_flags = new_satisfiable_flags; + WaitFlagsStateChangedNoLock(); } virtual Type GetType() const OVERRIDE { @@ -66,25 +71,18 @@ class MockSimpleDispatcher : public SimpleDispatcher { virtual scoped_refptr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock() OVERRIDE { scoped_refptr<MockSimpleDispatcher> rv(new MockSimpleDispatcher()); - rv->satisfied_flags_ = satisfied_flags_; - rv->satisfiable_flags_ = satisfiable_flags_; + rv->state_ = state_; return scoped_refptr<Dispatcher>(rv.get()); } // |SimpleDispatcher| implementation: - virtual MojoWaitFlags SatisfiedFlagsNoLock() const OVERRIDE { - lock().AssertAcquired(); - return satisfied_flags_; - } - - virtual MojoWaitFlags SatisfiableFlagsNoLock() const OVERRIDE { + virtual WaitFlagsState GetWaitFlagsStateNoLock() const OVERRIDE { lock().AssertAcquired(); - return satisfiable_flags_; + return state_; } // Protected by |lock()|: - MojoWaitFlags satisfied_flags_; - MojoWaitFlags satisfiable_flags_; + WaitFlagsState state_; DISALLOW_COPY_AND_ASSIGN(MockSimpleDispatcher); }; diff --git a/mojo/system/wait_flags_state.h b/mojo/system/wait_flags_state.h new file mode 100644 index 0000000..aaddd0c --- /dev/null +++ b/mojo/system/wait_flags_state.h @@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_SYSTEM_WAIT_FLAGS_STATE_H_ +#define MOJO_SYSTEM_WAIT_FLAGS_STATE_H_ + +#include "base/macros.h" +#include "mojo/public/c/system/types.h" +#include "mojo/system/system_impl_export.h" + +namespace mojo { +namespace system { + +// Just "add" some constructors and methods to the C struct |MojoWaitFlagsState| +// (for convenience). This should add no overhead. +struct MOJO_SYSTEM_IMPL_EXPORT WaitFlagsState : public MojoWaitFlagsState { + WaitFlagsState() { + satisfied_flags = MOJO_WAIT_FLAG_NONE; + satisfiable_flags = MOJO_WAIT_FLAG_NONE; + } + WaitFlagsState(MojoWaitFlags satisfied, MojoWaitFlags satisfiable) { + satisfied_flags = satisfied; + satisfiable_flags = satisfiable; + } + + bool equals(const WaitFlagsState& other) const { + return satisfied_flags == other.satisfied_flags && + satisfiable_flags == other.satisfiable_flags; + } + + bool satisfies(MojoWaitFlags flags) const { + return !!(satisfied_flags & flags); + } + + bool can_satisfy(MojoWaitFlags flags) const { + return !!(satisfiable_flags & flags); + } + + // (Copy and assignment allowed.) +}; +COMPILE_ASSERT(sizeof(WaitFlagsState) == sizeof(MojoWaitFlagsState), + WaitFlagsState_should_add_no_overhead); + +} // namespace system +} // namespace mojo + +#endif // MOJO_SYSTEM_WAIT_FLAGS_STATE_H_ diff --git a/mojo/system/waiter_list.cc b/mojo/system/waiter_list.cc index 6f2c444..c398c84 100644 --- a/mojo/system/waiter_list.cc +++ b/mojo/system/waiter_list.cc @@ -5,6 +5,7 @@ #include "mojo/system/waiter_list.h" #include "base/logging.h" +#include "mojo/system/wait_flags_state.h" #include "mojo/system/waiter.h" namespace mojo { @@ -17,6 +18,17 @@ WaiterList::~WaiterList() { DCHECK(waiters_.empty()); } +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->wake_result); + else if (!state.can_satisfy(it->flags)) + it->waiter->Awake(MOJO_RESULT_FAILED_PRECONDITION); + } +} + +//FIXME Remove: void WaiterList::AwakeWaitersForStateChange(MojoWaitFlags satisfied_flags, MojoWaitFlags satisfiable_flags) { for (WaiterInfoList::iterator it = waiters_.begin(); it != waiters_.end(); diff --git a/mojo/system/waiter_list.h b/mojo/system/waiter_list.h index 7266e2c..105717e 100644 --- a/mojo/system/waiter_list.h +++ b/mojo/system/waiter_list.h @@ -15,6 +15,7 @@ namespace mojo { namespace system { class Waiter; +struct WaitFlagsState; // |WaiterList| tracks all the |Waiter|s that are waiting on a given // handle/|Dispatcher|. There should be a |WaiterList| for each handle that can @@ -28,6 +29,8 @@ class MOJO_SYSTEM_IMPL_EXPORT WaiterList { WaiterList(); ~WaiterList(); + void AwakeWaitersForStateChange(const WaitFlagsState& state); +//FIXME Remove: void AwakeWaitersForStateChange(MojoWaitFlags satisfied_flags, MojoWaitFlags satisfiable_flags); void CancelAllWaiters(); diff --git a/mojo/system/waiter_list_unittest.cc b/mojo/system/waiter_list_unittest.cc index 9eeb4e7..eb77681 100644 --- a/mojo/system/waiter_list_unittest.cc +++ b/mojo/system/waiter_list_unittest.cc @@ -12,6 +12,7 @@ #include "base/threading/platform_thread.h" // For |Sleep()|. #include "base/time/time.h" #include "mojo/system/test_utils.h" +#include "mojo/system/wait_flags_state.h" #include "mojo/system/waiter.h" #include "mojo/system/waiter_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -65,9 +66,9 @@ TEST(WaiterListTest, BasicAwakeSatisfied) { test::SimpleWaiterThread thread(&result); waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0); thread.Start(); - waiter_list.AwakeWaitersForStateChange(MOJO_WAIT_FLAG_READABLE, - MOJO_WAIT_FLAG_READABLE | - MOJO_WAIT_FLAG_WRITABLE); + 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); @@ -77,9 +78,9 @@ TEST(WaiterListTest, BasicAwakeSatisfied) { WaiterList waiter_list; test::SimpleWaiterThread thread(&result); waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 1); - waiter_list.AwakeWaitersForStateChange(MOJO_WAIT_FLAG_WRITABLE, - MOJO_WAIT_FLAG_READABLE | - MOJO_WAIT_FLAG_WRITABLE); + waiter_list.AwakeWaitersForStateChange( + WaitFlagsState(MOJO_WAIT_FLAG_WRITABLE, + MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE)); waiter_list.RemoveWaiter(thread.waiter()); waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. thread.Start(); @@ -93,9 +94,9 @@ TEST(WaiterListTest, BasicAwakeSatisfied) { waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 2); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - waiter_list.AwakeWaitersForStateChange(MOJO_WAIT_FLAG_READABLE, - MOJO_WAIT_FLAG_READABLE | - MOJO_WAIT_FLAG_WRITABLE); + 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(2, result); @@ -110,7 +111,8 @@ TEST(WaiterListTest, BasicAwakeUnsatisfiable) { test::SimpleWaiterThread thread(&result); waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 0); thread.Start(); - waiter_list.AwakeWaitersForStateChange(0, MOJO_WAIT_FLAG_WRITABLE); + 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); @@ -120,8 +122,8 @@ TEST(WaiterListTest, BasicAwakeUnsatisfiable) { WaiterList waiter_list; test::SimpleWaiterThread thread(&result); waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_WRITABLE, 1); - waiter_list.AwakeWaitersForStateChange(MOJO_WAIT_FLAG_READABLE, - MOJO_WAIT_FLAG_READABLE); + waiter_list.AwakeWaitersForStateChange( + WaitFlagsState(MOJO_WAIT_FLAG_READABLE, MOJO_WAIT_FLAG_READABLE)); waiter_list.RemoveWaiter(thread.waiter()); thread.Start(); } // Join |thread|. @@ -134,7 +136,8 @@ TEST(WaiterListTest, BasicAwakeUnsatisfiable) { waiter_list.AddWaiter(thread.waiter(), MOJO_WAIT_FLAG_READABLE, 2); thread.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - waiter_list.AwakeWaitersForStateChange(0, MOJO_WAIT_FLAG_WRITABLE); + waiter_list.AwakeWaitersForStateChange( + WaitFlagsState(MOJO_WAIT_FLAG_NONE, MOJO_WAIT_FLAG_WRITABLE)); waiter_list.RemoveWaiter(thread.waiter()); waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. } // Join |thread|. @@ -172,9 +175,9 @@ TEST(WaiterListTest, MultipleWaiters) { waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 3); thread2.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - waiter_list.AwakeWaitersForStateChange(MOJO_WAIT_FLAG_READABLE, - MOJO_WAIT_FLAG_READABLE | - MOJO_WAIT_FLAG_WRITABLE); + waiter_list.AwakeWaitersForStateChange( + WaitFlagsState(MOJO_WAIT_FLAG_READABLE, + MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE)); waiter_list.RemoveWaiter(thread1.waiter()); waiter_list.CancelAllWaiters(); } // Join threads. @@ -191,7 +194,8 @@ TEST(WaiterListTest, MultipleWaiters) { waiter_list.AddWaiter(thread2.waiter(), MOJO_WAIT_FLAG_WRITABLE, 5); thread2.Start(); base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); - waiter_list.AwakeWaitersForStateChange(0, MOJO_WAIT_FLAG_READABLE); + waiter_list.AwakeWaitersForStateChange( + WaitFlagsState(MOJO_WAIT_FLAG_NONE, MOJO_WAIT_FLAG_READABLE)); waiter_list.RemoveWaiter(thread2.waiter()); waiter_list.CancelAllWaiters(); } // Join threads. @@ -208,9 +212,9 @@ TEST(WaiterListTest, MultipleWaiters) { base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); // Should do nothing. - waiter_list.AwakeWaitersForStateChange(0, - MOJO_WAIT_FLAG_READABLE | - MOJO_WAIT_FLAG_WRITABLE); + waiter_list.AwakeWaitersForStateChange( + 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); @@ -219,9 +223,9 @@ TEST(WaiterListTest, MultipleWaiters) { base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); // Awake #1. - waiter_list.AwakeWaitersForStateChange(MOJO_WAIT_FLAG_READABLE, - MOJO_WAIT_FLAG_READABLE | - MOJO_WAIT_FLAG_WRITABLE); + waiter_list.AwakeWaitersForStateChange( + WaitFlagsState(MOJO_WAIT_FLAG_READABLE, + MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE)); waiter_list.RemoveWaiter(thread1.waiter()); base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); @@ -237,7 +241,8 @@ TEST(WaiterListTest, MultipleWaiters) { base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); // Awake #2 and #3 for unsatisfiability. - waiter_list.AwakeWaitersForStateChange(0, MOJO_WAIT_FLAG_READABLE); + waiter_list.AwakeWaitersForStateChange( + WaitFlagsState(MOJO_WAIT_FLAG_NONE, MOJO_WAIT_FLAG_READABLE)); waiter_list.RemoveWaiter(thread2.waiter()); waiter_list.RemoveWaiter(thread3.waiter()); |