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. GetPort(const PortRef & port_ref)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 AssertNoPortsLockedOnCurrentThread()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 port()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