GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/fence.h Lines: 27 29 93.1 %
Date: 2019-02-03 02:48:13 Branches: 2 4 50.0 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#ifndef CVMFS_FENCE_H_
6
#define CVMFS_FENCE_H_
7
8
#include "atomic.h"
9
#include "gtest/gtest_prod.h"
10
#include "util/posix.h"
11
#include "util/single_copy.h"
12
13
#ifdef CVMFS_NAMESPACE_GUARD
14
namespace CVMFS_NAMESPACE_GUARD {
15
#endif
16
17
/**
18
 * A Fence can be used to protect critical regions where blocking is a very
19
 * rare operation.  When the Fence is not blocked, entering and leaving a
20
 * critical region requires only a 1-2 atomic operations.  In order to block
21
 * the fence, no new threads can enter a critical region.  When all entered
22
 * regions are left, the fence is blocked.  Waiting is done through slow busy
23
 * wait.
24
 */
25
class Fence : public SingleCopy {
26
  FRIEND_TEST(T_Fence, Basics);
27
28
 public:
29
4
  Fence() {
30
4
    atomic_init64(&counter_);
31
4
    atomic_init32(&blocking_);
32
4
  }
33
34
8
  void Enter() {
35
16
    while (atomic_read32(&blocking_)) {
36
      SafeSleepMs(kBusyWaitBackoffMs);
37
    }
38
8
    atomic_inc64(&counter_);
39
8
  }
40
41
8
  void Leave() {
42
8
    atomic_dec64(&counter_);
43
8
  }
44
45
8
  void Close() {
46
8
    atomic_cas32(&blocking_, 0, 1);
47
8
  }
48
49
  /**
50
   * Close and let live critical regions exit
51
   */
52
4
  void Drain() {
53
4
    Close();
54
8
    while (atomic_read64(&counter_) > 0) {
55
      SafeSleepMs(kBusyWaitBackoffMs);
56
    }
57
4
  }
58
59
8
  void Open() {
60
8
    atomic_cas32(&blocking_, 1, 0);
61
8
  }
62
63
 private:
64
  static const unsigned kBusyWaitBackoffMs = 100;
65
66
  /**
67
   * Number of active critical regions.
68
   */
69
  atomic_int64 counter_;
70
71
  /**
72
   * A boolean that indicates if the fence is blocked.
73
   */
74
  atomic_int32 blocking_;
75
};
76
77
78
/**
79
 * RAII wrapper in case an entire function or code block should be protected
80
 * by a fence.
81
 */
82
class FenceGuard {
83
 public:
84
4
  explicit FenceGuard(Fence *fence) : fence_(fence) {
85
4
    fence_->Enter();
86
4
  }
87
4
  ~FenceGuard() {
88
4
    fence_->Leave();
89
4
  }
90
 private:
91
  Fence *fence_;
92
};
93
94
#ifdef CVMFS_NAMESPACE_GUARD
95
}  // namespace CVMFS_NAMESPACE_GUARD
96
#endif
97
98
#endif  // CVMFS_FENCE_H_