/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#include <folly/test/DeterministicSchedule.h>
+
+#include <assert.h>
+
#include <algorithm>
#include <list>
#include <mutex>
#include <random>
-#include <utility>
#include <unordered_map>
-#include <assert.h>
+#include <utility>
+
+#include <folly/Random.h>
namespace folly {
namespace test {
FOLLY_TLS sem_t* DeterministicSchedule::tls_sem;
FOLLY_TLS DeterministicSchedule* DeterministicSchedule::tls_sched;
FOLLY_TLS unsigned DeterministicSchedule::tls_threadId;
+thread_local AuxAct DeterministicSchedule::tls_aux_act;
+AuxChk DeterministicSchedule::aux_chk;
// access is protected by futexLock
static std::unordered_map<detail::Futex<DeterministicAtomic>*,
DeterministicSchedule::DeterministicSchedule(
const std::function<int(int)>& scheduler)
- : scheduler_(scheduler), nextThreadId_(1) {
+ : scheduler_(scheduler), nextThreadId_(1), step_(0) {
assert(tls_sem == nullptr);
assert(tls_sched == nullptr);
+ assert(tls_aux_act == nullptr);
tls_sem = new sem_t;
sem_init(tls_sem, 0, 1);
void adjustPermSize(size_t numActive) {
if (perm_.size() > numActive) {
- perm_.erase(std::remove_if(perm_.begin(), perm_.end(), [=](size_t x) {
- return x >= numActive;
- }), perm_.end());
+ perm_.erase(std::remove_if(perm_.begin(),
+ perm_.end(),
+ [=](size_t x) { return x >= numActive; }),
+ perm_.end());
} else {
while (perm_.size() < numActive) {
perm_.push_back(perm_.size());
if (!sched) {
return;
}
+ sem_post(sched->sems_[sched->scheduler_(sched->sems_.size())]);
+}
+void DeterministicSchedule::afterSharedAccess(bool success) {
+ auto sched = tls_sched;
+ if (!sched) {
+ return;
+ }
+ sched->callAux(success);
sem_post(sched->sems_[sched->scheduler_(sched->sems_.size())]);
}
if (tls_sched) {
return tls_sched->scheduler_(n);
}
- return std::rand() % n;
+ return Random::rand32() % n;
}
-int DeterministicSchedule::getcpu(unsigned* cpu, unsigned* node, void* unused) {
+int DeterministicSchedule::getcpu(unsigned* cpu,
+ unsigned* node,
+ void* /* unused */) {
if (!tls_threadId && tls_sched) {
beforeSharedAccess();
tls_threadId = tls_sched->nextThreadId_++;
return 0;
}
+void DeterministicSchedule::setAuxAct(AuxAct& aux) {
+ tls_aux_act = aux;
+}
+
+void DeterministicSchedule::setAuxChk(AuxChk& aux) {
+ aux_chk = aux;
+}
+
+void DeterministicSchedule::clearAuxChk() {
+ aux_chk = nullptr;
+}
+
sem_t* DeterministicSchedule::beforeThreadCreate() {
sem_t* s = new sem_t;
sem_init(s, 0, 0);
delete tls_sem;
tls_sem = nullptr;
tls_sched = nullptr;
+ tls_aux_act = nullptr;
}
void DeterministicSchedule::join(std::thread& child) {
child.join();
}
+void DeterministicSchedule::callAux(bool success) {
+ ++step_;
+ if (tls_aux_act) {
+ tls_aux_act(success);
+ tls_aux_act = nullptr;
+ }
+ if (aux_chk) {
+ aux_chk(step_);
+ }
+}
+
void DeterministicSchedule::post(sem_t* sem) {
beforeSharedAccess();
sem_post(sem);
bool hasTimeout = absSystemTimeout != nullptr || absSteadyTimeout != nullptr;
bool awoken = false;
FutexResult result = FutexResult::AWOKEN;
- int futexErrno = 0;
DeterministicSchedule::beforeSharedAccess();
FOLLY_TEST_DSCHED_VLOG(this << ".futexWait(" << std::hex << expected
<< ", .., " << std::hex << waitMask
<< ") beginning..");
futexLock.lock();
- if (data == expected) {
+ if (this->data == expected) {
auto& queue = futexQueues[this];
queue.emplace_back(waitMask, &awoken);
auto ours = queue.end();
char const* resultStr = "?";
switch (result) {
- case FutexResult::AWOKEN:
- resultStr = "AWOKEN";
- break;
- case FutexResult::TIMEDOUT:
- resultStr = "TIMEDOUT";
- break;
- case FutexResult::INTERRUPTED:
- resultStr = "INTERRUPTED";
- break;
- case FutexResult::VALUE_CHANGED:
- resultStr = "VALUE_CHANGED";
- break;
+ case FutexResult::AWOKEN:
+ resultStr = "AWOKEN";
+ break;
+ case FutexResult::TIMEDOUT:
+ resultStr = "TIMEDOUT";
+ break;
+ case FutexResult::INTERRUPTED:
+ resultStr = "INTERRUPTED";
+ break;
+ case FutexResult::VALUE_CHANGED:
+ resultStr = "VALUE_CHANGED";
+ break;
}
FOLLY_TEST_DSCHED_VLOG(this << ".futexWait(" << std::hex << expected
<< ", .., " << std::hex << waitMask << ") -> "
}
template <>
-const AccessSpreader<test::DeterministicAtomic>
- AccessSpreader<test::DeterministicAtomic>::stripeByCore(
- CacheLocality::system<>().numCachesByLevel.front());
-
-template <>
-const AccessSpreader<test::DeterministicAtomic>
- AccessSpreader<test::DeterministicAtomic>::stripeByChip(
- CacheLocality::system<>().numCachesByLevel.back());
-
-template <>
-AccessSpreaderArray<test::DeterministicAtomic, 128>
- AccessSpreaderArray<test::DeterministicAtomic, 128>::sharedInstance = {};
-
-template <>
-Getcpu::Func AccessSpreader<test::DeterministicAtomic>::pickGetcpuFunc(
- size_t numStripes) {
+Getcpu::Func AccessSpreader<test::DeterministicAtomic>::pickGetcpuFunc() {
return &DeterministicSchedule::getcpu;
}
}