Chromium Code Reviews| 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 |