1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
//===--- LockingHelpers.h - Utilities to help test locks ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef LOCKING_HELPERS_H
#define LOCKING_HELPERS_H
#include "ThreadingHelpers.h"
// Test that a Mutex object can be locked and unlocked from a single thread
template <typename M>
void basicLockable(M &mutex) {
// We can lock, unlock, lock and unlock an unlocked lock
mutex.lock();
mutex.unlock();
mutex.lock();
mutex.unlock();
}
// Test that a Mutex object's try_lock() method works.
template <typename M>
void tryLockable(M &mutex) {
bool ret;
// We can lock an unlocked lock
ret = mutex.try_lock();
ASSERT_TRUE(ret);
// We cannot lock a locked lock
ret = mutex.try_lock();
#if SWIFT_THREADING_NONE
// Noop since none threading mode always succeeds getting lock
(void)ret;
#else
ASSERT_FALSE(ret);
#endif
mutex.unlock();
}
// Test that a Mutex object can be locked and unlocked
template <typename M>
void basicLockableThreaded(M &mutex) {
int count1 = 0;
int count2 = 0;
threadedExecute(10, [&](int) {
for (int j = 0; j < 50; ++j) {
mutex.lock();
auto count = count2;
count1++;
count2 = count + 1;
mutex.unlock();
}
});
ASSERT_EQ(count1, 500);
ASSERT_EQ(count2, 500);
}
#if SWIFT_THREADING_NONE
template <typename M>
void lockableThreaded(M &mutex) {
// Noop since none threading mode always succeeds getting lock
}
#else
// More extensive tests
template <typename M>
void lockableThreaded(M &mutex) {
mutex.lock();
threadedExecute(5, [&](int) { ASSERT_FALSE(mutex.try_lock()); });
mutex.unlock();
threadedExecute(1, [&](int) {
ASSERT_TRUE(mutex.try_lock());
mutex.unlock();
});
int count1 = 0;
int count2 = 0;
threadedExecute(10, [&](int) {
for (int j = 0; j < 50; ++j) {
if (mutex.try_lock()) {
auto count = count2;
count1++;
count2 = count + 1;
mutex.unlock();
} else {
j--;
}
}
});
ASSERT_EQ(count1, 500);
ASSERT_EQ(count2, 500);
}
#endif
// Test a scoped lock implementation
template <typename SL, typename M>
void scopedLockThreaded(M &mutex) {
int count1 = 0;
int count2 = 0;
threadedExecute(10, [&](int) {
for (int j = 0; j < 50; ++j) {
SL guard(mutex);
auto count = count2;
count1++;
count2 = count + 1;
}
});
ASSERT_EQ(count1, 500);
ASSERT_EQ(count2, 500);
}
// Test a scoped unlock nested in a scoped lock
template <typename SL, typename SU, typename M>
void scopedUnlockUnderScopedLockThreaded(M &mutex) {
int count1 = 0;
int count2 = 0;
int badCount = 0;
threadedExecute(10, [&](int) {
for (int j = 0; j < 50; ++j) {
SL guard(mutex);
{
SU unguard(mutex);
badCount++;
}
auto count = count2;
count1++;
count2 = count + 1;
}
});
ASSERT_EQ(count1, 500);
ASSERT_EQ(count2, 500);
}
// Test a critical section
template <typename M>
void criticalSectionThreaded(M &mutex) {
int count1 = 0;
int count2 = 0;
threadedExecute(10, [&](int) {
for (int j = 0; j < 50; ++j) {
mutex.withLock([&] {
auto count = count2;
count1++;
count2 = count + 1;
});
}
});
ASSERT_EQ(count1, 500);
ASSERT_EQ(count2, 500);
}
#endif
|