ipc/chromium/src/base/waitable_event_posix.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 #include "base/waitable_event.h"
     7 #include "base/condition_variable.h"
     8 #include "base/lock.h"
     9 #include "base/message_loop.h"
    11 // -----------------------------------------------------------------------------
    12 // A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't
    13 // support cross-process events (where one process can signal an event which
    14 // others are waiting on). Because of this, we can avoid having one thread per
    15 // listener in several cases.
    16 //
    17 // The WaitableEvent maintains a list of waiters, protected by a lock. Each
    18 // waiter is either an async wait, in which case we have a Task and the
    19 // MessageLoop to run it on, or a blocking wait, in which case we have the
    20 // condition variable to signal.
    21 //
    22 // Waiting involves grabbing the lock and adding oneself to the wait list. Async
    23 // waits can be canceled, which means grabbing the lock and removing oneself
    24 // from the list.
    25 //
    26 // Waiting on multiple events is handled by adding a single, synchronous wait to
    27 // the wait-list of many events. An event passes a pointer to itself when
    28 // firing a waiter and so we can store that pointer to find out which event
    29 // triggered.
    30 // -----------------------------------------------------------------------------
    32 namespace base {
    34 // -----------------------------------------------------------------------------
    35 // This is just an abstract base class for waking the two types of waiters
    36 // -----------------------------------------------------------------------------
    37 WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled)
    38     : kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) {
    39 }
    41 WaitableEvent::~WaitableEvent() {
    42 }
    44 void WaitableEvent::Reset() {
    45   AutoLock locked(kernel_->lock_);
    46   kernel_->signaled_ = false;
    47 }
    49 void WaitableEvent::Signal() {
    50   AutoLock locked(kernel_->lock_);
    52   if (kernel_->signaled_)
    53     return;
    55   if (kernel_->manual_reset_) {
    56     SignalAll();
    57     kernel_->signaled_ = true;
    58   } else {
    59     // In the case of auto reset, if no waiters were woken, we remain
    60     // signaled.
    61     if (!SignalOne())
    62       kernel_->signaled_ = true;
    63   }
    64 }
    66 bool WaitableEvent::IsSignaled() {
    67   AutoLock locked(kernel_->lock_);
    69   const bool result = kernel_->signaled_;
    70   if (result && !kernel_->manual_reset_)
    71     kernel_->signaled_ = false;
    72   return result;
    73 }
    75 // -----------------------------------------------------------------------------
    76 // Synchronous waits
    78 // -----------------------------------------------------------------------------
    79 // This is an synchronous waiter. The thread is waiting on the given condition
    80 // variable and the fired flag in this object.
    81 // -----------------------------------------------------------------------------
    82 class SyncWaiter : public WaitableEvent::Waiter {
    83  public:
    84   SyncWaiter(ConditionVariable* cv, Lock* lock)
    85       : fired_(false),
    86         cv_(cv),
    87         lock_(lock),
    88         signaling_event_(NULL) {
    89   }
    91   bool Fire(WaitableEvent *signaling_event) {
    92     lock_->Acquire();
    93       const bool previous_value = fired_;
    94       fired_ = true;
    95       if (!previous_value)
    96         signaling_event_ = signaling_event;
    97     lock_->Release();
    99     if (previous_value)
   100       return false;
   102     cv_->Broadcast();
   104     // SyncWaiters are stack allocated on the stack of the blocking thread.
   105     return true;
   106   }
   108   WaitableEvent* signaled_event() const {
   109     return signaling_event_;
   110   }
   112   // ---------------------------------------------------------------------------
   113   // These waiters are always stack allocated and don't delete themselves. Thus
   114   // there's no problem and the ABA tag is the same as the object pointer.
   115   // ---------------------------------------------------------------------------
   116   bool Compare(void* tag) {
   117     return this == tag;
   118   }
   120   // ---------------------------------------------------------------------------
   121   // Called with lock held.
   122   // ---------------------------------------------------------------------------
   123   bool fired() const {
   124     return fired_;
   125   }
   127   // ---------------------------------------------------------------------------
   128   // During a TimedWait, we need a way to make sure that an auto-reset
   129   // WaitableEvent doesn't think that this event has been signaled between
   130   // unlocking it and removing it from the wait-list. Called with lock held.
   131   // ---------------------------------------------------------------------------
   132   void Disable() {
   133     fired_ = true;
   134   }
   136  private:
   137   bool fired_;
   138   ConditionVariable *const cv_;
   139   Lock *const lock_;
   140   WaitableEvent* signaling_event_;  // The WaitableEvent which woke us
   141 };
   143 bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
   144   const TimeTicks end_time(TimeTicks::Now() + max_time);
   145   const bool finite_time = max_time.ToInternalValue() >= 0;
   147   kernel_->lock_.Acquire();
   148     if (kernel_->signaled_) {
   149       if (!kernel_->manual_reset_) {
   150         // In this case we were signaled when we had no waiters. Now that
   151         // someone has waited upon us, we can automatically reset.
   152         kernel_->signaled_ = false;
   153       }
   155       kernel_->lock_.Release();
   156       return true;
   157     }
   159     Lock lock;
   160     lock.Acquire();
   161     ConditionVariable cv(&lock);
   162     SyncWaiter sw(&cv, &lock);
   164     Enqueue(&sw);
   165   kernel_->lock_.Release();
   166   // We are violating locking order here by holding the SyncWaiter lock but not
   167   // the WaitableEvent lock. However, this is safe because we don't lock @lock_
   168   // again before unlocking it.
   170   for (;;) {
   171     const TimeTicks current_time(TimeTicks::Now());
   173     if (sw.fired() || (finite_time && current_time >= end_time)) {
   174       const bool return_value = sw.fired();
   176       // We can't acquire @lock_ before releasing @lock (because of locking
   177       // order), however, inbetween the two a signal could be fired and @sw
   178       // would accept it, however we will still return false, so the signal
   179       // would be lost on an auto-reset WaitableEvent. Thus we call Disable
   180       // which makes sw::Fire return false.
   181       sw.Disable();
   182       lock.Release();
   184       kernel_->lock_.Acquire();
   185         kernel_->Dequeue(&sw, &sw);
   186       kernel_->lock_.Release();
   188       return return_value;
   189     }
   191     if (finite_time) {
   192       const TimeDelta max_wait(end_time - current_time);
   193       cv.TimedWait(max_wait);
   194     } else {
   195       cv.Wait();
   196     }
   197   }
   198 }
   200 bool WaitableEvent::Wait() {
   201   return TimedWait(TimeDelta::FromSeconds(-1));
   202 }
   204 // -----------------------------------------------------------------------------
   207 // -----------------------------------------------------------------------------
   208 // Synchronous waiting on multiple objects.
   210 static bool  // StrictWeakOrdering
   211 cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a,
   212              const std::pair<WaitableEvent*, unsigned> &b) {
   213   return a.first < b.first;
   214 }
   216 // static
   217 size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
   218                                size_t count) {
   219   DCHECK(count) << "Cannot wait on no events";
   221   // We need to acquire the locks in a globally consistent order. Thus we sort
   222   // the array of waitables by address. We actually sort a pairs so that we can
   223   // map back to the original index values later.
   224   std::vector<std::pair<WaitableEvent*, size_t> > waitables;
   225   waitables.reserve(count);
   226   for (size_t i = 0; i < count; ++i)
   227     waitables.push_back(std::make_pair(raw_waitables[i], i));
   229   DCHECK_EQ(count, waitables.size());
   231   sort(waitables.begin(), waitables.end(), cmp_fst_addr);
   233   // The set of waitables must be distinct. Since we have just sorted by
   234   // address, we can check this cheaply by comparing pairs of consecutive
   235   // elements.
   236   for (size_t i = 0; i < waitables.size() - 1; ++i) {
   237     DCHECK(waitables[i].first != waitables[i+1].first);
   238   }
   240   Lock lock;
   241   ConditionVariable cv(&lock);
   242   SyncWaiter sw(&cv, &lock);
   244   const size_t r = EnqueueMany(&waitables[0], count, &sw);
   245   if (r) {
   246     // One of the events is already signaled. The SyncWaiter has not been
   247     // enqueued anywhere. EnqueueMany returns the count of remaining waitables
   248     // when the signaled one was seen, so the index of the signaled event is
   249     // @count - @r.
   250     return waitables[count - r].second;
   251   }
   253   // At this point, we hold the locks on all the WaitableEvents and we have
   254   // enqueued our waiter in them all.
   255   lock.Acquire();
   256     // Release the WaitableEvent locks in the reverse order
   257     for (size_t i = 0; i < count; ++i) {
   258       waitables[count - (1 + i)].first->kernel_->lock_.Release();
   259     }
   261     for (;;) {
   262       if (sw.fired())
   263         break;
   265       cv.Wait();
   266     }
   267   lock.Release();
   269   // The address of the WaitableEvent which fired is stored in the SyncWaiter.
   270   WaitableEvent *const signaled_event = sw.signaled_event();
   271   // This will store the index of the raw_waitables which fired.
   272   size_t signaled_index = 0;
   274   // Take the locks of each WaitableEvent in turn (except the signaled one) and
   275   // remove our SyncWaiter from the wait-list
   276   for (size_t i = 0; i < count; ++i) {
   277     if (raw_waitables[i] != signaled_event) {
   278       raw_waitables[i]->kernel_->lock_.Acquire();
   279         // There's no possible ABA issue with the address of the SyncWaiter here
   280         // because it lives on the stack. Thus the tag value is just the pointer
   281         // value again.
   282         raw_waitables[i]->kernel_->Dequeue(&sw, &sw);
   283       raw_waitables[i]->kernel_->lock_.Release();
   284     } else {
   285       signaled_index = i;
   286     }
   287   }
   289   return signaled_index;
   290 }
   292 // -----------------------------------------------------------------------------
   293 // If return value == 0:
   294 //   The locks of the WaitableEvents have been taken in order and the Waiter has
   295 //   been enqueued in the wait-list of each. None of the WaitableEvents are
   296 //   currently signaled
   297 // else:
   298 //   None of the WaitableEvent locks are held. The Waiter has not been enqueued
   299 //   in any of them and the return value is the index of the first WaitableEvent
   300 //   which was signaled, from the end of the array.
   301 // -----------------------------------------------------------------------------
   302 // static
   303 size_t WaitableEvent::EnqueueMany
   304     (std::pair<WaitableEvent*, size_t>* waitables,
   305      size_t count, Waiter* waiter) {
   306   if (!count)
   307     return 0;
   309   waitables[0].first->kernel_->lock_.Acquire();
   310     if (waitables[0].first->kernel_->signaled_) {
   311       if (!waitables[0].first->kernel_->manual_reset_)
   312         waitables[0].first->kernel_->signaled_ = false;
   313       waitables[0].first->kernel_->lock_.Release();
   314       return count;
   315     }
   317     const size_t r = EnqueueMany(waitables + 1, count - 1, waiter);
   318     if (r) {
   319       waitables[0].first->kernel_->lock_.Release();
   320     } else {
   321       waitables[0].first->Enqueue(waiter);
   322     }
   324     return r;
   325 }
   327 // -----------------------------------------------------------------------------
   330 // -----------------------------------------------------------------------------
   331 // Private functions...
   333 // -----------------------------------------------------------------------------
   334 // Wake all waiting waiters. Called with lock held.
   335 // -----------------------------------------------------------------------------
   336 bool WaitableEvent::SignalAll() {
   337   bool signaled_at_least_one = false;
   339   for (std::list<Waiter*>::iterator
   340        i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) {
   341     if ((*i)->Fire(this))
   342       signaled_at_least_one = true;
   343   }
   345   kernel_->waiters_.clear();
   346   return signaled_at_least_one;
   347 }
   349 // ---------------------------------------------------------------------------
   350 // Try to wake a single waiter. Return true if one was woken. Called with lock
   351 // held.
   352 // ---------------------------------------------------------------------------
   353 bool WaitableEvent::SignalOne() {
   354   for (;;) {
   355     if (kernel_->waiters_.empty())
   356       return false;
   358     const bool r = (*kernel_->waiters_.begin())->Fire(this);
   359     kernel_->waiters_.pop_front();
   360     if (r)
   361       return true;
   362   }
   363 }
   365 // -----------------------------------------------------------------------------
   366 // Add a waiter to the list of those waiting. Called with lock held.
   367 // -----------------------------------------------------------------------------
   368 void WaitableEvent::Enqueue(Waiter* waiter) {
   369   kernel_->waiters_.push_back(waiter);
   370 }
   372 // -----------------------------------------------------------------------------
   373 // Remove a waiter from the list of those waiting. Return true if the waiter was
   374 // actually removed. Called with lock held.
   375 // -----------------------------------------------------------------------------
   376 bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
   377   for (std::list<Waiter*>::iterator
   378        i = waiters_.begin(); i != waiters_.end(); ++i) {
   379     if (*i == waiter && (*i)->Compare(tag)) {
   380       waiters_.erase(i);
   381       return true;
   382     }
   383   }
   385   return false;
   386 }
   388 // -----------------------------------------------------------------------------
   390 }  // namespace base

mercurial