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_SHARED_MEM_SYNCHRONIZER_H_ | |
6 #define MEDIA_AUDIO_SHARED_MEM_SYNCHRONIZER_H_ | |
7 | |
8 #include <vector> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/process.h" | |
12 #include "media/base/media_export.h" | |
13 | |
14 #if defined(OS_WIN) | |
15 #include "base/win/scoped_handle.h" | |
16 #else | |
17 #include "base/file_descriptor_posix.h" | |
18 #include "base/sync_socket.h" | |
19 #endif | |
20 | |
21 // A mechanism to synchronize access to a shared memory segment between | |
22 // two parties when the usage pattern resembles that of two players playing | |
23 // a game of chess. Each end has an instance of SharedMemSynchronizer and | |
24 // calls Signal() when it has finished reading from/writing to the shared | |
25 // memory section. Before accessing the memory, it must call Wait() in order | |
26 // to know when the other end has called Signal(). | |
27 // | |
28 // Here's some pseudo code for how this class can be used: | |
29 // | |
30 // This method is used by both processes as it's a general way to access the | |
31 // shared memory section, write to it and then grant the privilege to the | |
32 // other process: | |
33 // | |
34 // void WriteToSharedMemory(SharedMemSynchronizer* synchronizer, | |
35 // SharedMemory* mem, | |
36 // const char my_char) { | |
37 // synchronizer->Wait(); // Wait for the other process to yield access. | |
38 // reinterpret_cast<char*>(mem->memory())[0] = my_char; | |
39 // synchronizer->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 // SharedMemSynchronizer b; | |
50 // CHECK(SharedMemSynchronizer::InitializePair(&synchronizer_, &b)); | |
51 // SharedMemSynchronizer::IPCHandle handle_1, handle_2; | |
52 // CHECK(b.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 // synchronizer_.Signal(); | |
58 // // Once B is done, we'll write 'A' to the shared memory. | |
59 // WriteToSharedMemory(&synchronizer_, &mem_, 'A'); | |
60 // } | |
61 // | |
62 // SharedMemSynchronizer synchronizer_; | |
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 // SharedMemSynchronizer::IPCHandle handle_1, | |
73 // SharedMemSynchronizer::IPCHandle handle_2) { | |
74 // mem_.reset(new SharedMemory(mem, false)); | |
75 // synchronizer_.reset(new SharedMemSynchronizer(handle_1, handle_2)); | |
76 // WriteToSharedMemory(&synchronizer_, &mem_, 'B'); | |
77 // } | |
78 // | |
79 // SharedMemSynchronizer synchronizer_; | |
80 // scoped_ptr<SharedMemory> mem_; | |
81 // }; | |
82 // | |
83 class MEDIA_EXPORT SharedMemSynchronizer { | |
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<SharedMemSynchronizer*> SynchronizerVector; | |
92 | |
93 // Default ctor. Initializes a NULL synchronizer. User must call | |
94 // InitializePair() to initialize the instance along with a connected one. | |
95 SharedMemSynchronizer(); | |
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 SharedMemSynchronizer(IPCHandle handle_1, IPCHandle handle_2); | |
101 ~SharedMemSynchronizer(); | |
102 | |
103 // Raises a signal that the shared memory now can be accessed by the | |
104 // other party. | |
105 void Signal(); | |
Ami GONE FROM CHROMIUM
2012/03/13 20:08:02
My point about blocking was that if a single synch
tommi (sloooow) - chröme
2012/03/14 13:32:43
Thanks. I added documentation to make that clear.
| |
106 | |
107 // Waits for the other party to finish using the shared memory. | |
108 void Wait(); | |
109 | |
110 bool IsValid() const; | |
111 | |
112 // Copies the internal handles to the output parameters, |handle_1| and | |
113 // |handle_2|. The operation can fail, so the caller must be prepared to | |
114 // handle that case. | |
115 bool ShareToProcess(base::ProcessHandle process, IPCHandle* handle_1, | |
116 IPCHandle* handle_2); | |
117 | |
118 // Initializes a pair of SharedMemSynchronizer instances. Note that this can | |
119 // fail (e.g. due to EMFILE on Linux), so the caller must handle that case. | |
120 static bool InitializePair(SharedMemSynchronizer* a, | |
121 SharedMemSynchronizer* b); | |
122 | |
123 // Use an instance of this class when you have to repeatedly wait | |
124 // for multiple instances of SharedMemSynchronizer on the same thread. | |
125 // The class will store information about which synchronizer was last signaled | |
126 // and try to distribute the signals so that all synchronizers get a chance to | |
127 // be processed in times of high load and a busy one won't starve the | |
128 // others. | |
129 // TODO(tommi): Support a way to abort the wait. | |
130 class MEDIA_EXPORT WaitForMultiple { | |
131 public: | |
132 // Caller must make sure that the lifetime of the array is greater than | |
133 // that of the WaitForMultiple instance. | |
134 WaitForMultiple(const SynchronizerVector* synchronizers); | |
135 | |
136 // Waits for any of the synchronizers to be signaled. Returns the 0 based | |
137 // index of a signaled synchronizer. | |
138 int Wait(); | |
139 | |
140 // Call when the array changes. | |
Ami GONE FROM CHROMIUM
2012/03/13 20:08:02
Doco the effect on outstanding Wait()'s?
(namely,
tommi (sloooow) - chröme
2012/03/14 13:32:43
Done.
| |
141 void Reset(const SynchronizerVector* synchronizers); | |
142 | |
143 private: | |
144 const SynchronizerVector* synchronizers_; | |
145 size_t last_; | |
146 }; | |
147 | |
148 private: | |
149 // Only called by the WaitForMultiple class. See documentation | |
150 // for WaitForMultiple and comments inside WaitMultiple for details. | |
151 static int WaitMultiple(const SynchronizerVector& synchronizers, | |
152 size_t last_signaled); | |
153 | |
154 #if defined(OS_WIN) | |
155 base::win::ScopedHandle mine_; | |
156 base::win::ScopedHandle other_; | |
157 #else | |
158 typedef base::CancelableSyncSocket SocketClass; | |
159 SocketClass socket_; | |
160 #endif | |
161 | |
162 private: | |
163 DISALLOW_COPY_AND_ASSIGN(SharedMemSynchronizer); | |
164 }; | |
165 | |
166 #endif // MEDIA_AUDIO_SHARED_MEM_SYNCHRONIZER_H_ | |
OLD | NEW |