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 DISALLOW_COPY_AND_ASSIGN(CrossProcessNotification); |
| 170 }; |
| 171 |
| 172 #endif // MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_ |
OLD | NEW |