1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef MOJO_SYSTEM_DISPATCHER_H_
6 #define MOJO_SYSTEM_DISPATCHER_H_
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/synchronization/lock.h"
16 #include "mojo/public/system/core.h"
17 #include "mojo/system/system_impl_export.h"
24 class DispatcherTransport;
25 class LocalMessagePipeEndpoint;
26 class ProxyMessagePipeEndpoint;
32 // TODO(vtl): We need to declare it here so we can friend it. We define it
33 // inline below, but maybe it should be in a test-only file instead.
34 DispatcherTransport DispatcherTryStartTransport(Dispatcher* dispatcher);
38 // A |Dispatcher| implements Mojo primitives that are "attached" to a particular
39 // handle. This includes most (all?) primitives except for |MojoWait...()|. This
40 // object is thread-safe, with its state being protected by a single lock
41 // |lock_|, which is also made available to implementation subclasses (via the
43 class MOJO_SYSTEM_IMPL_EXPORT Dispatcher :
44 public base::RefCountedThreadSafe<Dispatcher> {
49 kTypeDataPipeProducer,
52 virtual Type GetType() const = 0;
54 // These methods implement the various primitives named |Mojo...()|. These
55 // take |lock_| and handle races with |Close()|. Then they call out to
56 // subclasses' |...ImplNoLock()| methods (still under |lock_|), which actually
57 // implement the primitives.
58 // NOTE(vtl): This puts a big lock around each dispatcher (i.e., handle), and
59 // prevents the various |...ImplNoLock()|s from releasing the lock as soon as
60 // possible. If this becomes an issue, we can rethink this.
63 // |transports| may be non-null if and only if there are handles to be
64 // written; not that |this| must not be in |transports|. On success, all the
65 // dispatchers in |transports| must have been moved to a closed state; on
66 // failure, they should remain in their original state.
67 MojoResult WriteMessage(const void* bytes,
69 std::vector<DispatcherTransport>* transports,
70 MojoWriteMessageFlags flags);
71 // |dispatchers| must be non-null but empty, if |num_dispatchers| is non-null
72 // and nonzero. On success, it will be set to the dispatchers to be received
73 // (and assigned handles) as part of the message.
74 MojoResult ReadMessage(
77 std::vector<scoped_refptr<Dispatcher> >* dispatchers,
78 uint32_t* num_dispatchers,
79 MojoReadMessageFlags flags);
80 MojoResult WriteData(const void* elements,
81 uint32_t* elements_num_bytes,
82 MojoWriteDataFlags flags);
83 MojoResult BeginWriteData(void** buffer,
84 uint32_t* buffer_num_bytes,
85 MojoWriteDataFlags flags);
86 MojoResult EndWriteData(uint32_t num_bytes_written);
87 MojoResult ReadData(void* elements,
89 MojoReadDataFlags flags);
90 MojoResult BeginReadData(const void** buffer,
91 uint32_t* buffer_num_bytes,
92 MojoReadDataFlags flags);
93 MojoResult EndReadData(uint32_t num_bytes_read);
95 // Adds a waiter to this dispatcher. The waiter will be woken up when this
96 // object changes state to satisfy |flags| with result |wake_result| (which
97 // must be >= 0, i.e., a success status). It will also be woken up when it
98 // becomes impossible for the object to ever satisfy |flags| with a suitable
102 // - |MOJO_RESULT_OK| if the waiter was added;
103 // - |MOJO_RESULT_ALREADY_EXISTS| if |flags| is already satisfied;
104 // - |MOJO_RESULT_INVALID_ARGUMENT| if the dispatcher has been closed; and
105 // - |MOJO_RESULT_FAILED_PRECONDITION| if it is not (or no longer) possible
106 // that |flags| will ever be satisfied.
107 MojoResult AddWaiter(Waiter* waiter,
109 MojoResult wake_result);
110 void RemoveWaiter(Waiter* waiter);
112 // A dispatcher must be put into a special state in order to be sent across a
113 // message pipe. Outside of tests, only |CoreImplAccess| is allowed to do
114 // this, since there are requirements on the handle table (see below).
116 // In this special state, only a restricted set of operations is allowed.
117 // These are the ones available as |DispatcherTransport| methods. Other
118 // |Dispatcher| methods must not be called until |DispatcherTransport::End()|
120 class CoreImplAccess {
122 friend class CoreImpl;
123 // Tests also need this, to avoid needing |CoreImpl|.
124 friend DispatcherTransport test::DispatcherTryStartTransport(Dispatcher*);
126 // This must be called under the handle table lock and only if the handle
127 // table entry is not marked busy. The caller must maintain a reference to
128 // |dispatcher| until |DispatcherTransport::End()| is called.
129 static DispatcherTransport TryStartTransport(Dispatcher* dispatcher);
135 friend class base::RefCountedThreadSafe<Dispatcher>;
136 virtual ~Dispatcher();
138 // These are to be overridden by subclasses (if necessary). They are called
139 // exactly once -- first |CancelAllWaitersNoLock()|, then |CloseImplNoLock()|,
140 // when the dispatcher is being closed. They are called under |lock_|.
141 virtual void CancelAllWaitersNoLock();
142 virtual void CloseImplNoLock();
143 virtual scoped_refptr<Dispatcher>
144 CreateEquivalentDispatcherAndCloseImplNoLock() = 0;
146 // These are to be overridden by subclasses (if necessary). They are never
147 // called after the dispatcher has been closed. They are called under |lock_|.
148 // See the descriptions of the methods without the "ImplNoLock" for more
150 virtual MojoResult WriteMessageImplNoLock(
153 std::vector<DispatcherTransport>* transports,
154 MojoWriteMessageFlags flags);
155 virtual MojoResult ReadMessageImplNoLock(
158 std::vector<scoped_refptr<Dispatcher> >* dispatchers,
159 uint32_t* num_dispatchers,
160 MojoReadMessageFlags flags);
161 virtual MojoResult WriteDataImplNoLock(const void* elements,
163 MojoWriteDataFlags flags);
164 virtual MojoResult BeginWriteDataImplNoLock(void** buffer,
165 uint32_t* buffer_num_bytes,
166 MojoWriteDataFlags flags);
167 virtual MojoResult EndWriteDataImplNoLock(uint32_t num_bytes_written);
168 virtual MojoResult ReadDataImplNoLock(void* elements,
170 MojoReadDataFlags flags);
171 virtual MojoResult BeginReadDataImplNoLock(const void** buffer,
172 uint32_t* buffer_num_bytes,
173 MojoReadDataFlags flags);
174 virtual MojoResult EndReadDataImplNoLock(uint32_t num_bytes_read);
175 virtual MojoResult AddWaiterImplNoLock(Waiter* waiter,
177 MojoResult wake_result);
178 virtual void RemoveWaiterImplNoLock(Waiter* waiter);
180 // Available to subclasses. (Note: Returns a non-const reference, just like
181 // |base::AutoLock|'s constructor takes a non-const reference.)
182 base::Lock& lock() const { return lock_; }
185 friend class DispatcherTransport;
187 // This should be overridden to return true if/when there's an ongoing
188 // operation (e.g., two-phase read/writes on data pipes) that should prevent a
189 // handle from being sent over a message pipe (with status "busy").
190 virtual bool IsBusyNoLock() const;
192 // Closes the dispatcher. This must be done under lock, and unlike |Close()|,
193 // the dispatcher must not be closed already. (This is the "equivalent" of
194 // |CreateEquivalentDispatcherAndCloseNoLock()|, for situations where the
195 // dispatcher must be disposed of instead of "transferred".)
198 // Creates an equivalent dispatcher -- representing the same resource as this
199 // dispatcher -- and close (i.e., disable) this dispatcher. I.e., this
200 // dispatcher will look as though it was closed, but the resource it
201 // represents will be assigned to the new dispatcher. This must be called
202 // under the dispatcher's lock.
203 scoped_refptr<Dispatcher> CreateEquivalentDispatcherAndCloseNoLock();
205 // This protects the following members as well as any state added by
207 mutable base::Lock lock_;
210 DISALLOW_COPY_AND_ASSIGN(Dispatcher);
213 // Wrapper around a |Dispatcher| pointer, while it's being processed to be
214 // passed in a message pipe. See the comment about |Dispatcher::CoreImplAccess|
217 // Note: This class is deliberately "thin" -- no more expensive than a
219 class MOJO_SYSTEM_IMPL_EXPORT DispatcherTransport {
221 DispatcherTransport() : dispatcher_(NULL) {}
225 Dispatcher::Type GetType() const { return dispatcher_->GetType(); }
226 bool IsBusy() const { return dispatcher_->IsBusyNoLock(); }
227 void Close() { dispatcher_->CloseNoLock(); }
228 scoped_refptr<Dispatcher> CreateEquivalentDispatcherAndClose() {
229 return dispatcher_->CreateEquivalentDispatcherAndCloseNoLock();
232 bool is_valid() const { return !!dispatcher_; }
235 Dispatcher* dispatcher() { return dispatcher_; }
238 friend class Dispatcher::CoreImplAccess;
240 explicit DispatcherTransport(Dispatcher* dispatcher)
241 : dispatcher_(dispatcher) {}
243 Dispatcher* dispatcher_;
245 // Copy and assign allowed.
250 inline DispatcherTransport DispatcherTryStartTransport(Dispatcher* dispatcher) {
251 return Dispatcher::CoreImplAccess::TryStartTransport(dispatcher);
256 } // namespace system
259 #endif // MOJO_SYSTEM_DISPATCHER_H_