summaryrefslogtreecommitdiffstats
path: root/media/audio/cross_process_notification.h
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-28 13:49:17 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-28 13:49:17 +0000
commitc73f5ccd1b4b854bc9f7cf67f06d1bc1d101e350 (patch)
tree08cbf4345eec986a5f60961ed5de3089fa00de95 /media/audio/cross_process_notification.h
parent572a6ead297488e1cd9701ace544e8d499e45716 (diff)
downloadchromium_src-c73f5ccd1b4b854bc9f7cf67f06d1bc1d101e350.zip
chromium_src-c73f5ccd1b4b854bc9f7cf67f06d1bc1d101e350.tar.gz
chromium_src-c73f5ccd1b4b854bc9f7cf67f06d1bc1d101e350.tar.bz2
Add a CrossProcessNotification class.
This class will be used to synchronize multiple audio objects with minimal thread and IPC socket usage. TEST=Several tests included. Run media unittests. BUG=114699 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=129263 Review URL: https://chromiumcodereview.appspot.com/9605015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129405 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio/cross_process_notification.h')
-rw-r--r--media/audio/cross_process_notification.h172
1 files changed, 172 insertions, 0 deletions
diff --git a/media/audio/cross_process_notification.h b/media/audio/cross_process_notification.h
new file mode 100644
index 0000000..cae7435
--- /dev/null
+++ b/media/audio/cross_process_notification.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_
+#define MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "base/threading/non_thread_safe.h"
+#include "media/base/media_export.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#else
+#include "base/file_descriptor_posix.h"
+#include "base/sync_socket.h"
+#endif
+
+// A mechanism to synchronize access to a shared resource between two parties
+// when the usage pattern resembles that of two players playing a game of chess.
+// Each end has an instance of CrossProcessNotification and calls Signal() when
+// it has finished using the shared resource.
+// Before accessing the resource, it must call Wait() in order to know when the
+// other end has called Signal().
+//
+// Here's some pseudo code for how this class can be used:
+//
+// This method is used by both processes as it's a general way to use the
+// shared resource and then grant the privilege to the other process:
+//
+// void WriteToSharedMemory(CrossProcessNotification* notification,
+// SharedMemory* mem,
+// const char my_char) {
+// notification->Wait(); // Wait for the other process to yield access.
+// reinterpret_cast<char*>(mem->memory())[0] = my_char;
+// notification->Signal(); // Grant the other process access.
+// }
+//
+// Process A:
+//
+// class A {
+// public:
+// void Initialize(base::ProcessHandle process_b) {
+// mem_.CreateNamed("foo", false, 1024);
+//
+// CrossProcessNotification other;
+// CHECK(CrossProcessNotification::InitializePair(&notification_, &other));
+// CrossProcessNotification::IPCHandle handle_1, handle_2;
+// CHECK(other.ShareToProcess(process_b, &handle_1, &handle_2));
+// // This could be implemented by using some IPC mechanism
+// // such as MessageLoop.
+// SendToProcessB(mem_, handle_1, handle_2);
+// // Allow process B the first chance to write to the memory:
+// notification_.Signal();
+// // Once B is done, we'll write 'A' to the shared memory.
+// WriteToSharedMemory(&notification_, &mem_, 'A');
+// }
+//
+// CrossProcessNotification notification_;
+// SharedMemory mem_;
+// };
+//
+// Process B:
+//
+// class B {
+// public:
+// // Called when we receive the IPC message from A.
+// void Initialize(SharedMemoryHandle mem,
+// CrossProcessNotification::IPCHandle handle_1,
+// CrossProcessNotification::IPCHandle handle_2) {
+// mem_.reset(new SharedMemory(mem, false));
+// notification_.reset(new CrossProcessNotification(handle_1, handle_2));
+// WriteToSharedMemory(&notification_, &mem_, 'B');
+// }
+//
+// CrossProcessNotification notification_;
+// scoped_ptr<SharedMemory> mem_;
+// };
+//
+class MEDIA_EXPORT CrossProcessNotification {
+ public:
+#if defined(OS_WIN)
+ typedef HANDLE IPCHandle;
+#else
+ typedef base::FileDescriptor IPCHandle;
+#endif
+
+ typedef std::vector<CrossProcessNotification*> Notifications;
+
+ // Default ctor. Initializes a NULL notification. User must call
+ // InitializePair() to initialize the instance along with a connected one.
+ CrossProcessNotification();
+
+ // Ctor for the user that does not call InitializePair but instead receives
+ // handles from the one that did. These handles come from a call to
+ // ShareToProcess.
+ CrossProcessNotification(IPCHandle handle_1, IPCHandle handle_2);
+ ~CrossProcessNotification();
+
+ // Raises a signal that the shared resource now can be accessed by the other
+ // party.
+ // NOTE: Calling Signal() more than once without calling Wait() in between
+ // is not a supported scenario and will result in undefined behavior (and
+ // different depending on platform).
+ void Signal();
+
+ // Waits for the other party to finish using the shared resource.
+ // NOTE: As with Signal(), you must not call Wait() more than once without
+ // calling Signal() in between.
+ void Wait();
+
+ bool IsValid() const;
+
+ // Copies the internal handles to the output parameters, |handle_1| and
+ // |handle_2|. The operation can fail, so the caller must be prepared to
+ // handle that case.
+ bool ShareToProcess(base::ProcessHandle process, IPCHandle* handle_1,
+ IPCHandle* handle_2);
+
+ // Initializes a pair of CrossProcessNotification instances. Note that this
+ // can fail (e.g. due to EMFILE on Linux).
+ static bool InitializePair(CrossProcessNotification* a,
+ CrossProcessNotification* b);
+
+ // Use an instance of this class when you have to repeatedly wait for multiple
+ // notifications on the same thread. The class will store information about
+ // which notification was last signaled and try to distribute the signals so
+ // that all notifications get a chance to be processed in times of high load
+ // and a busy one won't starve the others.
+ // TODO(tommi): Support a way to abort the wait.
+ class MEDIA_EXPORT WaitForMultiple :
+ public NON_EXPORTED_BASE(base::NonThreadSafe) {
+ public:
+ // Caller must make sure that the lifetime of the array is greater than
+ // that of the WaitForMultiple instance.
+ explicit WaitForMultiple(const Notifications* notifications);
+
+ // Waits for any of the notifications to be signaled. Returns the 0 based
+ // index of a signaled notification.
+ int Wait();
+
+ // Call when the array changes. This should be called on the same thread
+ // as Wait() is called on and the array must never change while a Wait()
+ // is in progress.
+ void Reset(const Notifications* notifications);
+
+ private:
+ const Notifications* notifications_;
+ size_t wait_offset_;
+ };
+
+ private:
+ // Only called by the WaitForMultiple class. See documentation
+ // for WaitForMultiple and comments inside WaitMultiple for details.
+ static int WaitMultiple(const Notifications& notifications,
+ size_t wait_offset);
+
+#if defined(OS_WIN)
+ base::win::ScopedHandle mine_;
+ base::win::ScopedHandle other_;
+#else
+ typedef base::CancelableSyncSocket SocketClass;
+ SocketClass socket_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(CrossProcessNotification);
+};
+
+#endif // MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_