Home | History | Annotate | Download | only in ports
      1 // Copyright 2017 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef MOJO_CORE_PORTS_PORT_LOCKER_H_
      6 #define MOJO_CORE_PORTS_PORT_LOCKER_H_
      7 
      8 #include <stdint.h>
      9 
     10 #include "base/macros.h"
     11 #include "mojo/core/ports/port_ref.h"
     12 
     13 namespace mojo {
     14 namespace core {
     15 namespace ports {
     16 
     17 class Port;
     18 class PortRef;
     19 
     20 // A helper which must be used to acquire individual Port locks. Any given
     21 // thread may have at most one of these alive at any time. This ensures that
     22 // when multiple ports are locked, they're locked in globally consistent order.
     23 //
     24 // Port locks are acquired upon construction of this object and released upon
     25 // destruction.
     26 class PortLocker {
     27  public:
     28   // Constructs a PortLocker over a sequence of |num_ports| contiguous
     29   // |PortRef*|s. The sequence may be reordered by this constructor, and upon
     30   // return, all referenced ports' locks are held.
     31   PortLocker(const PortRef** port_refs, size_t num_ports);
     32   ~PortLocker();
     33 
     34   // Provides safe access to a PortRef's Port. Note that in release builds this
     35   // doesn't do anything other than pass through to the private accessor on
     36   // |port_ref|, but it does force callers to go through a PortLocker to get to
     37   // the state, thus minimizing the likelihood that they'll go and do something
     38   // stupid.
     39   Port* GetPort(const PortRef& port_ref) const {
     40 #if DCHECK_IS_ON()
     41     // Sanity check when DCHECK is on to ensure this is actually a port whose
     42     // lock is held by this PortLocker.
     43     bool is_port_locked = false;
     44     for (size_t i = 0; i < num_ports_ && !is_port_locked; ++i)
     45       if (port_refs_[i]->port() == port_ref.port())
     46         is_port_locked = true;
     47     DCHECK(is_port_locked);
     48 #endif
     49     return port_ref.port();
     50   }
     51 
     52 // A helper which can be used to verify that no Port locks are held on the
     53 // current thread. In non-DCHECK builds this is a no-op.
     54 #if DCHECK_IS_ON()
     55   static void AssertNoPortsLockedOnCurrentThread();
     56 #else
     57   static void AssertNoPortsLockedOnCurrentThread() {}
     58 #endif
     59 
     60  private:
     61   const PortRef** const port_refs_;
     62   const size_t num_ports_;
     63 
     64   DISALLOW_COPY_AND_ASSIGN(PortLocker);
     65 };
     66 
     67 // Convenience wrapper for a PortLocker that locks a single port.
     68 class SinglePortLocker {
     69  public:
     70   explicit SinglePortLocker(const PortRef* port_ref);
     71   ~SinglePortLocker();
     72 
     73   Port* port() const { return locker_.GetPort(*port_ref_); }
     74 
     75  private:
     76   const PortRef* port_ref_;
     77   PortLocker locker_;
     78 
     79   DISALLOW_COPY_AND_ASSIGN(SinglePortLocker);
     80 };
     81 
     82 }  // namespace ports
     83 }  // namespace core
     84 }  // namespace mojo
     85 
     86 #endif  // MOJO_CORE_PORTS_PORT_LOCKER_H_
     87