1  //===-- tsan_mutexset.h -----------------------------------------*- C++ -*-===//
       2  //
       3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
       4  // See https://llvm.org/LICENSE.txt for license information.
       5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
       6  //
       7  //===----------------------------------------------------------------------===//
       8  //
       9  // This file is a part of ThreadSanitizer (TSan), a race detector.
      10  //
      11  // MutexSet holds the set of mutexes currently held by a thread.
      12  //===----------------------------------------------------------------------===//
      13  #ifndef TSAN_MUTEXSET_H
      14  #define TSAN_MUTEXSET_H
      15  
      16  #include "tsan_defs.h"
      17  
      18  namespace __tsan {
      19  
      20  class MutexSet {
      21   public:
      22    // Holds limited number of mutexes.
      23    // The oldest mutexes are discarded on overflow.
      24    static constexpr uptr kMaxSize = 16;
      25    struct Desc {
      26      uptr addr;
      27      StackID stack_id;
      28      u32 seq;
      29      u32 count;
      30      bool write;
      31  
      32      Desc() { internal_memset(this, 0, sizeof(*this)); }
      33      Desc(const Desc& other) { *this = other; }
      34      Desc& operator=(const MutexSet::Desc& other) {
      35        internal_memcpy(this, &other, sizeof(*this));
      36        return *this;
      37      }
      38    };
      39  
      40    MutexSet();
      41    void Reset();
      42    void AddAddr(uptr addr, StackID stack_id, bool write);
      43    void DelAddr(uptr addr, bool destroy = false);
      44    uptr Size() const;
      45    Desc Get(uptr i) const;
      46  
      47   private:
      48  #if !SANITIZER_GO
      49    u32 seq_ = 0;
      50    uptr size_ = 0;
      51    Desc descs_[kMaxSize];
      52  
      53    void RemovePos(uptr i);
      54  #endif
      55  };
      56  
      57  // MutexSet is too large to live on stack.
      58  // DynamicMutexSet can be use used to create local MutexSet's.
      59  class DynamicMutexSet {
      60   public:
      61    DynamicMutexSet();
      62    ~DynamicMutexSet();
      63    MutexSet* operator->() { return ptr_; }
      64    operator MutexSet*() { return ptr_; }
      65    DynamicMutexSet(const DynamicMutexSet&) = delete;
      66    DynamicMutexSet& operator=(const DynamicMutexSet&) = delete;
      67  
      68   private:
      69    MutexSet* ptr_;
      70  #if SANITIZER_GO
      71    MutexSet set_;
      72  #endif
      73  };
      74  
      75  // Go does not have mutexes, so do not spend memory and time.
      76  // (Go sync.Mutex is actually a semaphore -- can be unlocked
      77  // in different goroutine).
      78  #if SANITIZER_GO
      79  MutexSet::MutexSet() {}
      80  void MutexSet::Reset() {}
      81  void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {}
      82  void MutexSet::DelAddr(uptr addr, bool destroy) {}
      83  uptr MutexSet::Size() const { return 0; }
      84  MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); }
      85  DynamicMutexSet::DynamicMutexSet() : ptr_(&set_) {}
      86  DynamicMutexSet::~DynamicMutexSet() {}
      87  #endif
      88  
      89  }  // namespace __tsan
      90  
      91  #endif  // TSAN_MUTEXSET_H