222 lines
3.9 KiB
C++
222 lines
3.9 KiB
C++
#pragma once
|
|
|
|
#include "../relacy/relacy_std.hpp"
|
|
|
|
|
|
|
|
struct test_mutex : rl::test_suite<test_mutex, 3>
|
|
{
|
|
rl::mutex mtx;
|
|
rl::var<int> data;
|
|
|
|
void before()
|
|
{
|
|
data($) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
RL_ASSERT(data($) == 3);
|
|
}
|
|
|
|
void thread(unsigned /*index*/)
|
|
{
|
|
mtx.lock($);
|
|
data($) += 1;
|
|
mtx.unlock($);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
struct test_deadlock : rl::test_suite<test_deadlock, 2, rl::test_result_deadlock>
|
|
{
|
|
rl::mutex mtx1;
|
|
rl::mutex mtx2;
|
|
|
|
void thread(unsigned index)
|
|
{
|
|
if (0 == index)
|
|
{
|
|
mtx1.lock($);
|
|
mtx2.lock($);
|
|
mtx1.unlock($);
|
|
mtx2.unlock($);
|
|
}
|
|
else
|
|
{
|
|
mtx2.lock($);
|
|
mtx1.lock($);
|
|
mtx1.unlock($);
|
|
mtx2.unlock($);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
struct test_deadlock2 : rl::test_suite<test_deadlock2, 2, rl::test_result_deadlock>
|
|
{
|
|
std::mutex m;
|
|
std::atomic<int> f;
|
|
|
|
void before()
|
|
{
|
|
f($) = 0;
|
|
}
|
|
|
|
void thread(unsigned index)
|
|
{
|
|
if (index)
|
|
{
|
|
m.lock($);
|
|
f($) = 1;
|
|
for (int i = 0; i != 100; ++i)
|
|
rl::yield(1, $);
|
|
}
|
|
else
|
|
{
|
|
while (0 == f($))
|
|
rl::yield(1, $);
|
|
m.lock($);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
struct test_mutex_destuction : rl::test_suite<test_mutex_destuction, 1, rl::test_result_destroying_owned_mutex>
|
|
{
|
|
void thread(unsigned)
|
|
{
|
|
std::mutex* m = new std::mutex;
|
|
m->lock($);
|
|
delete m;
|
|
}
|
|
};
|
|
|
|
|
|
struct test_mutex_destuction2 : rl::test_suite<test_mutex_destuction2, 2, rl::test_result_destroying_owned_mutex>
|
|
{
|
|
std::mutex* m;
|
|
std::atomic<int> f;
|
|
|
|
void before()
|
|
{
|
|
m = new std::mutex;
|
|
f($) = 0;
|
|
}
|
|
|
|
void thread(unsigned index)
|
|
{
|
|
if (0 == index)
|
|
{
|
|
m->lock($);
|
|
f($) = 1;
|
|
while (1 == f($))
|
|
rl::yield(1, $);
|
|
m->unlock($);
|
|
}
|
|
else
|
|
{
|
|
while (0 == f($))
|
|
rl::yield(1, $);
|
|
delete m;
|
|
f($) = 2;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
struct test_mutex_recursion : rl::test_suite<test_mutex_recursion, 2>
|
|
{
|
|
std::recursive_mutex mtx;
|
|
rl::var<int> data;
|
|
|
|
void before()
|
|
{
|
|
data($) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
RL_ASSERT(data($) == 2);
|
|
}
|
|
|
|
void thread(unsigned /*index*/)
|
|
{
|
|
mtx.lock($);
|
|
mtx.lock($);
|
|
data($) += 1;
|
|
mtx.unlock($);
|
|
mtx.unlock($);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
struct test_mutex_try_lock : rl::test_suite<test_mutex_try_lock, 2>
|
|
{
|
|
std::recursive_mutex mtx;
|
|
rl::var<int> data;
|
|
|
|
void before()
|
|
{
|
|
data($) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
RL_ASSERT(data($) == 2);
|
|
}
|
|
|
|
void thread(unsigned /*index*/)
|
|
{
|
|
while (false == mtx.try_lock($))
|
|
rl::yield(1, $);
|
|
RL_ASSERT(mtx.try_lock($));
|
|
data($) += 1;
|
|
mtx.unlock($);
|
|
mtx.unlock($);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
struct test_mutex_recursion_error : rl::test_suite<test_mutex_recursion_error, 1, rl::test_result_recursion_on_nonrecursive_mutex>
|
|
{
|
|
void thread(unsigned)
|
|
{
|
|
std::mutex m;
|
|
m.lock($);
|
|
m.lock($);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
struct test_mutex_unlock_error : rl::test_suite<test_mutex_unlock_error, 1, rl::test_result_unlocking_mutex_wo_ownership>
|
|
{
|
|
void thread(unsigned)
|
|
{
|
|
std::mutex m;
|
|
m.lock($);
|
|
m.unlock($);
|
|
m.unlock($);
|
|
}
|
|
};
|
|
|
|
|
|
struct test_mutex_leak : rl::test_suite<test_mutex_leak, 1, rl::test_result_resource_leak>
|
|
{
|
|
void thread(unsigned)
|
|
{
|
|
char* p = new char [sizeof(std::mutex)];
|
|
new (p) std::mutex();
|
|
delete [] p;
|
|
}
|
|
};
|
|
|
|
|