| Index: media/audio/cross_process_notification.h
|
| diff --git a/media/audio/cross_process_notification.h b/media/audio/cross_process_notification.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cae74355a7b74bf5a9148294d5c5a59622cfef68
|
| --- /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(¬ification_, &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(¬ification_, &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(¬ification_, &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_
|
|
|