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