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 #include "mojo/core/ports/port_locker.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "mojo/core/ports/port.h"
     10 
     11 #if DCHECK_IS_ON()
     12 #include "base/threading/thread_local.h"
     13 #endif
     14 
     15 namespace mojo {
     16 namespace core {
     17 namespace ports {
     18 
     19 namespace {
     20 
     21 #if DCHECK_IS_ON()
     22 void UpdateTLS(PortLocker* old_locker, PortLocker* new_locker) {
     23   // Sanity check when DCHECK is on to make sure there is only ever one
     24   // PortLocker extant on the current thread.
     25   static auto* tls = new base::ThreadLocalPointer<PortLocker>();
     26   DCHECK_EQ(old_locker, tls->Get());
     27   tls->Set(new_locker);
     28 }
     29 #endif
     30 
     31 }  // namespace
     32 
     33 PortLocker::PortLocker(const PortRef** port_refs, size_t num_ports)
     34     : port_refs_(port_refs), num_ports_(num_ports) {
     35 #if DCHECK_IS_ON()
     36   UpdateTLS(nullptr, this);
     37 #endif
     38 
     39   // Sort the ports by address to lock them in a globally consistent order.
     40   std::sort(
     41       port_refs_, port_refs_ + num_ports_,
     42       [](const PortRef* a, const PortRef* b) { return a->port() < b->port(); });
     43   for (size_t i = 0; i < num_ports_; ++i) {
     44     // TODO(crbug.com/725605): Remove this CHECK.
     45     CHECK(port_refs_[i]->port());
     46     port_refs_[i]->port()->lock_.Acquire();
     47   }
     48 }
     49 
     50 PortLocker::~PortLocker() {
     51   for (size_t i = 0; i < num_ports_; ++i)
     52     port_refs_[i]->port()->lock_.Release();
     53 
     54 #if DCHECK_IS_ON()
     55   UpdateTLS(this, nullptr);
     56 #endif
     57 }
     58 
     59 #if DCHECK_IS_ON()
     60 // static
     61 void PortLocker::AssertNoPortsLockedOnCurrentThread() {
     62   // Forces a DCHECK if the TLS PortLocker is anything other than null.
     63   UpdateTLS(nullptr, nullptr);
     64 }
     65 #endif
     66 
     67 SinglePortLocker::SinglePortLocker(const PortRef* port_ref)
     68     : port_ref_(port_ref), locker_(&port_ref_, 1) {}
     69 
     70 SinglePortLocker::~SinglePortLocker() = default;
     71 
     72 }  // namespace ports
     73 }  // namespace core
     74 }  // namespace mojo
     75