summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/atomic_ref_count.h10
-rw-r--r--base/base_lib.scons4
-rw-r--r--base/base_unittests.scons1
-rw-r--r--base/build/base.vcproj8
-rw-r--r--base/waitable_event.h87
-rw-r--r--base/waitable_event_generic.cc71
-rw-r--r--base/waitable_event_posix.cc392
-rw-r--r--base/waitable_event_unittest.cc55
-rw-r--r--base/waitable_event_watcher.h148
-rw-r--r--base/waitable_event_watcher_posix.cc253
-rw-r--r--base/waitable_event_watcher_unittest.cc136
-rw-r--r--base/waitable_event_watcher_win.cc60
-rw-r--r--base/waitable_event_win.cc40
-rw-r--r--chrome/browser/browser_process.h5
-rw-r--r--chrome/browser/browser_process_impl.cc3
-rw-r--r--chrome/browser/browser_process_impl.h4
-rw-r--r--chrome/browser/browser_shutdown.cc3
-rw-r--r--chrome/browser/render_view_host.cc26
-rw-r--r--chrome/browser/render_view_host.h12
-rw-r--r--chrome/browser/render_view_host_delegate.h9
-rw-r--r--chrome/browser/render_view_host_manager.cc10
-rw-r--r--chrome/browser/render_view_host_manager.h4
-rw-r--r--chrome/browser/tab_contents/web_contents.cc2
-rw-r--r--chrome/browser/tab_contents/web_contents.h6
-rw-r--r--chrome/browser/tab_contents/web_contents_unittest.cc6
-rw-r--r--chrome/browser/tab_contents/web_contents_view.cc3
-rw-r--r--chrome/browser/tab_contents/web_contents_view.h11
-rw-r--r--chrome/browser/tab_contents/web_contents_view_win.cc2
-rw-r--r--chrome/browser/tab_contents/web_contents_view_win.h2
-rw-r--r--chrome/common/child_process.cc11
-rw-r--r--chrome/common/child_process.h7
-rw-r--r--chrome/common/common.scons2
-rw-r--r--chrome/common/ipc_logging.h7
-rw-r--r--chrome/common/ipc_message.h3
-rw-r--r--chrome/common/ipc_sync_channel.cc94
-rw-r--r--chrome/common/ipc_sync_channel.h42
-rw-r--r--chrome/common/ipc_sync_message.cc12
-rw-r--r--chrome/common/ipc_sync_message.h21
-rw-r--r--chrome/plugin/npobject_proxy.cc11
-rw-r--r--chrome/plugin/npobject_proxy.h11
-rw-r--r--chrome/plugin/npobject_util.cc2
-rw-r--r--chrome/plugin/npobject_util.h5
-rw-r--r--chrome/plugin/webplugin_proxy.cc12
-rw-r--r--chrome/plugin/webplugin_proxy.h7
-rw-r--r--chrome/renderer/render_thread.cc4
-rw-r--r--chrome/renderer/render_view.cc18
-rw-r--r--chrome/renderer/render_view.h14
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc6
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h6
-rw-r--r--chrome/test/testing_browser_process.h16
50 files changed, 1418 insertions, 266 deletions
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
index af83572..66fe07b 100644
--- a/base/atomic_ref_count.h
+++ b/base/atomic_ref_count.h
@@ -13,12 +13,12 @@
namespace base {
-typedef base::subtle::Atomic32 AtomicRefCount;
+typedef subtle::Atomic32 AtomicRefCount;
// Increment a reference count by "increment", which must exceed 0.
inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
AtomicRefCount increment) {
- base::subtle::NoBarrier_AtomicIncrement(ptr, increment);
+ subtle::NoBarrier_AtomicIncrement(ptr, increment);
}
// Decrement a reference count by "decrement", which must exceed 0,
@@ -27,7 +27,7 @@ inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
// became zero will be visible to a thread that has just made the count zero.
inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
AtomicRefCount decrement) {
- return base::subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0;
+ return subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0;
}
// Increment a reference count by 1.
@@ -49,14 +49,14 @@ inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
// needed for the owning thread to act on the object, knowing that it has
// exclusive access to the object.
inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
- return base::subtle::Acquire_Load(ptr) == 1;
+ return subtle::Acquire_Load(ptr) == 1;
}
// Return whether the reference count is zero. With conventional object
// referencing counting, the object will be destroyed, so the reference count
// should never be zero. Hence this is generally used for a debug check.
inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
- return base::subtle::Acquire_Load(ptr) == 0;
+ return subtle::Acquire_Load(ptr) == 0;
}
} // namespace base
diff --git a/base/base_lib.scons b/base/base_lib.scons
index ee52dbf..573eea3 100644
--- a/base/base_lib.scons
+++ b/base/base_lib.scons
@@ -320,6 +320,7 @@ if not env.Bit('windows'):
'third_party/purify/pure_api.c',
'time_win.cc',
'waitable_event_win.cc',
+ 'waitable_event_watcher_win.cc',
'win_util.cc',
'wmi_util.cc',
'worker_pool.cc',
@@ -343,7 +344,8 @@ if env.Bit('posix'):
'thread_local_storage_posix.cc',
'thread_local_posix.cc',
'time_posix.cc',
- 'waitable_event_generic.cc',
+ 'waitable_event_posix.cc',
+ 'waitable_event_watcher_posix.cc',
])
if env.Bit('mac'):
diff --git a/base/base_unittests.scons b/base/base_unittests.scons
index 69172e9..a7ea02f 100644
--- a/base/base_unittests.scons
+++ b/base/base_unittests.scons
@@ -112,6 +112,7 @@ input_files = ChromeFileList([
'tuple_unittest.cc',
'values_unittest.cc',
'waitable_event_unittest.cc',
+ 'waitable_event_watcher_unittest.cc',
'watchdog_unittest.cc',
'win_util_unittest.cc',
'wmi_util_unittest.cc',
diff --git a/base/build/base.vcproj b/base/build/base.vcproj
index c5de938..2bfc20a 100644
--- a/base/build/base.vcproj
+++ b/base/build/base.vcproj
@@ -954,6 +954,14 @@
>
</File>
<File
+ RelativePath="..\waitable_event_watcher.h"
+ >
+ </File>
+ <File
+ RelativePath="..\waitable_event_watcher_win.cc"
+ >
+ </File>
+ <File
RelativePath="..\waitable_event_win.cc"
>
</File>
diff --git a/base/waitable_event.h b/base/waitable_event.h
index b723653..84feedc 100644
--- a/base/waitable_event.h
+++ b/base/waitable_event.h
@@ -8,18 +8,27 @@
#include "base/basictypes.h"
#if defined(OS_WIN)
-typedef void* HANDLE;
-#else
+#include <windows.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <list>
+#include <utility>
#include "base/condition_variable.h"
#include "base/lock.h"
+#include "base/ref_counted.h"
#endif
+#include "base/message_loop.h"
+
namespace base {
class TimeDelta;
// A WaitableEvent can be a useful thread synchronization tool when you want to
-// allow one thread to wait for another thread to finish some work.
+// allow one thread to wait for another thread to finish some work. For
+// non-Windows systems, this can only be used from within a single address
+// space.
//
// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
// protect a simple boolean value. However, if you find yourself using a
@@ -31,7 +40,6 @@ class TimeDelta;
// by a Windows event object. This is intentional. If you are writing Windows
// specific code and you need other features of a Windows event, then you might
// be better off just using an Windows event directly.
-//
class WaitableEvent {
public:
// If manual_reset is true, then to set the event state to non-signaled, a
@@ -40,6 +48,13 @@ class WaitableEvent {
// waiting thread has been released.
WaitableEvent(bool manual_reset, bool initially_signaled);
+#if defined(OS_WIN)
+ // Create a WaitableEvent from an Event HANDLE which has already been
+ // created. This objects takes ownership of the HANDLE and will close it when
+ // deleted.
+ explicit WaitableEvent(HANDLE event_handle);
+#endif
+
// WARNING: Destroying a WaitableEvent while threads are waiting on it is not
// supported. Doing so will cause crashes or other instability.
~WaitableEvent();
@@ -64,14 +79,70 @@ class WaitableEvent {
// does not necessarily mean that max_time was exceeded.
bool TimedWait(const TimeDelta& max_time);
+#if defined(OS_WIN)
+ HANDLE handle() const { return handle_; }
+#endif
+
+ // Wait, synchronously, on multiple events.
+ // waitables: an array of WaitableEvent pointers
+ // count: the number of elements in @waitables
+ //
+ // returns: the index of a WaitableEvent which has been signaled.
+ static size_t WaitMany(WaitableEvent** waitables, size_t count);
+
+ // For asynchronous waiting, see WaitableEventWatcher
+
+ // This is a private helper class. It's here because it's used by friends of
+ // this class (such as WaitableEventWatcher) to be able to enqueue elements
+ // of the wait-list
+ class Waiter {
+ public:
+ // Signal the waiter to wake up.
+ //
+ // Consider the case of a Waiter which is in multiple WaitableEvent's
+ // wait-lists. Each WaitableEvent is automatic-reset and two of them are
+ // signaled at the same time. Now, each will wake only the first waiter in
+ // the wake-list before resetting. However, if those two waiters happen to
+ // be the same object (as can happen if another thread didn't have a chance
+ // to dequeue the waiter from the other wait-list in time), two auto-resets
+ // will have happened, but only one waiter has been signaled!
+ //
+ // Because of this, a Waiter may "reject" a wake by returning false. In
+ // this case, the auto-reset WaitableEvent shouldn't act as if anything has
+ // been notified.
+ virtual bool Fire(WaitableEvent* signaling_event) = 0;
+
+ // Waiters may implement this in order to provide an extra condition for
+ // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
+ // pointers match then this function is called as a final check. See the
+ // comments in ~Handle for why.
+ virtual bool Compare(void* tag) = 0;
+ };
+
private:
+ friend class WaitableEventWatcher;
+
#if defined(OS_WIN)
- HANDLE event_;
+ HANDLE handle_;
#else
- Lock lock_; // Needs to be listed first so it will be constructed first.
- ConditionVariable cvar_;
+ bool SignalAll();
+ bool SignalOne();
+ void Enqueue(Waiter* waiter);
+ bool Dequeue(Waiter* waiter, void* tag);
+
+ // When dealing with arrays of WaitableEvent*, we want to sort by the address
+ // of the WaitableEvent in order to have a globally consistent locking order.
+ // In that case we keep them, in sorted order, in an array of pairs where the
+ // second element is the index of the WaitableEvent in the original,
+ // unsorted, array.
+ typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
+ static unsigned EnqueueMany(WaiterAndIndex* waitables,
+ size_t count, Waiter* waiter);
+
+ Lock lock_;
bool signaled_;
- bool manual_reset_;
+ const bool manual_reset_;
+ std::list<Waiter*> waiters_;
#endif
DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
diff --git a/base/waitable_event_generic.cc b/base/waitable_event_generic.cc
deleted file mode 100644
index 61eeeb8..0000000
--- a/base/waitable_event_generic.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2006-2008 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.
-
-#include "base/waitable_event.h"
-
-namespace base {
-
-WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
- : lock_(),
- cvar_(&lock_),
- signaled_(signaled),
- manual_reset_(manual_reset) {
-}
-
-WaitableEvent::~WaitableEvent() {
- // Members are destroyed in the reverse of their initialization order, so we
- // should not have to worry about lock_ being destroyed before cvar_.
-}
-
-void WaitableEvent::Reset() {
- AutoLock locked(lock_);
- signaled_ = false;
-}
-
-void WaitableEvent::Signal() {
- AutoLock locked(lock_);
- if (!signaled_) {
- signaled_ = true;
- if (manual_reset_) {
- cvar_.Broadcast();
- } else {
- cvar_.Signal();
- }
- }
-}
-
-bool WaitableEvent::IsSignaled() {
- return TimedWait(TimeDelta::FromMilliseconds(0));
-}
-
-bool WaitableEvent::Wait() {
- AutoLock locked(lock_);
- while (!signaled_)
- cvar_.Wait();
- if (!manual_reset_)
- signaled_ = false;
- return true;
-}
-
-bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
- AutoLock locked(lock_);
- // In case of spurious wake-ups, we need to adjust the amount of time that we
- // spend sleeping.
- TimeDelta total_time;
- for (;;) {
- TimeTicks start = TimeTicks::Now();
- cvar_.TimedWait(max_time - total_time);
- if (signaled_)
- break;
- total_time += TimeTicks::Now() - start;
- if (total_time >= max_time)
- break;
- }
- bool result = signaled_;
- if (!manual_reset_)
- signaled_ = false;
- return result;
-}
-
-} // namespace base
diff --git a/base/waitable_event_posix.cc b/base/waitable_event_posix.cc
new file mode 100644
index 0000000..be5af6e
--- /dev/null
+++ b/base/waitable_event_posix.cc
@@ -0,0 +1,392 @@
+// Copyright (c) 2006-2008 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.
+
+#include "base/waitable_event.h"
+
+#include "base/condition_variable.h"
+#include "base/lock.h"
+#include "base/message_loop.h"
+
+// -----------------------------------------------------------------------------
+// A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't
+// support cross-process events (where one process can signal an event which
+// others are waiting on). Because of this, we can avoid having one thread per
+// listener in several cases.
+//
+// The WaitableEvent maintains a list of waiters, protected by a lock. Each
+// waiter is either an async wait, in which case we have a Task and the
+// MessageLoop to run it on, or a blocking wait, in which case we have the
+// condition variable to signal.
+//
+// Waiting involves grabbing the lock and adding oneself to the wait list. Async
+// waits can be canceled, which means grabbing the lock and removing oneself
+// from the list.
+//
+// Waiting on multiple events is handled by adding a single, synchronous wait to
+// the wait-list of many events. An event passes a pointer to itself when
+// firing a waiter and so we can store that pointer to find out which event
+// triggered.
+// -----------------------------------------------------------------------------
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// This is just an abstract base class for waking the two types of waiters
+// -----------------------------------------------------------------------------
+WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled)
+ : signaled_(false),
+ manual_reset_(manual_reset) {
+ DCHECK(!initially_signaled) << "Not implemented";
+}
+
+WaitableEvent::~WaitableEvent() {
+ DCHECK(waiters_.empty()) << "Deleting WaitableEvent with listeners!";
+}
+
+void WaitableEvent::Reset() {
+ AutoLock locked(lock_);
+ signaled_ = false;
+}
+
+void WaitableEvent::Signal() {
+ AutoLock locked(lock_);
+
+ if (signaled_)
+ return;
+
+ if (manual_reset_) {
+ SignalAll();
+ signaled_ = true;
+ } else {
+ // In the case of auto reset, if no waiters were woken, we remain
+ // signaled.
+ if (!SignalOne())
+ signaled_ = true;
+ }
+}
+
+bool WaitableEvent::IsSignaled() {
+ AutoLock locked(lock_);
+
+ const bool result = signaled_;
+ if (result && !manual_reset_)
+ signaled_ = false;
+ return result;
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waits
+
+// -----------------------------------------------------------------------------
+// This is an synchronous waiter. The thread is waiting on the given condition
+// variable and the fired flag in this object.
+// -----------------------------------------------------------------------------
+class SyncWaiter : public WaitableEvent::Waiter {
+ public:
+ SyncWaiter(ConditionVariable* cv, Lock* lock)
+ : fired_(false),
+ cv_(cv),
+ lock_(lock),
+ signaling_event_(NULL) { }
+
+ bool Fire(WaitableEvent *signaling_event) {
+ lock_->Acquire();
+ const bool previous_value = fired_;
+ fired_ = true;
+ if (!previous_value)
+ signaling_event_ = signaling_event;
+ lock_->Release();
+
+ if (previous_value)
+ return false;
+
+ cv_->Broadcast();
+
+ // SyncWaiters are stack allocated on the stack of the blocking thread.
+ return true;
+ }
+
+ WaitableEvent* signaled_event() const {
+ return signaling_event_;
+ }
+
+ // ---------------------------------------------------------------------------
+ // These waiters are always stack allocated and don't delete themselves. Thus
+ // there's no problem and the ABA tag is the same as the object pointer.
+ // ---------------------------------------------------------------------------
+ bool Compare(void* tag) {
+ return this == tag;
+ }
+
+ // ---------------------------------------------------------------------------
+ // Called with lock held.
+ // ---------------------------------------------------------------------------
+ bool fired() const {
+ return fired_;
+ }
+
+ // ---------------------------------------------------------------------------
+ // During a TimedWait, we need a way to make sure that an auto-reset
+ // WaitableEvent doesn't think that this event has been signaled between
+ // unlocking it and removing it from the wait-list. Called with lock held.
+ // ---------------------------------------------------------------------------
+ void Disable() {
+ fired_ = true;
+ }
+
+ private:
+ bool fired_;
+ ConditionVariable *const cv_;
+ Lock *const lock_;
+ WaitableEvent* signaling_event_; // The WaitableEvent which woke us
+};
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+ const Time end_time(Time::Now() + max_time);
+
+ lock_.Acquire();
+ if (signaled_) {
+ if (!manual_reset_) {
+ // In this case we were signaled when we had no waiters. Now that
+ // someone has waited upon us, we can automatically reset.
+ signaled_ = false;
+ }
+
+ lock_.Release();
+ return true;
+ }
+
+ Lock lock;
+ lock.Acquire();
+ ConditionVariable cv(&lock);
+ SyncWaiter sw(&cv, &lock);
+
+ Enqueue(&sw);
+ lock_.Release();
+ // We are violating locking order here by holding the SyncWaiter lock but not
+ // the WaitableEvent lock. However, this is safe because we don't lock @lock_
+ // again before unlocking it.
+
+ for (;;) {
+ if (sw.fired()) {
+ lock.Release();
+ return true;
+ }
+
+ if (max_time.ToInternalValue() < 0) {
+ cv.Wait();
+ } else {
+ const Time current_time(Time::Now());
+ if (current_time >= end_time) {
+ // We can't acquire @lock_ before releasing @lock (because of locking
+ // order), however, inbetween the two a signal could be fired and @sw
+ // would accept it, however we will still return false, so the signal
+ // would be lost on an auto-reset WaitableEvent. Thus we call Disable
+ // which makes sw::Fire return false.
+ sw.Disable();
+ lock.Release();
+
+ lock_.Acquire();
+ Dequeue(&sw, &sw);
+ lock_.Release();
+ return false;
+ }
+ const TimeDelta max_wait(end_time - current_time);
+
+ cv.TimedWait(max_wait);
+ }
+ }
+}
+
+bool WaitableEvent::Wait() {
+ return TimedWait(TimeDelta::FromSeconds(-1));
+}
+
+// -----------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// Synchronous waiting on multiple objects.
+
+static bool // StrictWeakOrdering
+cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a,
+ const std::pair<WaitableEvent*, unsigned> &b) {
+ return a.first < b.first;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
+ size_t count) {
+ DCHECK(count) << "Cannot wait on no events";
+
+ // We need to acquire the locks in a globally consistent order. Thus we sort
+ // the array of waitables by address. We actually sort a pairs so that we can
+ // map back to the original index values later.
+ std::vector<std::pair<WaitableEvent*, size_t> > waitables;
+ waitables.reserve(count);
+ for (size_t i = 0; i < count; ++i)
+ waitables.push_back(std::make_pair(raw_waitables[i], i));
+
+ DCHECK_EQ(count, waitables.size());
+
+ sort(waitables.begin(), waitables.end(), cmp_fst_addr);
+
+ // The set of waitables must be distinct. Since we have just sorted by
+ // address, we can check this cheaply by comparing pairs of consecutive
+ // elements.
+ for (size_t i = 0; i < waitables.size() - 1; ++i) {
+ DCHECK(waitables[i].first != waitables[i+1].first);
+ }
+
+ Lock lock;
+ ConditionVariable cv(&lock);
+ SyncWaiter sw(&cv, &lock);
+
+ const size_t r = EnqueueMany(&waitables[0], count, &sw);
+ if (r) {
+ // One of the events is already signaled. The SyncWaiter has not been
+ // enqueued anywhere. EnqueueMany returns the count of remaining waitables
+ // when the signaled one was seen, so the index of the signaled event is
+ // @count - @r.
+ return waitables[count - r].second;
+ }
+
+ // At this point, we hold the locks on all the WaitableEvents and we have
+ // enqueued our waiter in them all.
+ lock.Acquire();
+ // Release the WaitableEvent locks in the reverse order
+ for (size_t i = 0; i < count; ++i) {
+ waitables[count - (1 + i)].first->lock_.Release();
+ }
+
+ for (;;) {
+ if (sw.fired())
+ break;
+
+ cv.Wait();
+ }
+ lock.Release();
+
+ // The address of the WaitableEvent which fired is stored in the SyncWaiter.
+ WaitableEvent *const signaled_event = sw.signaled_event();
+ // This will store the index of the raw_waitables which fired.
+ size_t signaled_index;
+
+ // Take the locks of each WaitableEvent in turn (except the signaled one) and
+ // remove our SyncWaiter from the wait-list
+ for (size_t i = 0; i < count; ++i) {
+ if (raw_waitables[i] != signaled_event) {
+ raw_waitables[i]->lock_.Acquire();
+ // There's no possible ABA issue with the address of the SyncWaiter here
+ // because it lives on the stack. Thus the tag value is just the pointer
+ // value again.
+ raw_waitables[i]->Dequeue(&sw, &sw);
+ raw_waitables[i]->lock_.Release();
+ } else {
+ signaled_index = i;
+ }
+ }
+
+ return signaled_index;
+}
+
+// -----------------------------------------------------------------------------
+// If return value == 0:
+// The locks of the WaitableEvents have been taken in order and the Waiter has
+// been enqueued in the wait-list of each. None of the WaitableEvents are
+// currently signaled
+// else:
+// None of the WaitableEvent locks are held. The Waiter has not been enqueued
+// in any of them and the return value is the index of the first WaitableEvent
+// which was signaled, from the end of the array.
+// -----------------------------------------------------------------------------
+// static
+unsigned WaitableEvent::EnqueueMany
+ (std::pair<WaitableEvent*, unsigned>* waitables,
+ unsigned count, Waiter* waiter) {
+ if (!count)
+ return 0;
+
+ waitables[0].first->lock_.Acquire();
+ if (waitables[0].first->signaled_) {
+ if (!waitables[0].first->manual_reset_)
+ waitables[0].first->signaled_ = false;
+ waitables[0].first->lock_.Release();
+ return count;
+ }
+
+ const unsigned r = EnqueueMany(waitables + 1, count - 1, waiter);
+ if (r) {
+ waitables[0].first->lock_.Release();
+ } else {
+ waitables[0].first->Enqueue(waiter);
+ }
+
+ return r;
+}
+
+// -----------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// Private functions...
+
+// -----------------------------------------------------------------------------
+// Wake all waiting waiters. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::SignalAll() {
+ bool signaled_at_least_one = false;
+
+ for (std::list<Waiter*>::iterator
+ i = waiters_.begin(); i != waiters_.end(); ++i) {
+ if ((*i)->Fire(this))
+ signaled_at_least_one = true;
+ }
+
+ waiters_.clear();
+ return signaled_at_least_one;
+}
+
+// ---------------------------------------------------------------------------
+// Try to wake a single waiter. Return true if one was woken. Called with lock
+// held.
+// ---------------------------------------------------------------------------
+bool WaitableEvent::SignalOne() {
+ for (;;) {
+ if (waiters_.empty())
+ return false;
+
+ const bool r = (*waiters_.begin())->Fire(this);
+ waiters_.pop_front();
+ if (r)
+ return true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Add a waiter to the list of those waiting. Called with lock held.
+// -----------------------------------------------------------------------------
+void WaitableEvent::Enqueue(Waiter* waiter) {
+ waiters_.push_back(waiter);
+}
+
+// -----------------------------------------------------------------------------
+// Remove a waiter from the list of those waiting. Return true if the waiter was
+// actually removed. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::Dequeue(Waiter* waiter, void* tag) {
+ for (std::list<Waiter*>::iterator
+ i = waiters_.begin(); i != waiters_.end(); ++i) {
+ if (*i == waiter && (*i)->Compare(tag)) {
+ waiters_.erase(i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+} // namespace base
diff --git a/base/waitable_event_unittest.cc b/base/waitable_event_unittest.cc
index e7bab49..b2590a8 100644
--- a/base/waitable_event_unittest.cc
+++ b/base/waitable_event_unittest.cc
@@ -4,6 +4,7 @@
#include "base/time.h"
#include "base/waitable_event.h"
+#include "base/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::TimeDelta;
@@ -52,3 +53,57 @@ TEST(WaitableEventTest, AutoBasics) {
EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
}
+TEST(WaitableEventTest, WaitManyShortcut) {
+ WaitableEvent* ev[5];
+ for (unsigned i = 0; i < 5; ++i)
+ ev[i] = new WaitableEvent(false, false);
+
+ ev[3]->Signal();
+ EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+ ev[3]->Signal();
+ EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+ ev[4]->Signal();
+ EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 4u);
+
+ ev[0]->Signal();
+ EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 0u);
+
+ for (unsigned i = 0; i < 5; ++i)
+ delete ev[i];
+}
+
+class WaitableEventSignaler : public PlatformThread::Delegate {
+ public:
+ WaitableEventSignaler(double seconds, WaitableEvent* ev)
+ : seconds_(seconds),
+ ev_(ev) {
+ }
+
+ void ThreadMain() {
+ PlatformThread::Sleep(static_cast<int>(seconds_ * 1000));
+ ev_->Signal();
+ }
+
+ private:
+ const double seconds_;
+ WaitableEvent *const ev_;
+};
+
+TEST(WaitableEventTest, WaitMany) {
+ WaitableEvent* ev[5];
+ for (unsigned i = 0; i < 5; ++i)
+ ev[i] = new WaitableEvent(false, false);
+
+ WaitableEventSignaler signaler(0.1, ev[2]);
+ PlatformThreadHandle thread;
+ PlatformThread::Create(0, &signaler, &thread);
+
+ EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 2u);
+
+ PlatformThread::Join(thread);
+
+ for (unsigned i = 0; i < 5; ++i)
+ delete ev[i];
+}
diff --git a/base/waitable_event_watcher.h b/base/waitable_event_watcher.h
new file mode 100644
index 0000000..3e17a10
--- /dev/null
+++ b/base/waitable_event_watcher.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2006-2008 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 BASE_WAITABLE_EVENT_WATCHER_H_
+#define BASE_WAITABLE_EVENT_WATCHER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/object_watcher.h"
+#else
+#include "base/message_loop.h"
+#endif
+
+namespace base {
+
+class WaitableEvent;
+class Flag;
+class AsyncWaiter;
+class AsyncCallbackTask;
+
+// -----------------------------------------------------------------------------
+// This class provides a way to wait on a WaitableEvent asynchronously.
+//
+// Each instance of this object can be waiting on a single WaitableEvent. When
+// the waitable event is signaled, a callback is made in the thread of a given
+// MessageLoop. This callback can be deleted by deleting the waiter.
+//
+// Typical usage:
+//
+// class MyClass : public base::WaitableEventWatcher::Delegate {
+// public:
+// void DoStuffWhenSignaled(WaitableEvent *waitable_event) {
+// watcher_.StartWatching(waitable_event, this);
+// }
+// virtual void OnWaitableEventSignaled(WaitableEvent* waitable_event) {
+// // OK, time to do stuff!
+// }
+// private:
+// base::WaitableEventWatcher watcher_;
+// };
+//
+// In the above example, MyClass wants to "do stuff" when waitable_event
+// becomes signaled. WaitableEventWatcher makes this task easy. When MyClass
+// goes out of scope, the watcher_ will be destroyed, and there is no need to
+// worry about OnWaitableEventSignaled being called on a deleted MyClass
+// pointer.
+//
+// BEWARE: With automatically reset WaitableEvents, a signal may be lost if it
+// occurs just before a WaitableEventWatcher is deleted. There is currently no
+// safe way to stop watching an automatic reset WaitableEvent without possibly
+// missing a signal.
+// -----------------------------------------------------------------------------
+
+class WaitableEventWatcher
+#if defined(OS_POSIX)
+ : public MessageLoop::DestructionObserver
+#endif
+{
+ public:
+
+ WaitableEventWatcher();
+ ~WaitableEventWatcher();
+
+ class Delegate {
+ public:
+ virtual ~Delegate() { }
+
+ // -------------------------------------------------------------------------
+ // This is called on the MessageLoop thread when WaitableEvent has been
+ // signaled.
+ //
+ // Note: the event may not be signaled by the time that this function is
+ // called. This indicates only that it has been signaled at some point in
+ // the past.
+ // -------------------------------------------------------------------------
+ virtual void OnWaitableEventSignaled(WaitableEvent* waitable_event) = 0;
+ };
+
+ // ---------------------------------------------------------------------------
+ // When @event is signaled, the given delegate is called on the thread of the
+ // current message loop when StartWatching is called. The delegate is not
+ // deleted.
+ // ---------------------------------------------------------------------------
+ bool StartWatching(WaitableEvent* event, Delegate* delegate);
+
+ // ---------------------------------------------------------------------------
+ // Cancel the current watch. Must be called from the same thread which
+ // started the watch.
+ //
+ // Does nothing if no event is being watched, nor if the watch has completed.
+ // The delegate will *not* be called for the current watch after this
+ // function returns. Since the delegate runs on the same thread as this
+ // function, it cannot be called during this function either.
+ // ---------------------------------------------------------------------------
+ void StopWatching();
+
+ // ---------------------------------------------------------------------------
+ // Return the currently watched event, or NULL if no object is currently being
+ // watched.
+ // ---------------------------------------------------------------------------
+ WaitableEvent* GetWatchedEvent();
+
+ private:
+ WaitableEvent* event_;
+
+#if defined(OS_WIN)
+ // ---------------------------------------------------------------------------
+ // The helper class exists because, if WaitableEventWatcher were to inherit
+ // from ObjectWatcher::Delegate, then it couldn't also have an inner class
+ // called Delegate (at least on Windows). Thus this object exists to proxy
+ // the callback function
+ // ---------------------------------------------------------------------------
+ class ObjectWatcherHelper : public ObjectWatcher::Delegate {
+ public:
+ ObjectWatcherHelper(WaitableEventWatcher* watcher);
+
+ // -------------------------------------------------------------------------
+ // Implementation of ObjectWatcher::Delegate
+ // -------------------------------------------------------------------------
+ void OnObjectSignaled(HANDLE h);
+
+ private:
+ WaitableEventWatcher *const watcher_;
+ };
+
+ void OnObjectSignaled();
+
+ Delegate* delegate_;
+ ObjectWatcherHelper helper_;
+ ObjectWatcher watcher_;
+#else
+ // ---------------------------------------------------------------------------
+ // Implementation of MessageLoop::DestructionObserver
+ // ---------------------------------------------------------------------------
+ void WillDestroyCurrentMessageLoop();
+
+ MessageLoop* message_loop_;
+ scoped_refptr<Flag> cancel_flag_;
+ AsyncWaiter* waiter_;
+ AsyncCallbackTask* callback_task_;
+#endif
+};
+
+} // namespace base
+
+#endif // BASE_WAITABLE_EVENT_WATCHER_H_
diff --git a/base/waitable_event_watcher_posix.cc b/base/waitable_event_watcher_posix.cc
new file mode 100644
index 0000000..e4e1a7f
--- /dev/null
+++ b/base/waitable_event_watcher_posix.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2006-2008 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.
+
+#include "base/waitable_event_watcher.h"
+
+#include "base/condition_variable.h"
+#include "base/lock.h"
+#include "base/message_loop.h"
+#include "base/waitable_event.h"
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// WaitableEventWatcher (async waits).
+//
+// The basic design is that we add an AsyncWaiter to the wait-list of the event.
+// That AsyncWaiter has a pointer to MessageLoop, and a Task to be posted to it.
+// The MessageLoop ends up running the task, which calls the delegate.
+//
+// Since the wait can be canceled, we have a thread-safe Flag object which is
+// set when the wait has been canceled. At each stage in the above, we check the
+// flag before going onto the next stage. Since the wait may only be canceled in
+// the MessageLoop which runs the Task, we are assured that the delegate cannot
+// be called after canceling...
+
+// -----------------------------------------------------------------------------
+// A thread-safe, reference-counted, write-once flag.
+// -----------------------------------------------------------------------------
+class Flag : public RefCountedThreadSafe<Flag> {
+ public:
+ Flag() { flag_ = false; }
+
+ void Set() {
+ AutoLock locked(lock_);
+ flag_ = true;
+ }
+
+ bool value() const {
+ AutoLock locked(lock_);
+ return flag_;
+ }
+
+ private:
+ mutable Lock lock_;
+ bool flag_;
+};
+
+// -----------------------------------------------------------------------------
+// This is an asynchronous waiter which posts a task to a MessageLoop when
+// fired. An AsyncWaiter may only be in a single wait-list.
+// -----------------------------------------------------------------------------
+class AsyncWaiter : public WaitableEvent::Waiter {
+ public:
+ AsyncWaiter(MessageLoop* message_loop, Task* task, Flag* flag)
+ : message_loop_(message_loop),
+ cb_task_(task),
+ flag_(flag) { }
+
+ bool Fire(WaitableEvent* event) {
+ if (flag_->value()) {
+ // If the callback has been canceled, we don't enqueue the task, we just
+ // delete it instead.
+ delete cb_task_;
+ } else {
+ message_loop_->PostTask(FROM_HERE, cb_task_);
+ }
+
+ // We are removed from the wait-list by the WaitableEvent itself. It only
+ // remains to delete ourselves.
+ delete this;
+
+ // We can always return true because an AsyncWaiter is never in two
+ // different wait-lists at the same time.
+ return true;
+ }
+
+ // See StopWatching for discussion
+ bool Compare(void* tag) {
+ return tag == flag_.get();
+ }
+
+ MessageLoop *const message_loop_;
+ Task *const cb_task_;
+ scoped_refptr<Flag> flag_;
+};
+
+// -----------------------------------------------------------------------------
+// For async waits we need to make a callback in a MessageLoop thread. We do
+// this by posting this task, which calls the delegate and keeps track of when
+// the event is canceled.
+// -----------------------------------------------------------------------------
+class AsyncCallbackTask : public Task {
+ public:
+ AsyncCallbackTask(Flag* flag, WaitableEventWatcher::Delegate* delegate,
+ WaitableEvent* event)
+ : flag_(flag),
+ delegate_(delegate),
+ event_(event) {
+ }
+
+ void Run() {
+ // Runs in MessageLoop thread.
+ if (!flag_->value())
+ delegate_->OnWaitableEventSignaled(event_);
+
+ // This is to let the WaitableEventWatcher know that the event has occured
+ // because it needs to be able to return NULL from GetWatchedEvent
+ flag_->Set();
+
+ // We are deleted by the MessageLoop
+ }
+
+ private:
+ scoped_refptr<Flag> flag_;
+ WaitableEventWatcher::Delegate *const delegate_;
+ WaitableEvent *const event_;
+};
+
+WaitableEventWatcher::WaitableEventWatcher()
+ : event_(NULL),
+ message_loop_(NULL),
+ cancel_flag_(NULL),
+ callback_task_(NULL) {
+}
+
+WaitableEventWatcher::~WaitableEventWatcher() {
+ StopWatching();
+}
+
+// -----------------------------------------------------------------------------
+// The Handle is how the user cancels a wait. After deleting the Handle we
+// insure that the delegate cannot be called.
+// -----------------------------------------------------------------------------
+bool WaitableEventWatcher::StartWatching
+ (WaitableEvent* event, WaitableEventWatcher::Delegate* delegate) {
+ MessageLoop *const current_ml = MessageLoop::current();
+ DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a "
+ "current MessageLoop";
+
+ DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching";
+
+ cancel_flag_ = new Flag;
+ callback_task_ = new AsyncCallbackTask(cancel_flag_, delegate, event);
+
+ AutoLock locked(event->lock_);
+
+ if (event->signaled_) {
+ if (!event->manual_reset_)
+ event->signaled_ = false;
+
+ // No hairpinning - we can't call the delegate directly here. We have to
+ // enqueue a task on the MessageLoop as normal.
+ current_ml->PostTask(FROM_HERE, callback_task_);
+ return true;
+ }
+
+ message_loop_ = current_ml;
+ current_ml->AddDestructionObserver(this);
+
+ event_ = event;
+ waiter_ = new AsyncWaiter(current_ml, callback_task_, cancel_flag_);
+ event->Enqueue(waiter_);
+
+ return true;
+}
+
+void WaitableEventWatcher::StopWatching() {
+ if (message_loop_) {
+ message_loop_->RemoveDestructionObserver(this);
+ message_loop_ = NULL;
+ }
+
+ if (!cancel_flag_.get()) // if not currently watching...
+ return;
+
+ if (!event_) {
+ // We have no WaitableEvent. This means that we never enqueued a Waiter on
+ // an event because the event was already signaled when StartWatching was
+ // called.
+ //
+ // In this case, a task was enqueued on the MessageLoop and will run.
+ // We set the flag in case the task hasn't yet run. The flag will stop the
+ // delegate getting called. If the task has run then we have the last
+ // reference to the flag and it will be deleted immedately after.
+ cancel_flag_->Set();
+ cancel_flag_ = NULL;
+ return;
+ }
+
+ AutoLock locked(event_->lock_);
+ // We have a lock on the WaitableEvent. No one else can signal the event while
+ // we have it.
+
+ // We have a possible ABA issue here. If Dequeue was to compare only the
+ // pointer values then it's possible that the AsyncWaiter could have been
+ // fired, freed and the memory reused for a different Waiter which was
+ // enqueued in the same wait-list. We would think that that waiter was our
+ // AsyncWaiter and remove it.
+ //
+ // To stop this, Dequeue also takes a tag argument which is passed to the
+ // virtual Compare function before the two are considered a match. So we need
+ // a tag which is good for the lifetime of this handle: the Flag. Since we
+ // have a reference to the Flag, its memory cannot be reused while this object
+ // still exists. So if we find a waiter with the correct pointer value, and
+ // which shares a Flag pointer, we have a real match.
+ if (event_->Dequeue(waiter_, cancel_flag_.get())) {
+ // Case 2: the waiter hasn't been signaled yet; it was still on the wait
+ // list. We've removed it, thus we can delete it and the task (which cannot
+ // have been enqueued with the MessageLoop because the waiter was never
+ // signaled)
+ delete waiter_;
+ delete callback_task_;
+ cancel_flag_ = NULL;
+ return;
+ }
+
+ // Case 3: the waiter isn't on the wait-list, thus it was signaled. It may
+ // not have run yet, so we set the flag to tell it not to bother enqueuing the
+ // task on the MessageLoop, but to delete it instead. The Waiter deletes
+ // itself once run.
+ cancel_flag_->Set();
+ cancel_flag_ = NULL;
+
+ // If the waiter has already run then the task has been enqueued. If the Task
+ // hasn't yet run, the flag will stop the delegate from getting called. (This
+ // is thread safe because one may only delete a Handle from the MessageLoop
+ // thread.)
+ //
+ // If the delegate has already been called then we have nothing to do. The
+ // task has been deleted by the MessageLoop.
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+ if (!cancel_flag_.get())
+ return NULL;
+
+ if (cancel_flag_->value())
+ return NULL;
+
+ return event_;
+}
+
+// -----------------------------------------------------------------------------
+// This is called when the MessageLoop which the callback will be run it is
+// deleted. We need to cancel the callback as if we had been deleted, but we
+// will still be deleted at some point in the future.
+// -----------------------------------------------------------------------------
+void WaitableEventWatcher::WillDestroyCurrentMessageLoop() {
+ StopWatching();
+}
+
+} // namespace base
diff --git a/base/waitable_event_watcher_unittest.cc b/base/waitable_event_watcher_unittest.cc
new file mode 100644
index 0000000..c50807f
--- /dev/null
+++ b/base/waitable_event_watcher_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2006-2008 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.
+
+#include "base/message_loop.h"
+#include "base/platform_thread.h"
+#include "base/waitable_event.h"
+#include "base/waitable_event_watcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::WaitableEvent;
+using base::WaitableEventWatcher;
+
+namespace {
+
+class QuitDelegate : public WaitableEventWatcher::Delegate {
+ public:
+ virtual void OnWaitableEventSignaled(WaitableEvent* event) {
+ MessageLoop::current()->Quit();
+ }
+};
+
+class DecrementCountDelegate : public WaitableEventWatcher::Delegate {
+ public:
+ DecrementCountDelegate(int* counter) : counter_(counter) {
+ }
+ virtual void OnWaitableEventSignaled(WaitableEvent* object) {
+ --(*counter_);
+ }
+ private:
+ int* counter_;
+};
+
+} // namespace
+
+void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
+ MessageLoop message_loop(message_loop_type);
+
+ // A manual-reset event that is not yet signaled.
+ WaitableEvent event(true, false);
+
+ WaitableEventWatcher watcher;
+ EXPECT_EQ(NULL, watcher.GetWatchedObject());
+
+ QuitDelegate delegate;
+ watcher.StartWatching(&event, &delegate);
+ EXPECT_EQ(&event, watcher.GetWatchedObject());
+
+ event.Signal();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(NULL, watcher.GetWatchedObject());
+}
+
+void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
+ MessageLoop message_loop(message_loop_type);
+
+ // A manual-reset event that is not yet signaled.
+ WaitableEvent event(true, false);
+
+ WaitableEventWatcher watcher;
+
+ QuitDelegate delegate;
+ watcher.StartWatching(&event, &delegate);
+
+ watcher.StopWatching();
+}
+
+void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
+ MessageLoop message_loop(message_loop_type);
+
+ // A manual-reset event that is not yet signaled.
+ WaitableEvent event(true, false);
+
+ WaitableEventWatcher watcher;
+
+ int counter = 1;
+ DecrementCountDelegate delegate(&counter);
+
+ watcher.StartWatching(&event, &delegate);
+
+ event.Signal();
+
+ // Let the background thread do its business
+ PlatformThread::Sleep(30);
+
+ watcher.StopWatching();
+
+ MessageLoop::current()->RunAllPending();
+
+ // Our delegate should not have fired.
+ EXPECT_EQ(1, counter);
+}
+
+void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
+ // Simulate a MessageLoop that dies before an WaitableEventWatcher. This
+ // ordinarily doesn't happen when people use the Thread class, but it can
+ // happen when people use the Singleton pattern or atexit.
+ WaitableEvent event(true, false);
+ {
+ WaitableEventWatcher watcher;
+ {
+ MessageLoop message_loop(message_loop_type);
+
+ QuitDelegate delegate;
+ watcher.StartWatching(&event, &delegate);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(ObjectWatcherTest, BasicSignal) {
+ RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT);
+ RunTest_BasicSignal(MessageLoop::TYPE_IO);
+ RunTest_BasicSignal(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, BasicCancel) {
+ RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT);
+ RunTest_BasicCancel(MessageLoop::TYPE_IO);
+ RunTest_BasicCancel(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, CancelAfterSet) {
+ RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT);
+ RunTest_CancelAfterSet(MessageLoop::TYPE_IO);
+ RunTest_CancelAfterSet(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, OutlivesMessageLoop) {
+ RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT);
+ RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO);
+ RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);
+}
diff --git a/base/waitable_event_watcher_win.cc b/base/waitable_event_watcher_win.cc
new file mode 100644
index 0000000..7619aa4
--- /dev/null
+++ b/base/waitable_event_watcher_win.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2006-2008 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.
+
+#include "base/waitable_event_watcher.h"
+
+#include "base/compiler_specific.h"
+#include "base/object_watcher.h"
+#include "base/waitable_event.h"
+
+namespace base {
+
+WaitableEventWatcher::ObjectWatcherHelper::ObjectWatcherHelper(
+ WaitableEventWatcher* watcher)
+ : watcher_(watcher) {
+};
+
+void WaitableEventWatcher::ObjectWatcherHelper::OnObjectSignaled(HANDLE h) {
+ watcher_->OnObjectSignaled();
+}
+
+
+WaitableEventWatcher::WaitableEventWatcher()
+ : event_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(helper_(this)),
+ delegate_(NULL) {
+}
+
+WaitableEventWatcher::~WaitableEventWatcher() {
+}
+
+bool WaitableEventWatcher::StartWatching(WaitableEvent* event,
+ Delegate* delegate) {
+ delegate_ = delegate;
+ event_ = event;
+
+ return watcher_.StartWatching(event->handle(), &helper_);
+}
+
+void WaitableEventWatcher::StopWatching() {
+ delegate_ = NULL;
+ event_ = NULL;
+ watcher_.StopWatching();
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+ return event_;
+}
+
+void WaitableEventWatcher::OnObjectSignaled() {
+ WaitableEvent* event = event_;
+ Delegate* delegate = delegate_;
+ event_ = NULL;
+ delegate_ = NULL;
+ DCHECK(event);
+
+ delegate->OnWaitableEventSignaled(event);
+}
+
+} // namespace base
diff --git a/base/waitable_event_win.cc b/base/waitable_event_win.cc
index 257f145..001a5df 100644
--- a/base/waitable_event_win.cc
+++ b/base/waitable_event_win.cc
@@ -13,22 +13,27 @@
namespace base {
WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
- : event_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
+ : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
// We're probably going to crash anyways if this is ever NULL, so we might as
// well make our stack reports more informative by crashing here.
- CHECK(event_);
+ CHECK(handle_);
+}
+
+WaitableEvent::WaitableEvent(HANDLE handle)
+ : handle_(handle) {
+ CHECK(handle) << "Tried to create WaitableEvent from NULL handle";
}
WaitableEvent::~WaitableEvent() {
- CloseHandle(event_);
+ CloseHandle(handle_);
}
void WaitableEvent::Reset() {
- ResetEvent(event_);
+ ResetEvent(handle_);
}
void WaitableEvent::Signal() {
- SetEvent(event_);
+ SetEvent(handle_);
}
bool WaitableEvent::IsSignaled() {
@@ -36,7 +41,7 @@ bool WaitableEvent::IsSignaled() {
}
bool WaitableEvent::Wait() {
- DWORD result = WaitForSingleObject(event_, INFINITE);
+ DWORD result = WaitForSingleObject(handle_, INFINITE);
// It is most unexpected that this should ever fail. Help consumers learn
// about it if it should ever fail.
DCHECK(result == WAIT_OBJECT_0) << "WaitForSingleObject failed";
@@ -49,7 +54,7 @@ bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
// is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6?
// It should be 6 to avoid returning too early.
double timeout = ceil(max_time.InMillisecondsF());
- DWORD result = WaitForSingleObject(event_, static_cast<DWORD>(timeout));
+ DWORD result = WaitForSingleObject(handle_, static_cast<DWORD>(timeout));
switch (result) {
case WAIT_OBJECT_0:
return true;
@@ -62,4 +67,25 @@ bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
return false;
}
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ CHECK(count <= MAXIMUM_WAIT_OBJECTS)
+ << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
+
+ for (size_t i = 0; i < count; ++i)
+ handles[i] = events[i]->handle();
+
+ DWORD result =
+ WaitForMultipleObjects(count, handles,
+ FALSE, // don't wait for all the objects
+ INFINITE); // no timeout
+ if (result < WAIT_OBJECT_0 || result >= WAIT_OBJECT_0 + count) {
+ NOTREACHED() << "WaitForMultipleObjects failed: " << GetLastError();
+ return 0;
+ }
+
+ return result - WAIT_OBJECT_0;
+}
+
} // namespace base
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 18ce8be..adff28b 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -36,6 +36,7 @@ class SuspendController;
namespace base {
class Thread;
+class WaitableEvent;
}
namespace sandbox {
class BrokerServices;
@@ -128,10 +129,10 @@ class BrowserProcess {
ResourceDispatcherHost* rdh = resource_dispatcher_host();
return rdh ? rdh->download_request_manager() : NULL;
}
+#endif
// Returns an event that is signaled when the browser shutdown.
- virtual HANDLE shutdown_event() = 0;
-#endif
+ virtual base::WaitableEvent* shutdown_event() = 0;
// Returns a reference to the user-data-dir based profiles vector.
std::vector<std::wstring>& user_data_dir_profiles() {
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 904de03..bccf10b 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/thread.h"
+#include "base/waitable_event.h"
#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/browser_trial.h"
#include "chrome/browser/chrome_thread.h"
@@ -127,7 +128,7 @@ BrowserProcessImpl::BrowserProcessImpl(CommandLine& command_line)
memory_model_ = MEDIUM_MEMORY_MODEL;
}
- shutdown_event_ = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ shutdown_event_ = new base::WaitableEvent(true, false);
}
BrowserProcessImpl::~BrowserProcessImpl() {
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 6f51102..3b8732c 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -167,7 +167,7 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
return memory_model_;
}
- virtual HANDLE shutdown_event() { return shutdown_event_; }
+ virtual base::WaitableEvent* shutdown_event() { return shutdown_event_; }
private:
void CreateResourceDispatcherHost();
@@ -242,7 +242,7 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
bool using_new_frames_;
// An event that notifies when we are shutting-down.
- HANDLE shutdown_event_;
+ base::WaitableEvent* shutdown_event_;
DISALLOW_EVIL_CONSTRUCTORS(BrowserProcessImpl);
};
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index e192688..e0417fa 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -9,6 +9,7 @@
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/first_run.h"
#include "chrome/browser/jankometer.h"
@@ -86,7 +87,7 @@ void Shutdown() {
DCHECK(g_browser_process);
// Notifies we are going away.
- ::SetEvent(g_browser_process->shutdown_event());
+ g_browser_process->shutdown_event()->Signal();
PluginService* plugin_service = PluginService::GetInstance();
if (plugin_service) {
diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc
index 5ace177..399beee 100644
--- a/chrome/browser/render_view_host.cc
+++ b/chrome/browser/render_view_host.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/string_util.h"
+#include "base/waitable_event.h"
#include "chrome/app/result_codes.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/cross_site_request_manager.h"
@@ -74,7 +75,7 @@ RenderViewHost* RenderViewHost::FromID(int render_process_id,
RenderViewHost::RenderViewHost(SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- HANDLE modal_dialog_event)
+ base::WaitableEvent* modal_dialog_event)
: RenderWidgetHost(instance->GetProcess(), routing_id),
instance_(instance),
enable_dom_ui_bindings_(false),
@@ -93,9 +94,9 @@ RenderViewHost::RenderViewHost(SiteInstance* instance,
DCHECK(instance_);
DCHECK(delegate_);
if (modal_dialog_event == NULL)
- modal_dialog_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ modal_dialog_event = new base::WaitableEvent(true, false);
- modal_dialog_event_.Set(modal_dialog_event);
+ modal_dialog_event_.reset(modal_dialog_event);
#ifdef CHROME_PERSONALIZATION
personalization_ = Personalization::CreateHostPersonalization(this);
#endif
@@ -134,7 +135,7 @@ bool RenderViewHost::CreateRenderView() {
renderer_process_handle = GetCurrentProcess();
BOOL result = DuplicateHandle(GetCurrentProcess(),
- modal_dialog_event_.Get(),
+ modal_dialog_event_->handle(),
renderer_process_handle,
&modal_dialog_event,
SYNCHRONIZE,
@@ -498,7 +499,7 @@ void RenderViewHost::JavaScriptMessageBoxClosed(IPC::Message* reply_msg,
}
if (--modal_dialog_count_ == 0)
- ResetEvent(modal_dialog_event_.Get());
+ modal_dialog_event_->Reset();
ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, success, prompt);
Send(reply_msg);
}
@@ -509,7 +510,7 @@ void RenderViewHost::ModalHTMLDialogClosed(IPC::Message* reply_msg,
StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
if (--modal_dialog_count_ == 0)
- ResetEvent(modal_dialog_event_.Get());
+ modal_dialog_event_->Reset();
ViewHostMsg_ShowModalHTMLDialog::WriteReplyParams(reply_msg, json_retval);
Send(reply_msg);
@@ -742,7 +743,7 @@ void RenderViewHost::Shutdown() {
// If we are being run modally (see RunModal), then we need to cleanup.
if (run_modal_reply_msg_) {
if (--modal_dialog_count_ == 0)
- ResetEvent(modal_dialog_event_.Get());
+ modal_dialog_event_->Reset();
Send(run_modal_reply_msg_);
run_modal_reply_msg_ = NULL;
}
@@ -753,7 +754,8 @@ void RenderViewHost::OnMsgCreateWindow(int route_id,
HANDLE modal_dialog_event) {
RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
if (view)
- view->CreateNewWindow(route_id, modal_dialog_event);
+ view->CreateNewWindow(route_id,
+ new base::WaitableEvent(modal_dialog_event));
}
void RenderViewHost::OnMsgCreateWidget(int route_id, bool activatable) {
@@ -781,7 +783,7 @@ void RenderViewHost::OnMsgShowWidget(int route_id,
void RenderViewHost::OnMsgRunModal(IPC::Message* reply_msg) {
DCHECK(!run_modal_reply_msg_);
if (modal_dialog_count_++ == 0)
- SetEvent(modal_dialog_event_.Get());
+ modal_dialog_event_->Reset();
run_modal_reply_msg_ = reply_msg;
// TODO(darin): Bug 1107929: Need to inform our delegate to show this view in
@@ -1085,7 +1087,7 @@ void RenderViewHost::OnMsgRunJavaScriptMessage(
IPC::Message* reply_msg) {
StopHangMonitorTimeout();
if (modal_dialog_count_++ == 0)
- SetEvent(modal_dialog_event_.Get());
+ modal_dialog_event_->Signal();
bool did_suppress_message = false;
delegate_->RunJavaScriptMessage(message, default_prompt, flags, reply_msg,
&are_javascript_messages_suppressed_);
@@ -1095,7 +1097,7 @@ void RenderViewHost::OnMsgRunBeforeUnloadConfirm(const std::wstring& message,
IPC::Message* reply_msg) {
StopHangMonitorTimeout();
if (modal_dialog_count_++ == 0)
- SetEvent(modal_dialog_event_.Get());
+ modal_dialog_event_->Signal();
delegate_->RunBeforeUnloadConfirm(message, reply_msg);
}
@@ -1104,7 +1106,7 @@ void RenderViewHost::OnMsgShowModalHTMLDialog(
IPC::Message* reply_msg) {
StopHangMonitorTimeout();
if (modal_dialog_count_++ == 0)
- SetEvent(modal_dialog_event_.Get());
+ modal_dialog_event_->Signal();
delegate_->ShowModalHTMLDialog(url, width, height, json_arguments, reply_msg);
}
diff --git a/chrome/browser/render_view_host.h b/chrome/browser/render_view_host.h
index f95720e..7b0ef7a 100644
--- a/chrome/browser/render_view_host.h
+++ b/chrome/browser/render_view_host.h
@@ -8,7 +8,7 @@
#include <string>
#include <vector>
-#include "base/scoped_handle.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/render_view_host_delegate.h"
#include "chrome/browser/render_widget_host.h"
#include "chrome/common/page_zoom.h"
@@ -33,6 +33,10 @@ struct WebDropData;
struct WebPreferences;
enum WindowOpenDisposition;
+namespace base {
+class WaitableEvent;
+}
+
namespace gfx {
class Point;
}
@@ -86,7 +90,7 @@ class RenderViewHost : public RenderWidgetHost {
explicit RenderViewHost(SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- HANDLE modal_dialog_event);
+ base::WaitableEvent* modal_dialog_event);
virtual ~RenderViewHost();
SiteInstance* site_instance() const { return instance_; }
@@ -578,7 +582,7 @@ class RenderViewHost : public RenderWidgetHost {
// Handle to an event that's set when the page is showing a modal dialog box
// (or equivalent constrained window). The renderer and plugin processes
// check this to know if they should pump messages/tasks then.
- ScopedHandle modal_dialog_event_;
+ scoped_ptr<base::WaitableEvent> modal_dialog_event_;
// Multiple dialog boxes can be shown before the first one is finished,
// so we keep a counter to know when we can reset the modal dialog event.
@@ -618,7 +622,7 @@ class RenderViewHostFactory {
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- HANDLE modal_dialog_event) = 0;
+ base::WaitableEvent* modal_dialog_event) = 0;
};
#endif // CHROME_BROWSER_RENDER_VIEW_HOST_H__
diff --git a/chrome/browser/render_view_host_delegate.h b/chrome/browser/render_view_host_delegate.h
index 1fd0c41..34aba46 100644
--- a/chrome/browser/render_view_host_delegate.h
+++ b/chrome/browser/render_view_host_delegate.h
@@ -22,6 +22,10 @@ class WebContents;
struct WebDropData;
enum WindowOpenDisposition;
+namespace base {
+class WaitableEvent;
+}
+
namespace IPC {
class Message;
}
@@ -56,7 +60,10 @@ class RenderViewHostDelegate {
//
// Note: this is not called "CreateWindow" because that will clash with
// the Windows function which is actually a #define.
- virtual void CreateNewWindow(int route_id, HANDLE modal_dialog_event) = 0;
+ //
+ // NOTE: this takes ownership of @modal_dialog_event
+ virtual void CreateNewWindow(int route_id,
+ base::WaitableEvent* modal_dialog_event) = 0;
// The page is trying to open a new widget (e.g. a select popup). The
// widget should be created associated with the given route, but it should
diff --git a/chrome/browser/render_view_host_manager.cc b/chrome/browser/render_view_host_manager.cc
index f7edacf..622df9e 100644
--- a/chrome/browser/render_view_host_manager.cc
+++ b/chrome/browser/render_view_host_manager.cc
@@ -15,6 +15,10 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
+namespace base {
+class WaitableEvent;
+}
+
RenderViewHostManager::RenderViewHostManager(
RenderViewHostFactory* render_view_factory,
RenderViewHostDelegate* render_view_delegate,
@@ -37,7 +41,7 @@ RenderViewHostManager::~RenderViewHostManager() {
void RenderViewHostManager::Init(Profile* profile,
SiteInstance* site_instance,
int routing_id,
- HANDLE modal_dialog_event) {
+ base::WaitableEvent* modal_dialog_event) {
// Create a RenderViewHost, once we have an instance. It is important to
// immediately give this SiteInstance to a RenderViewHost so that it is
// ref counted.
@@ -55,7 +59,7 @@ void RenderViewHostManager::Shutdown() {
render_view_host_->Shutdown();
render_view_host_ = NULL;
}
-
+
RenderViewHost* RenderViewHostManager::Navigate(const NavigationEntry& entry) {
RenderViewHost* dest_render_view_host = UpdateRendererStateNavigate(entry);
if (!dest_render_view_host)
@@ -347,7 +351,7 @@ bool RenderViewHostManager::CreatePendingRenderView(SiteInstance* instance) {
RenderViewHost* RenderViewHostManager::CreateRenderViewHost(
SiteInstance* instance,
int routing_id,
- HANDLE modal_dialog_event) {
+ base::WaitableEvent* modal_dialog_event) {
if (render_view_factory_) {
return render_view_factory_->CreateRenderViewHost(
instance, render_view_delegate_, routing_id, modal_dialog_event);
diff --git a/chrome/browser/render_view_host_manager.h b/chrome/browser/render_view_host_manager.h
index 3c2f61d..ee0e16b 100644
--- a/chrome/browser/render_view_host_manager.h
+++ b/chrome/browser/render_view_host_manager.h
@@ -69,7 +69,7 @@ class RenderViewHostManager {
void Init(Profile* profile,
SiteInstance* site_instance,
int routing_id,
- HANDLE modal_dialog_event);
+ base::WaitableEvent* modal_dialog_event);
// Schedules all RenderViewHosts for destruction.
void Shutdown();
@@ -179,7 +179,7 @@ class RenderViewHostManager {
// factory is NULL).
RenderViewHost* CreateRenderViewHost(SiteInstance* instance,
int routing_id,
- HANDLE modal_dialog_event);
+ base::WaitableEvent* modal_dialog_event);
// Replaces the currently shown render_view_host_ with the RenderViewHost in
// the field pointed to by |new_render_view_host|, and then NULLs the field.
diff --git a/chrome/browser/tab_contents/web_contents.cc b/chrome/browser/tab_contents/web_contents.cc
index 77faa55..638d370 100644
--- a/chrome/browser/tab_contents/web_contents.cc
+++ b/chrome/browser/tab_contents/web_contents.cc
@@ -178,7 +178,7 @@ WebContents::WebContents(Profile* profile,
SiteInstance* site_instance,
RenderViewHostFactory* render_view_factory,
int routing_id,
- HANDLE modal_dialog_event)
+ base::WaitableEvent* modal_dialog_event)
: TabContents(TAB_CONTENTS_WEB),
view_(new WebContentsViewWin(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(
diff --git a/chrome/browser/tab_contents/web_contents.h b/chrome/browser/tab_contents/web_contents.h
index 7b44e79..86ce3bf 100644
--- a/chrome/browser/tab_contents/web_contents.h
+++ b/chrome/browser/tab_contents/web_contents.h
@@ -24,6 +24,10 @@ class RenderViewHostFactory;
class RenderWidgetHost;
class WebContentsView;
+namespace base {
+class WaitableEvent;
+}
+
// WebContents represents the contents of a tab that shows web pages. It embeds
// a RenderViewHost (via RenderViewHostManager) to actually display the page.
class WebContents : public TabContents,
@@ -41,7 +45,7 @@ class WebContents : public TabContents,
SiteInstance* instance,
RenderViewHostFactory* render_view_factory,
int routing_id,
- HANDLE modal_dialog_event);
+ base::WaitableEvent* modal_dialog_event);
static void RegisterUserPrefs(PrefService* prefs);
diff --git a/chrome/browser/tab_contents/web_contents_unittest.cc b/chrome/browser/tab_contents/web_contents_unittest.cc
index df018c1..fbb3ad6 100644
--- a/chrome/browser/tab_contents/web_contents_unittest.cc
+++ b/chrome/browser/tab_contents/web_contents_unittest.cc
@@ -82,7 +82,7 @@ class TestRenderViewHost : public RenderViewHost {
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- HANDLE modal_dialog_event)
+ base::WaitableEvent* modal_dialog_event)
: RenderViewHost(instance, delegate, routing_id, modal_dialog_event),
is_loading(false),
is_created(false),
@@ -156,7 +156,7 @@ class TestRenderViewHostFactory : public RenderViewHostFactory {
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- HANDLE modal_dialog_event) {
+ base::WaitableEvent* modal_dialog_event) {
return new TestRenderViewHost(
instance, delegate, routing_id, modal_dialog_event);
}
@@ -217,7 +217,7 @@ class TestWebContents : public WebContents {
RenderViewHost* CreateRenderViewHost(SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
- HANDLE modal_dialog_event) {
+ base::WaitableEvent* modal_dialog_event) {
return new TestRenderViewHost(
instance, delegate, routing_id, modal_dialog_event);
}
diff --git a/chrome/browser/tab_contents/web_contents_view.cc b/chrome/browser/tab_contents/web_contents_view.cc
index d95fd78..c3c8e8b 100644
--- a/chrome/browser/tab_contents/web_contents_view.cc
+++ b/chrome/browser/tab_contents/web_contents_view.cc
@@ -16,7 +16,8 @@ void WebContentsView::RenderWidgetHostDestroyed(RenderWidgetHost* host) {
}
}
-void WebContentsView::CreateNewWindow(int route_id, HANDLE modal_dialog_event) {
+void WebContentsView::CreateNewWindow(int route_id,
+ base::WaitableEvent* modal_dialog_event) {
// Save the created window associated with the route so we can show it later.
pending_contents_[route_id] = CreateNewWindowInternal(route_id,
modal_dialog_event);
diff --git a/chrome/browser/tab_contents/web_contents_view.h b/chrome/browser/tab_contents/web_contents_view.h
index 232b449..dc5362c 100644
--- a/chrome/browser/tab_contents/web_contents_view.h
+++ b/chrome/browser/tab_contents/web_contents_view.h
@@ -24,6 +24,10 @@ class WebContents;
struct WebDropData;
class WebKeyboardEvent;
+namespace base {
+class WaitableEvent;
+}
+
// The WebContentsView is an interface that is implemented by the platform-
// dependent web contents views. The WebContents uses this interface to talk to
// them. View-related messages will also get forwarded directly to this class
@@ -152,8 +156,8 @@ class WebContentsView : public RenderViewHostDelegate::View {
// created objects so that they can be associated with the given routes. When
// they are shown later, we'll look them up again and pass the objects to
// the Show functions rather than the route ID.
- virtual WebContents* CreateNewWindowInternal(int route_id,
- HANDLE modal_dialog_event) = 0;
+ virtual WebContents* CreateNewWindowInternal
+ (int route_id, base::WaitableEvent* modal_dialog_event) = 0;
virtual RenderWidgetHostView* CreateNewWidgetInternal(int route_id,
bool activatable) = 0;
virtual void ShowCreatedWindowInternal(WebContents* new_web_contents,
@@ -167,7 +171,8 @@ class WebContentsView : public RenderViewHostDelegate::View {
// We implement these functions on RenderViewHostDelegate::View directly and
// do some book-keeping associated with the request. The request is then
// forwarded to *Internal which does platform-specific work.
- virtual void CreateNewWindow(int route_id, HANDLE modal_dialog_event);
+ virtual void CreateNewWindow(int route_id,
+ base::WaitableEvent* modal_dialog_event);
virtual void CreateNewWidget(int route_id, bool activatable);
virtual void ShowCreatedWindow(int route_id,
WindowOpenDisposition disposition,
diff --git a/chrome/browser/tab_contents/web_contents_view_win.cc b/chrome/browser/tab_contents/web_contents_view_win.cc
index ab244cc..29af1f6 100644
--- a/chrome/browser/tab_contents/web_contents_view_win.cc
+++ b/chrome/browser/tab_contents/web_contents_view_win.cc
@@ -326,7 +326,7 @@ void WebContentsViewWin::ShowContextMenu(
WebContents* WebContentsViewWin::CreateNewWindowInternal(
int route_id,
- HANDLE modal_dialog_event) {
+ base::WaitableEvent* modal_dialog_event) {
// Create the new web contents. This will automatically create the new
// WebContentsView. In the future, we may want to create the view separately.
WebContents* new_contents =
diff --git a/chrome/browser/tab_contents/web_contents_view_win.h b/chrome/browser/tab_contents/web_contents_view_win.h
index 137674a..a94b601 100644
--- a/chrome/browser/tab_contents/web_contents_view_win.h
+++ b/chrome/browser/tab_contents/web_contents_view_win.h
@@ -48,7 +48,7 @@ class WebContentsViewWin : public WebContentsView,
// Backend implementation of RenderViewHostDelegate::View.
virtual WebContents* CreateNewWindowInternal(
- int route_id, HANDLE modal_dialog_event);
+ int route_id, base::WaitableEvent* modal_dialog_event);
virtual RenderWidgetHostView* CreateNewWidgetInternal(int route_id,
bool activatable);
virtual void ShowCreatedWindowInternal(WebContents* new_web_contents,
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc
index 979418f..539d8a3 100644
--- a/chrome/common/child_process.cc
+++ b/chrome/common/child_process.cc
@@ -10,13 +10,14 @@
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/string_util.h"
+#include "base/waitable_event.h"
#include "chrome/common/chrome_switches.h"
#include "webkit/glue/webkit_glue.h"
ChildProcess* ChildProcess::child_process_;
MessageLoop* ChildProcess::main_thread_loop_;
static base::AtomicRefCount ref_count;
-HANDLE ChildProcess::shutdown_event_;
+base::WaitableEvent* ChildProcess::shutdown_event_;
ChildProcess::ChildProcess() {
@@ -51,7 +52,7 @@ void ChildProcess::OnFinalRelease() {
main_thread_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
-HANDLE ChildProcess::GetShutDownEvent() {
+base::WaitableEvent* ChildProcess::GetShutDownEvent() {
return shutdown_event_;
}
@@ -74,7 +75,7 @@ bool ChildProcess::GlobalInit(const std::wstring &channel_name,
main_thread_loop_ = MessageLoop::current();
// An event that will be signalled when we shutdown.
- shutdown_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
+ shutdown_event_ = new base::WaitableEvent(true, false);
child_process_ = factory->Create(channel_name);
@@ -92,7 +93,7 @@ void ChildProcess::GlobalCleanup() {
// background threads.
// For example, in the renderer the RenderThread instances will be able to
// notice shutdown before the render process begins waiting for them to exit.
- SetEvent(shutdown_event_);
+ shutdown_event_->Signal();
// Destroy the child process first to force all background threads to
// terminate before we bring down other resources. (We null pointers
@@ -103,7 +104,7 @@ void ChildProcess::GlobalCleanup() {
main_thread_loop_ = NULL;
- CloseHandle(shutdown_event_);
+ delete shutdown_event_;
shutdown_event_ = NULL;
}
diff --git a/chrome/common/child_process.h b/chrome/common/child_process.h
index a74205a..4a63efb 100644
--- a/chrome/common/child_process.h
+++ b/chrome/common/child_process.h
@@ -10,6 +10,9 @@
#include "base/basictypes.h"
#include "base/message_loop.h"
+namespace base {
+ class WaitableEvent;
+};
class ChildProcess;
@@ -53,7 +56,7 @@ class ChildProcess {
// up waiting.
// For example, see the renderer code used to implement
// webkit_glue::GetCookies.
- static HANDLE GetShutDownEvent();
+ static base::WaitableEvent* GetShutDownEvent();
// You must call Init after creating this object before it will be valid
ChildProcess();
@@ -80,7 +83,7 @@ class ChildProcess {
// Derived classes can override this to handle any cleanup, called by
// GlobalCleanup.
virtual void Cleanup() {}
- static HANDLE shutdown_event_;
+ static base::WaitableEvent* shutdown_event_;
DISALLOW_EVIL_CONSTRUCTORS(ChildProcess);
};
diff --git a/chrome/common/common.scons b/chrome/common/common.scons
index 86255d8..c59ca6c 100644
--- a/chrome/common/common.scons
+++ b/chrome/common/common.scons
@@ -55,6 +55,7 @@ input_files.extend([
'ipc_channel_proxy.cc',
'ipc_message.cc',
'ipc_message_utils.cc',
+ 'ipc_sync_channel.cc',
'ipc_sync_message.cc',
'jpeg_codec.cc',
'json_value_serializer.cc',
@@ -99,7 +100,6 @@ if env.Bit('windows'):
'gfx/path.cc',
'gfx/text_elider.cc',
'ipc_logging.cc',
- 'ipc_sync_channel.cc',
'jstemplate_builder.cc',
'os_exchange_data.cc',
'plugin_messages.cc',
diff --git a/chrome/common/ipc_logging.h b/chrome/common/ipc_logging.h
index 2736402..567ba84 100644
--- a/chrome/common/ipc_logging.h
+++ b/chrome/common/ipc_logging.h
@@ -5,13 +5,14 @@
#ifndef CHROME_COMMON_IPC_LOGGING_H_
#define CHROME_COMMON_IPC_LOGGING_H_
-#include "base/lock.h"
-#include "base/object_watcher.h"
-#include "base/singleton.h"
#include "chrome/common/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED.
#ifdef IPC_MESSAGE_LOG_ENABLED
+#include "base/lock.h"
+#include "base/object_watcher.h"
+#include "base/singleton.h"
+
class MessageLoop;
namespace IPC {
diff --git a/chrome/common/ipc_message.h b/chrome/common/ipc_message.h
index 8163d4f..040a346 100644
--- a/chrome/common/ipc_message.h
+++ b/chrome/common/ipc_message.h
@@ -11,9 +11,12 @@
#include "base/pickle.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
+#if defined(OS_WIN)
+// TODO(port): IPC message logging hasn't been ported to other platforms yet.
#ifndef NDEBUG
#define IPC_MESSAGE_LOG_ENABLED
#endif
+#endif
namespace IPC {
diff --git a/chrome/common/ipc_sync_channel.cc b/chrome/common/ipc_sync_channel.cc
index 45e42d6..4f1e71f 100644
--- a/chrome/common/ipc_sync_channel.cc
+++ b/chrome/common/ipc_sync_channel.cc
@@ -2,19 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <windows.h>
-
#include "chrome/common/ipc_sync_channel.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/thread_local.h"
-#include "chrome/common/child_process.h"
+#include "base/message_loop.h"
+#include "base/waitable_event.h"
+#include "base/waitable_event_watcher.h"
#include "chrome/common/ipc_logging.h"
#include "chrome/common/ipc_sync_message.h"
+#if !defined(OS_WIN)
+#define INFINITE -1
+#endif
+
using base::TimeDelta;
using base::TimeTicks;
+using base::WaitableEvent;
namespace IPC {
// When we're blocked in a Send(), we need to process incoming synchronous
@@ -34,8 +39,6 @@ namespace IPC {
// SyncChannel objects on the same thread (since one object can receive a
// sync message while another one is blocked).
-class SyncChannel::ReceivedSyncMsgQueue;
-
class SyncChannel::ReceivedSyncMsgQueue :
public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> {
public:
@@ -70,7 +73,7 @@ class SyncChannel::ReceivedSyncMsgQueue :
message_queue_.push_back(QueuedMessage(new Message(msg), context));
}
- SetEvent(dispatch_event_);
+ dispatch_event_.Signal();
if (!was_task_pending) {
listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
this, &ReceivedSyncMsgQueue::DispatchMessagesTask));
@@ -143,7 +146,7 @@ class SyncChannel::ReceivedSyncMsgQueue :
}
}
- HANDLE dispatch_event() { return dispatch_event_; }
+ WaitableEvent* dispatch_event() { return &dispatch_event_; }
MessageLoop* listener_message_loop() { return listener_message_loop_; }
// Holds a pointer to the per-thread ReceivedSyncMsgQueue object.
@@ -167,9 +170,9 @@ class SyncChannel::ReceivedSyncMsgQueue :
// See the comment in SyncChannel::SyncChannel for why this event is created
// as manual reset.
ReceivedSyncMsgQueue() :
- dispatch_event_(CreateEvent(NULL, TRUE, FALSE, NULL)),
- task_pending_(false),
+ dispatch_event_(true, false),
listener_message_loop_(MessageLoop::current()),
+ task_pending_(false),
listener_count_(0) {
}
@@ -181,14 +184,14 @@ class SyncChannel::ReceivedSyncMsgQueue :
};
typedef std::deque<QueuedMessage> SyncMessageQueue;
- SyncMessageQueue message_queue_;
+ SyncMessageQueue message_queue_;
std::vector<QueuedMessage> received_replies_;
// Set when we got a synchronous message that we must respond to as the
// sender needs its reply before it can reply to our original synchronous
// message.
- ScopedHandle dispatch_event_;
+ WaitableEvent dispatch_event_;
MessageLoop* listener_message_loop_;
Lock message_lock_;
bool task_pending_;
@@ -202,10 +205,10 @@ SyncChannel::SyncContext::SyncContext(
Channel::Listener* listener,
MessageFilter* filter,
MessageLoop* ipc_thread,
- HANDLE shutdown_event)
+ WaitableEvent* shutdown_event)
: ChannelProxy::Context(listener, filter, ipc_thread),
- shutdown_event_(shutdown_event),
- received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()){
+ received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
+ shutdown_event_(shutdown_event) {
}
SyncChannel::SyncContext::~SyncContext() {
@@ -217,13 +220,13 @@ SyncChannel::SyncContext::~SyncContext() {
// we know how to deserialize the reply. Returns a handle that's set when
// the reply has arrived.
void SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
- // The event is created as manual reset because in between SetEvent and
+ // The event is created as manual reset because in between Signal and
// OnObjectSignalled, another Send can happen which would stop the watcher
// from being called. The event would get watched later, when the nested
// Send completes, so the event will need to remain set.
PendingSyncMsg pending(SyncMessage::GetMessageId(*sync_msg),
sync_msg->GetReplyDeserializer(),
- CreateEvent(NULL, TRUE, FALSE, NULL));
+ new WaitableEvent(true, false));
AutoLock auto_lock(deserializers_lock_);
deserializers_.push_back(pending);
}
@@ -234,7 +237,8 @@ bool SyncChannel::SyncContext::Pop() {
AutoLock auto_lock(deserializers_lock_);
PendingSyncMsg msg = deserializers_.back();
delete msg.deserializer;
- CloseHandle(msg.done_event);
+ delete msg.done_event;
+ msg.done_event = NULL;
deserializers_.pop_back();
result = msg.send_result;
}
@@ -250,12 +254,12 @@ bool SyncChannel::SyncContext::Pop() {
return result;
}
-HANDLE SyncChannel::SyncContext::GetSendDoneEvent() {
+WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
AutoLock auto_lock(deserializers_lock_);
return deserializers_.back().done_event;
}
-HANDLE SyncChannel::SyncContext::GetDispatchEvent() {
+WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() {
return received_sync_msgs_->dispatch_event();
}
@@ -274,7 +278,7 @@ bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
deserializers_.back().send_result = deserializers_.back().deserializer->
SerializeOutputParameters(*msg);
}
- SetEvent(deserializers_.back().done_event);
+ deserializers_.back().done_event->Signal();
return true;
}
@@ -327,7 +331,7 @@ void SyncChannel::SyncContext::OnSendTimeout(int message_id) {
PendingSyncMessageQueue::iterator iter;
for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
if (iter->id == message_id) {
- SetEvent(iter->done_event);
+ iter->done_event->Signal();
break;
}
}
@@ -337,11 +341,11 @@ void SyncChannel::SyncContext::CancelPendingSends() {
AutoLock auto_lock(deserializers_lock_);
PendingSyncMessageQueue::iterator iter;
for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++)
- SetEvent(iter->done_event);
+ iter->done_event->Signal();
}
-void SyncChannel::SyncContext::OnObjectSignaled(HANDLE object) {
- DCHECK(object == shutdown_event_);
+void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) {
+ DCHECK(event == shutdown_event_);
// Process shut down before we can get a reply to a synchronous message.
// Cancel pending Send calls, which will end up setting the send done event.
CancelPendingSends();
@@ -351,7 +355,8 @@ void SyncChannel::SyncContext::OnObjectSignaled(HANDLE object) {
SyncChannel::SyncChannel(
const std::wstring& channel_id, Channel::Mode mode,
Channel::Listener* listener, MessageFilter* filter,
- MessageLoop* ipc_message_loop, bool create_pipe_now, HANDLE shutdown_event)
+ MessageLoop* ipc_message_loop, bool create_pipe_now,
+ WaitableEvent* shutdown_event)
: ChannelProxy(
channel_id, mode, ipc_message_loop,
new SyncContext(listener, filter, ipc_message_loop, shutdown_event),
@@ -362,7 +367,7 @@ SyncChannel::SyncChannel(
// message loop running under it or not, so we wouldn't know whether to
// stop or keep watching. So we always watch it, and create the event as
// manual reset since the object watcher might otherwise reset the event
- // when we're doing a WaitForMultipleObjects.
+ // when we're doing a WaitMany.
dispatch_watcher_.StartWatching(sync_context()->GetDispatchEvent(), this);
}
@@ -381,7 +386,7 @@ bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
// *this* might get deleted in WaitForReply.
scoped_refptr<SyncContext> context(sync_context());
- if (WaitForSingleObject(context->shutdown_event(), 0) == WAIT_OBJECT_0) {
+ if (context->shutdown_event()->IsSignaled()) {
delete message;
return false;
}
@@ -390,7 +395,7 @@ bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
context->Push(sync_msg);
int message_id = SyncMessage::GetMessageId(*sync_msg);
- HANDLE pump_messages_event = sync_msg->pump_messages_event();
+ WaitableEvent* pump_messages_event = sync_msg->pump_messages_event();
ChannelProxy::Send(message);
@@ -409,22 +414,25 @@ bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
return context->Pop();
}
-void SyncChannel::WaitForReply(HANDLE pump_messages_event) {
+void SyncChannel::WaitForReply(WaitableEvent* pump_messages_event) {
while (true) {
- HANDLE objects[] = { sync_context()->GetDispatchEvent(),
- sync_context()->GetSendDoneEvent(),
- pump_messages_event };
- uint32 count = pump_messages_event ? 3: 2;
- DWORD result = WaitForMultipleObjects(count, objects, FALSE, INFINITE);
- if (result == WAIT_OBJECT_0) {
+ WaitableEvent* objects[] = {
+ sync_context()->GetDispatchEvent(),
+ sync_context()->GetSendDoneEvent(),
+ pump_messages_event
+ };
+
+ unsigned count = pump_messages_event ? 3: 2;
+ unsigned result = WaitableEvent::WaitMany(objects, count);
+ if (result == 0 /* dispatch event */) {
// We're waiting for a reply, but we received a blocking synchronous
// call. We must process it or otherwise a deadlock might occur.
- ResetEvent(sync_context()->GetDispatchEvent());
+ sync_context()->GetDispatchEvent()->Reset();
sync_context()->DispatchMessages();
continue;
}
- if (result == WAIT_OBJECT_0 + 2)
+ if (result == 2 /* pump_messages_event */)
WaitForReplyWithNestedMessageLoop(); // Start a nested message loop.
break;
@@ -432,7 +440,7 @@ void SyncChannel::WaitForReply(HANDLE pump_messages_event) {
}
void SyncChannel::WaitForReplyWithNestedMessageLoop() {
- HANDLE old_done_event = send_done_watcher_.GetWatchedObject();
+ WaitableEvent* old_done_event = send_done_watcher_.GetWatchedEvent();
send_done_watcher_.StopWatching();
send_done_watcher_.StartWatching(sync_context()->GetSendDoneEvent(), this);
bool old_state = MessageLoop::current()->NestableTasksAllowed();
@@ -443,17 +451,17 @@ void SyncChannel::WaitForReplyWithNestedMessageLoop() {
send_done_watcher_.StartWatching(old_done_event, this);
}
-void SyncChannel::OnObjectSignaled(HANDLE object) {
- HANDLE dispatch_event = sync_context()->GetDispatchEvent();
- if (object == dispatch_event) {
+void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) {
+ WaitableEvent* dispatch_event = sync_context()->GetDispatchEvent();
+ if (event == dispatch_event) {
// The call to DispatchMessages might delete this object, so reregister
// the object watcher first.
- ResetEvent(dispatch_event);
+ dispatch_event->Reset();
dispatch_watcher_.StartWatching(dispatch_event, this);
sync_context()->DispatchMessages();
} else {
// We got the reply, timed out or the process shutdown.
- DCHECK(object == sync_context()->GetSendDoneEvent());
+ DCHECK(event == sync_context()->GetSendDoneEvent());
MessageLoop::current()->Quit();
}
}
diff --git a/chrome/common/ipc_sync_channel.h b/chrome/common/ipc_sync_channel.h
index 6c03745..725fb33 100644
--- a/chrome/common/ipc_sync_channel.h
+++ b/chrome/common/ipc_sync_channel.h
@@ -5,19 +5,20 @@
#ifndef CHROME_COMMON_IPC_SYNC_SENDER_H__
#define CHROME_COMMON_IPC_SYNC_SENDER_H__
-#include <windows.h>
#include <string>
#include <deque>
#include "base/basictypes.h"
#include "base/lock.h"
-#include "base/object_watcher.h"
#include "base/ref_counted.h"
#include "base/scoped_handle.h"
+#include "base/waitable_event.h"
+#include "base/waitable_event_watcher.h"
#include "chrome/common/ipc_channel_proxy.h"
namespace IPC {
class SyncMessage;
+class MessageReplyDeserializer;
// This is similar to IPC::ChannelProxy, with the added feature of supporting
// sending synchronous messages.
@@ -26,12 +27,12 @@ class SyncMessage;
// is running and it's used to send a message, then it will use the invalid
// message loop pointer to proxy it to the ipc thread.
class SyncChannel : public ChannelProxy,
- public base::ObjectWatcher::Delegate {
+ public base::WaitableEventWatcher::Delegate {
public:
SyncChannel(const std::wstring& channel_id, Channel::Mode mode,
Channel::Listener* listener, MessageFilter* filter,
MessageLoop* ipc_message_loop, bool create_pipe_now,
- HANDLE shutdown_event);
+ base::WaitableEvent* shutdown_event);
~SyncChannel();
virtual bool Send(Message* message);
@@ -50,12 +51,12 @@ class SyncChannel : public ChannelProxy,
// can be deleted while it's being used in a different thread. See
// ChannelProxy::Context for more information.
class SyncContext : public Context,
- public base::ObjectWatcher::Delegate {
+ public base::WaitableEventWatcher::Delegate {
public:
SyncContext(Channel::Listener* listener,
MessageFilter* filter,
MessageLoop* ipc_thread,
- HANDLE shutdown_event);
+ base::WaitableEvent* shutdown_event);
~SyncContext();
@@ -69,11 +70,11 @@ class SyncChannel : public ChannelProxy,
// Returns an event that's set when the send is complete, timed out or the
// process shut down.
- HANDLE GetSendDoneEvent();
+ base::WaitableEvent* GetSendDoneEvent();
// Returns an event that's set when an incoming message that's not the reply
// needs to get dispatched (by calling SyncContext::DispatchMessages).
- HANDLE GetDispatchEvent();
+ base::WaitableEvent* GetDispatchEvent();
void DispatchMessages();
@@ -86,7 +87,7 @@ class SyncChannel : public ChannelProxy,
// times out.
void OnSendTimeout(int message_id);
- HANDLE shutdown_event() { return shutdown_event_; }
+ base::WaitableEvent* shutdown_event() { return shutdown_event_; }
private:
// IPC::ChannelProxy methods that we override.
@@ -103,17 +104,18 @@ class SyncChannel : public ChannelProxy,
// Cancels all pending Send calls.
void CancelPendingSends();
- // ObjectWatcher::Delegate implementation.
- virtual void OnObjectSignaled(HANDLE object);
+ // WaitableEventWatcher::Delegate implementation.
+ virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
// When sending a synchronous message, this structure contains an object that
// knows how to deserialize the response.
struct PendingSyncMsg {
- PendingSyncMsg(int id, IPC::MessageReplyDeserializer* d, HANDLE e) :
+ PendingSyncMsg(int id, IPC::MessageReplyDeserializer* d,
+ base::WaitableEvent* e) :
id(id), deserializer(d), done_event(e), send_result(false) { }
int id;
IPC::MessageReplyDeserializer* deserializer;
- HANDLE done_event;
+ base::WaitableEvent* done_event;
bool send_result;
};
@@ -123,19 +125,19 @@ class SyncChannel : public ChannelProxy,
scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_;
- HANDLE shutdown_event_;
- base::ObjectWatcher shutdown_watcher_;
+ base::WaitableEvent* shutdown_event_;
+ base::WaitableEventWatcher shutdown_watcher_;
};
private:
- // ObjectWatcher::Delegate implementation.
- virtual void OnObjectSignaled(HANDLE object);
+ // WaitableEventWatcher::Delegate implementation.
+ virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
SyncContext* sync_context() { return reinterpret_cast<SyncContext*>(context()); }
// Both these functions wait for a reply, timeout or process shutdown. The
// latter one also runs a nested message loop in the meantime.
- void WaitForReply(HANDLE pump_messages_event);
+ void WaitForReply(base::WaitableEvent* pump_messages_event);
// Runs a nested message loop until a reply arrives, times out, or the process
// shuts down.
@@ -144,8 +146,8 @@ class SyncChannel : public ChannelProxy,
bool sync_messages_with_no_timeout_allowed_;
// Used to signal events between the IPC and listener threads.
- base::ObjectWatcher send_done_watcher_;
- base::ObjectWatcher dispatch_watcher_;
+ base::WaitableEventWatcher send_done_watcher_;
+ base::WaitableEventWatcher dispatch_watcher_;
DISALLOW_EVIL_CONSTRUCTORS(SyncChannel);
};
diff --git a/chrome/common/ipc_sync_message.cc b/chrome/common/ipc_sync_message.cc
index 4a851e5..a07ea15 100644
--- a/chrome/common/ipc_sync_message.cc
+++ b/chrome/common/ipc_sync_message.cc
@@ -9,8 +9,9 @@
#endif
#include <stack>
-#include "chrome/common/ipc_sync_message.h"
#include "base/logging.h"
+#include "base/waitable_event.h"
+#include "chrome/common/ipc_sync_message.h"
namespace IPC {
@@ -20,7 +21,7 @@ uint32 SyncMessage::next_id_ = 0;
#if defined(OS_WIN)
// TODO(playmobil): reinstantiate once ObjectWatcher is ported.
// A dummy handle used by EnableMessagePumping.
-HANDLE dummy_event = ::CreateEvent(NULL, TRUE, TRUE, NULL);
+base::WaitableEvent* dummy_event = new base::WaitableEvent(true, true);
#endif
SyncMessage::SyncMessage(
@@ -29,11 +30,8 @@ SyncMessage::SyncMessage(
PriorityValue priority,
MessageReplyDeserializer* deserializer)
: Message(routing_id, type, priority),
- deserializer_(deserializer)
-#if defined(OS_WIN)
- // TODO(playmobil): reinstantiate once ObjectWatcher is ported.
- , pump_messages_event_(NULL)
-#endif
+ deserializer_(deserializer),
+ pump_messages_event_(NULL)
{
set_sync();
set_unblock(true);
diff --git a/chrome/common/ipc_sync_message.h b/chrome/common/ipc_sync_message.h
index 116e6c7..034de07 100644
--- a/chrome/common/ipc_sync_message.h
+++ b/chrome/common/ipc_sync_message.h
@@ -12,6 +12,10 @@
#include "base/basictypes.h"
#include "chrome/common/ipc_message.h"
+namespace base {
+class WaitableEvent;
+}
+
namespace IPC {
class MessageReplyDeserializer;
@@ -26,15 +30,13 @@ class SyncMessage : public Message {
// for deleting the deserializer when they're done.
MessageReplyDeserializer* GetReplyDeserializer();
-// TODO(playmobil): reimplement on POSIX.
-#if defined(OS_WIN)
// If this message can cause the receiver to block while waiting for user
// input (i.e. by calling MessageBox), then the caller needs to pump window
// messages and dispatch asynchronous messages while waiting for the reply.
- // If this handle is passed in, then window messages will start being pumped
+ // If this event is passed in, then window messages will start being pumped
// when it's set. Note that this behavior will continue even if the event is
- // later reset. The handle must be valid until after the Send call returns.
- void set_pump_messages_event(HANDLE event) {
+ // later reset. The event must be valid until after the Send call returns.
+ void set_pump_messages_event(base::WaitableEvent* event) {
pump_messages_event_ = event;
if (event) {
header()->flags |= PUMPING_MSGS_BIT;
@@ -47,8 +49,9 @@ class SyncMessage : public Message {
// or set_pump_messages_event but not both.
void EnableMessagePumping();
- HANDLE pump_messages_event() const { return pump_messages_event_; }
-#endif // defined(OS_WIN)
+ base::WaitableEvent* pump_messages_event() const {
+ return pump_messages_event_;
+ }
// Returns true if the message is a reply to the given request id.
static bool IsMessageReplyTo(const Message& msg, int request_id);
@@ -73,9 +76,7 @@ class SyncMessage : public Message {
static bool WriteSyncHeader(Message* msg, const SyncHeader& header);
MessageReplyDeserializer* deserializer_;
-#if defined(OS_WIN)
- HANDLE pump_messages_event_;
-#endif
+ base::WaitableEvent* pump_messages_event_;
static uint32 next_id_; // for generation of unique ids
};
diff --git a/chrome/plugin/npobject_proxy.cc b/chrome/plugin/npobject_proxy.cc
index 7df4e5c..3c4f811 100644
--- a/chrome/plugin/npobject_proxy.cc
+++ b/chrome/plugin/npobject_proxy.cc
@@ -4,6 +4,7 @@
#include "chrome/plugin/npobject_proxy.h"
+#include "base/waitable_event.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/win_util.h"
#include "chrome/plugin/npobject_util.h"
@@ -48,7 +49,7 @@ NPObjectProxy::NPObjectProxy(
PluginChannelBase* channel,
int route_id,
void* npobject_ptr,
- HANDLE modal_dialog_event)
+ base::WaitableEvent* modal_dialog_event)
: channel_(channel),
route_id_(route_id),
npobject_ptr_(npobject_ptr),
@@ -67,7 +68,7 @@ NPObjectProxy::~NPObjectProxy() {
NPObject* NPObjectProxy::Create(PluginChannelBase* channel,
int route_id,
void* npobject_ptr,
- HANDLE modal_dialog_event) {
+ base::WaitableEvent* modal_dialog_event) {
NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(
NPN_CreateObject(0, &npclass_proxy_));
obj->proxy = new NPObjectProxy(
@@ -178,7 +179,7 @@ bool NPObjectProxy::NPInvokePrivate(NPP npp,
// messages are pumped).
msg->set_pump_messages_event(proxy->modal_dialog_event_);
- HANDLE modal_dialog_event_handle = proxy->modal_dialog_event_;
+ base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
proxy->Send(msg);
@@ -237,7 +238,7 @@ bool NPObjectProxy::NPGetProperty(NPObject *obj,
CreateNPIdentifierParam(name, &name_param);
NPVariant_Param param;
- HANDLE modal_dialog_event_handle = proxy->modal_dialog_event_;
+ base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
scoped_refptr<PluginChannelBase> channel(proxy->channel_);
proxy->Send(new NPObjectMsg_GetProperty(
proxy->route_id(), name_param, &param, &result));
@@ -367,7 +368,7 @@ bool NPObjectProxy::NPNEvaluate(NPP npp,
// the reasoning behind setting the pump messages event in the sync message.
msg->set_pump_messages_event(proxy->modal_dialog_event_);
scoped_refptr<PluginChannelBase> channel(proxy->channel_);
- HANDLE modal_dialog_event_handle = proxy->modal_dialog_event_;
+ base::WaitableEvent* modal_dialog_event_handle = proxy->modal_dialog_event_;
proxy->Send(msg);
// Send may delete proxy.
proxy = NULL;
diff --git a/chrome/plugin/npobject_proxy.h b/chrome/plugin/npobject_proxy.h
index 4157717..dcc4d01 100644
--- a/chrome/plugin/npobject_proxy.h
+++ b/chrome/plugin/npobject_proxy.h
@@ -16,6 +16,10 @@ class PluginChannelBase;
struct NPObject;
struct NPVariant_Param;
+namespace base {
+class WaitableEvent;
+}
+
// When running a plugin in a different process from the renderer, we need to
// proxy calls to NPObjects across process boundaries. This happens both ways,
// as a plugin can get an NPObject for the window, and a page can get an
@@ -29,10 +33,11 @@ class NPObjectProxy : public IPC::Channel::Listener,
public:
~NPObjectProxy();
+ // modal_dialog_event_ is must be valid for the lifetime of the NPObjectProxy.
static NPObject* Create(PluginChannelBase* channel,
int route_id,
void* npobject_ptr,
- HANDLE modal_dialog_event);
+ base::WaitableEvent* modal_dialog_event);
// IPC::Message::Sender implementation:
bool Send(IPC::Message* msg);
@@ -93,7 +98,7 @@ class NPObjectProxy : public IPC::Channel::Listener,
NPObjectProxy(PluginChannelBase* channel,
int route_id,
void* npobject_ptr,
- HANDLE modal_dialog_event);
+ base::WaitableEvent* modal_dialog_event);
// IPC::Channel::Listener implementation:
void OnMessageReceived(const IPC::Message& msg);
@@ -109,7 +114,7 @@ class NPObjectProxy : public IPC::Channel::Listener,
int route_id_;
void* npobject_ptr_;
scoped_refptr<PluginChannelBase> channel_;
- HANDLE modal_dialog_event_;
+ base::WaitableEvent* modal_dialog_event_;
};
#endif // CHROME_PLUGIN_NPOBJECT_PROXY_H_
diff --git a/chrome/plugin/npobject_util.cc b/chrome/plugin/npobject_util.cc
index 8936471..f5283f9 100644
--- a/chrome/plugin/npobject_util.cc
+++ b/chrome/plugin/npobject_util.cc
@@ -200,7 +200,7 @@ void CreateNPVariantParam(const NPVariant& variant,
void CreateNPVariant(const NPVariant_Param& param,
PluginChannelBase* channel,
NPVariant* result,
- HANDLE modal_dialog_event) {
+ base::WaitableEvent* modal_dialog_event) {
switch (param.type) {
case NPVARIANT_PARAM_VOID:
result->type = NPVariantType_Void;
diff --git a/chrome/plugin/npobject_util.h b/chrome/plugin/npobject_util.h
index cc9347e..ba74a6b 100644
--- a/chrome/plugin/npobject_util.h
+++ b/chrome/plugin/npobject_util.h
@@ -22,6 +22,9 @@ struct NPIdentifier_Param;
struct NPVariant_Param;
typedef void *NPIdentifier;
+namespace base {
+class WaitableEvent;
+}
// Needs to be called early in the plugin process lifetime, before any
// plugin instances are initialized.
@@ -52,7 +55,7 @@ void CreateNPVariantParam(const NPVariant& variant,
void CreateNPVariant(const NPVariant_Param& param,
PluginChannelBase* channel,
NPVariant* result,
- HANDLE modal_dialog_event);
+ base::WaitableEvent* modal_dialog_event);
// Given a plugin's HWND, returns an event associated with the WebContents
// that's set when inside a messagebox. This tells the plugin process that
diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc
index 0bd6ed8..bb7ee5c 100644
--- a/chrome/plugin/webplugin_proxy.cc
+++ b/chrome/plugin/webplugin_proxy.cc
@@ -8,6 +8,7 @@
#include "base/scoped_handle.h"
#include "base/shared_memory.h"
#include "base/singleton.h"
+#include "base/waitable_event.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/win_util.h"
@@ -47,7 +48,7 @@ WebPluginProxy::WebPluginProxy(
FALSE,
0);
DCHECK(result) << "Couldn't duplicate the modal dialog handle for the plugin.";
- modal_dialog_event_.Set(event);
+ modal_dialog_event_.reset(new base::WaitableEvent(event));
}
WebPluginProxy::~WebPluginProxy() {
@@ -121,7 +122,7 @@ NPObject* WebPluginProxy::GetWindowScriptNPObject() {
window_npobject_ = NPObjectProxy::Create(channel_,
npobject_route_id,
npobject_ptr,
- modal_dialog_event_.Get());
+ modal_dialog_event_.get());
return window_npobject_;
}
@@ -141,7 +142,7 @@ NPObject* WebPluginProxy::GetPluginElement() {
plugin_element_ = NPObjectProxy::Create(channel_,
npobject_route_id,
npobject_ptr,
- modal_dialog_event_.Get());
+ modal_dialog_event_.get());
return plugin_element_;
}
@@ -170,8 +171,9 @@ void WebPluginProxy::ShowModalHTMLDialog(const GURL& url, int width, int height,
// Create a new event and set it. This forces us to pump messages while
// waiting for a response (which won't come until the dialog is closed). This
// avoids a deadlock.
- ScopedHandle event(CreateEvent(NULL, FALSE, TRUE, NULL));
- msg->set_pump_messages_event(event);
+ scoped_ptr<base::WaitableEvent> event(
+ new base::WaitableEvent(false, true));
+ msg->set_pump_messages_event(event.get());
Send(msg);
}
diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h
index c2cefc7..7828abf 100644
--- a/chrome/plugin/webplugin_proxy.h
+++ b/chrome/plugin/webplugin_proxy.h
@@ -8,12 +8,17 @@
#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/scoped_handle.h"
+#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
#include "base/timer.h"
#include "chrome/common/ipc_message.h"
#include "chrome/common/chrome_plugin_api.h"
#include "webkit/glue/webplugin.h"
+namespace base {
+class WaitableEvent;
+}
+
class PluginChannel;
class WebPluginDelegateImpl;
@@ -126,7 +131,7 @@ class WebPluginProxy : public WebPlugin {
gfx::Rect damaged_rect_;
bool waiting_for_paint_;
uint32 cp_browsing_context_;
- ScopedHandle modal_dialog_event_;
+ scoped_ptr<base::WaitableEvent> modal_dialog_event_;
// Variables used for desynchronized windowless plugin painting. See note in
// webplugin_delegate_proxy.h for how this works.
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index 311e865..e0108e4 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -198,8 +198,10 @@ void RenderThread::OnCreateNewView(HWND parent_hwnd,
int32 view_id) {
// TODO(darin): once we have a RenderThread per RenderView, this will need to
// change to assert that we are not creating more than one view.
+ base::WaitableEvent* waitable_event =
+ new base::WaitableEvent(modal_dialog_event);
RenderView::Create(
- this, parent_hwnd, modal_dialog_event, MSG_ROUTING_NONE, webkit_prefs,
+ this, parent_hwnd, waitable_event, MSG_ROUTING_NONE, webkit_prefs,
new SharedRenderViewCounter(0), view_id);
}
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 708453f..7c85b65 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -197,7 +197,7 @@ RenderView::~RenderView() {
RenderView* RenderView::Create(
RenderThreadBase* render_thread,
HWND parent_hwnd,
- HANDLE modal_dialog_event,
+ base::WaitableEvent* modal_dialog_event,
int32 opener_id,
const WebPreferences& webkit_prefs,
SharedRenderViewCounter* counter,
@@ -245,7 +245,7 @@ void RenderView::JSOutOfMemory() {
}
void RenderView::Init(HWND parent_hwnd,
- HANDLE modal_dialog_event,
+ base::WaitableEvent* modal_dialog_event,
int32 opener_id,
const WebPreferences& webkit_prefs,
SharedRenderViewCounter* counter,
@@ -287,7 +287,7 @@ void RenderView::Init(HWND parent_hwnd,
}
host_window_ = parent_hwnd;
- modal_dialog_event_.Set(modal_dialog_event);
+ modal_dialog_event_.reset(modal_dialog_event);
CommandLine command_line;
enable_dom_automation_ =
@@ -1648,7 +1648,7 @@ bool RenderView::RunJavaScriptMessage(int type,
IPC::SyncMessage* msg = new ViewHostMsg_RunJavaScriptMessage(
routing_id_, message, default_value, type, &success, result);
- msg->set_pump_messages_event(modal_dialog_event_);
+ msg->set_pump_messages_event(modal_dialog_event_.get());
Send(msg);
return success;
@@ -1669,7 +1669,7 @@ bool RenderView::RunBeforeUnloadConfirm(WebView* webview,
IPC::SyncMessage* msg = new ViewHostMsg_RunBeforeUnloadConfirm(
routing_id_, message, &success, &ignored_result);
- msg->set_pump_messages_event(modal_dialog_event_);
+ msg->set_pump_messages_event(modal_dialog_event_.get());
Send(msg);
return success;
@@ -1716,7 +1716,7 @@ void RenderView::ShowModalHTMLDialog(const GURL& url, int width, int height,
IPC::SyncMessage* msg = new ViewHostMsg_ShowModalHTMLDialog(
routing_id_, url, width, height, json_arguments, json_retval);
- msg->set_pump_messages_event(modal_dialog_event_);
+ msg->set_pump_messages_event(modal_dialog_event_.get());
Send(msg);
}
@@ -1803,8 +1803,10 @@ WebView* RenderView::CreateWebView(WebView* webview, bool user_gesture) {
// The WebView holds a reference to this new RenderView
const WebPreferences& prefs = webview->GetPreferences();
+ base::WaitableEvent* waitable_event =
+ new base::WaitableEvent(modal_dialog_event);
RenderView* view = RenderView::Create(render_thread_,
- NULL, modal_dialog_event, routing_id_,
+ NULL, waitable_event, routing_id_,
prefs, shared_popup_counter_,
routing_id);
view->set_opened_by_user_gesture(user_gesture);
@@ -1938,7 +1940,7 @@ void RenderView::RunModal(WebWidget* webwidget) {
IPC::SyncMessage* msg = new ViewHostMsg_RunModal(routing_id_);
- msg->set_pump_messages_event(modal_dialog_event_);
+ msg->set_pump_messages_event(modal_dialog_event_.get());
Send(msg);
}
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index ef0307d..26e3b97 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -48,6 +48,10 @@ class WebPluginDelegate;
class WebPluginDelegateProxy;
enum WebRequestCachePolicy;
+namespace base {
+class WaitableEvent;
+}
+
namespace webkit_glue {
struct FileUploadData;
}
@@ -85,7 +89,7 @@ class RenderView : public RenderWidget,
static RenderView* Create(
RenderThreadBase* render_thread,
HWND parent_hwnd,
- HANDLE modal_dialog_event,
+ base::WaitableEvent* modal_dialog_event, // takes ownership
int32 opener_id,
const WebPreferences& webkit_prefs,
SharedRenderViewCounter* counter,
@@ -108,8 +112,8 @@ class RenderView : public RenderWidget,
return host_window_;
}
- HANDLE modal_dialog_event() {
- return modal_dialog_event_.Get();
+ base::WaitableEvent* modal_dialog_event() {
+ return modal_dialog_event_.get();
}
// IPC::Channel::Listener
@@ -328,7 +332,7 @@ class RenderView : public RenderWidget,
// set to 'MSG_ROUTING_NONE' if the true ID is not yet known. In this case,
// CompleteInit must be called later with the true ID.
void Init(HWND parent,
- HANDLE modal_dialog_event,
+ base::WaitableEvent* modal_dialog_event, // takes ownership
int32 opener_id,
const WebPreferences& webkit_prefs,
SharedRenderViewCounter* counter,
@@ -659,7 +663,7 @@ class RenderView : public RenderWidget,
// Handle to an event that's set when the page is showing a modal dialog (or
// equivalent constrained window). The renderer and any plugin processes
// check this to know if they should pump messages/tasks then.
- ScopedHandle modal_dialog_event_;
+ scoped_ptr<base::WaitableEvent> modal_dialog_event_;
// Document width when in print CSS media type. 0 otherwise.
int printed_document_width_;
diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc
index 22ece4b..f4c61a2 100644
--- a/chrome/renderer/webplugin_delegate_proxy.cc
+++ b/chrome/renderer/webplugin_delegate_proxy.cc
@@ -246,7 +246,7 @@ bool WebPluginDelegateProxy::Initialize(const GURL& url, char** argn,
}
}
params.load_manually = load_manually;
- params.modal_dialog_event = render_view_->modal_dialog_event();
+ params.modal_dialog_event = render_view_->modal_dialog_event()->handle();
plugin_ = plugin;
@@ -571,7 +571,7 @@ bool WebPluginDelegateProxy::HandleEvent(NPEvent* event, WebCursor* cursor) {
IPC::SyncMessage* message = new PluginMsg_HandleEvent(instance_id_,
*event, &handled,
cursor);
- message->set_pump_messages_event(modal_loop_pump_messages_event_);
+ message->set_pump_messages_event(modal_loop_pump_messages_event_.get());
Send(message);
return handled;
}
@@ -587,7 +587,7 @@ void WebPluginDelegateProxy::OnSetWindow(
plugin_->SetWindow(window, modal_loop_pump_messages_event);
DCHECK(modal_loop_pump_messages_event_ == NULL);
- modal_loop_pump_messages_event_.Set(modal_loop_pump_messages_event);
+ modal_loop_pump_messages_event_.reset();
}
void WebPluginDelegateProxy::OnCancelResource(int id) {
diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h
index 4f8b757..521b763 100644
--- a/chrome/renderer/webplugin_delegate_proxy.h
+++ b/chrome/renderer/webplugin_delegate_proxy.h
@@ -23,6 +23,10 @@ struct PluginHostMsg_RouteToFrame_Params;
class RenderView;
class SkBitmap;
+namespace base {
+class WaitableEvent;
+}
+
namespace skia {
class PlatformCanvasWin;
}
@@ -167,7 +171,7 @@ class WebPluginDelegateProxy : public WebPluginDelegate,
// Event passed in by the plugin process and is used to decide if
// messages need to be pumped in the NPP_HandleEvent sync call.
- ScopedHandle modal_loop_pump_messages_event_;
+ scoped_ptr<base::WaitableEvent> modal_loop_pump_messages_event_;
// Bitmap for crashed plugin
SkBitmap* sad_plugin_;
diff --git a/chrome/test/testing_browser_process.h b/chrome/test/testing_browser_process.h
index 4e756f1..76f349c 100644
--- a/chrome/test/testing_browser_process.h
+++ b/chrome/test/testing_browser_process.h
@@ -15,17 +15,17 @@
#include <string>
#include "base/string_util.h"
+#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/notification_service.h"
#include "base/logging.h"
class TestingBrowserProcess : public BrowserProcess {
public:
- TestingBrowserProcess() {
-#if defined(OS_WIN)
- shutdown_event_ = ::CreateEvent(NULL, TRUE, FALSE, NULL);
-#endif
+ TestingBrowserProcess()
+ : shutdown_event_(new base::WaitableEvent(true, false)) {
}
+
virtual ~TestingBrowserProcess() {
}
@@ -122,15 +122,11 @@ class TestingBrowserProcess : public BrowserProcess {
virtual MemoryModel memory_model() { return HIGH_MEMORY_MODEL; }
-#if defined(OS_WIN)
- virtual HANDLE shutdown_event() { return shutdown_event_; }
-#endif
+ virtual base::WaitableEvent* shutdown_event() { return shutdown_event_.get(); }
private:
NotificationService notification_service_;
-#if defined(OS_WIN)
- HANDLE shutdown_event_;
-#endif
+ scoped_ptr<base::WaitableEvent> shutdown_event_;
DISALLOW_COPY_AND_ASSIGN(TestingBrowserProcess);
};