OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_ | |
6 #define MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_ | |
7 | |
8 #include <vector> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/process.h" | |
12 #include "base/threading/non_thread_safe.h" | |
13 #include "media/base/media_export.h" | |
14 | |
15 #if defined(OS_WIN) | |
16 #include "base/win/scoped_handle.h" | |
17 #else | |
18 #include "base/file_descriptor_posix.h" | |
19 #include "base/sync_socket.h" | |
20 #endif | |
21 | |
22 // A mechanism to synchronize access to a shared resource between two parties | |
23 // when the usage pattern resembles that of two players playing a game of chess. | |
24 // Each end has an instance of CrossProcessNotification and calls Signal() when | |
25 // it has finished using the shared resource. | |
26 // Before accessing the resource, it must call Wait() in order to know when the | |
27 // other end has called Signal(). | |
28 // | |
29 // Here's some pseudo code for how this class can be used: | |
30 // | |
31 // This method is used by both processes as it's a general way to use the | |
32 // shared resource and then grant the privilege to the other process: | |
33 // | |
34 // void WriteToSharedMemory(CrossProcessNotification* notification, | |
35 // SharedMemory* mem, | |
36 // const char my_char) { | |
37 // notification->Wait(); // Wait for the other process to yield access. | |
38 // reinterpret_cast<char*>(mem->memory())[0] = my_char; | |
39 // notification->Signal(); // Grant the other process access. | |
40 // } | |
41 // | |
42 // Process A: | |
43 // | |
44 // class A { | |
45 // public: | |
46 // void Initialize(base::ProcessHandle process_b) { | |
47 // mem_.CreateNamed("foo", false, 1024); | |
48 // | |
49 // CrossProcessNotification other; | |
50 // CHECK(CrossProcessNotification::InitializePair(¬ification_, &other)); | |
51 // CrossProcessNotification::IPCHandle handle_1, handle_2; | |
52 // CHECK(other.ShareToProcess(process_b, &handle_1, &handle_2)); | |
53 // // This could be implemented by using some IPC mechanism | |
54 // // such as MessageLoop. | |
55 // SendToProcessB(mem_, handle_1, handle_2); | |
56 // // Allow process B the first chance to write to the memory: | |
57 // notification_.Signal(); | |
58 // // Once B is done, we'll write 'A' to the shared memory. | |
59 // WriteToSharedMemory(¬ification_, &mem_, 'A'); | |
60 // } | |
61 // | |
62 // CrossProcessNotification notification_; | |
63 // SharedMemory mem_; | |
64 // }; | |
65 // | |
66 // Process B: | |
67 // | |
68 // class B { | |
69 // public: | |
70 // // Called when we receive the IPC message from A. | |
71 // void Initialize(SharedMemoryHandle mem, | |
72 // CrossProcessNotification::IPCHandle handle_1, | |
73 // CrossProcessNotification::IPCHandle handle_2) { | |
74 // mem_.reset(new SharedMemory(mem, false)); | |
75 // notification_.reset(new CrossProcessNotification(handle_1, handle_2)); | |
76 // WriteToSharedMemory(¬ification_, &mem_, 'B'); | |
77 // } | |
78 // | |
79 // CrossProcessNotification notification_; | |
80 // scoped_ptr<SharedMemory> mem_; | |
81 // }; | |
82 // | |
83 class MEDIA_EXPORT CrossProcessNotification { | |
84 public: | |
85 #if defined(OS_WIN) | |
86 typedef HANDLE IPCHandle; | |
87 #else | |
88 typedef base::FileDescriptor IPCHandle; | |
89 #endif | |
90 | |
91 typedef std::vector<CrossProcessNotification*> Notifications; | |
92 | |
93 // Default ctor. Initializes a NULL notification. User must call | |
94 // InitializePair() to initialize the instance along with a connected one. | |
95 CrossProcessNotification(); | |
96 | |
97 // Ctor for the user that does not call InitializePair but instead receives | |
98 // handles from the one that did. These handles come from a call to | |
99 // ShareToProcess. | |
100 CrossProcessNotification(IPCHandle handle_1, IPCHandle handle_2); | |
101 ~CrossProcessNotification(); | |
102 | |
103 // Raises a signal that the shared resource now can be accessed by the other | |
104 // party. | |
105 // NOTE: Calling Signal() more than once without calling Wait() in between | |
106 // is not a supported scenario and will result in undefined behavior (and | |
107 // different depending on platform). | |
108 void Signal(); | |
109 | |
110 // Waits for the other party to finish using the shared resource. | |
111 // NOTE: As with Signal(), you must not call Wait() more than once without | |
112 // calling Signal() in between. | |
113 void Wait(); | |
114 | |
115 bool IsValid() const; | |
116 | |
117 // Copies the internal handles to the output parameters, |handle_1| and | |
118 // |handle_2|. The operation can fail, so the caller must be prepared to | |
119 // handle that case. | |
120 bool ShareToProcess(base::ProcessHandle process, IPCHandle* handle_1, | |
121 IPCHandle* handle_2); | |
122 | |
123 // Initializes a pair of CrossProcessNotification instances. Note that this | |
124 // can fail (e.g. due to EMFILE on Linux). | |
125 static bool InitializePair(CrossProcessNotification* a, | |
126 CrossProcessNotification* b); | |
127 | |
128 // Use an instance of this class when you have to repeatedly wait for multiple | |
129 // notifications on the same thread. The class will store information about | |
130 // which notification was last signaled and try to distribute the signals so | |
131 // that all notifications get a chance to be processed in times of high load | |
132 // and a busy one won't starve the others. | |
133 // TODO(tommi): Support a way to abort the wait. | |
134 class MEDIA_EXPORT WaitForMultiple : | |
135 public NON_EXPORTED_BASE(base::NonThreadSafe) { | |
136 public: | |
137 // Caller must make sure that the lifetime of the array is greater than | |
138 // that of the WaitForMultiple instance. | |
139 explicit WaitForMultiple(const Notifications* notifications); | |
140 | |
141 // Waits for any of the notifications to be signaled. Returns the 0 based | |
142 // index of a signaled notification. | |
143 int Wait(); | |
144 | |
145 // Call when the array changes. This should be called on the same thread | |
146 // as Wait() is called on and the array must never change while a Wait() | |
147 // is in progress. | |
148 void Reset(const Notifications* notifications); | |
149 | |
150 private: | |
151 const Notifications* notifications_; | |
152 size_t wait_offset_; | |
153 }; | |
154 | |
155 private: | |
156 // Only called by the WaitForMultiple class. See documentation | |
157 // for WaitForMultiple and comments inside WaitMultiple for details. | |
158 static int WaitMultiple(const Notifications& notifications, | |
159 size_t wait_offset); | |
160 | |
161 #if defined(OS_WIN) | |
162 base::win::ScopedHandle mine_; | |
163 base::win::ScopedHandle other_; | |
164 #else | |
165 typedef base::CancelableSyncSocket SocketClass; | |
166 SocketClass socket_; | |
167 #endif | |
168 | |
169 private: | |
scherkus (not reviewing)
2012/03/27 14:38:14
nit: remove duplicate private: section
| |
170 DISALLOW_COPY_AND_ASSIGN(CrossProcessNotification); | |
171 }; | |
172 | |
173 #endif // MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_ | |
OLD | NEW |