libicsneo/include/icsneo/third-party/concurrentqueue/tests/relacy/relacy/test/main.cpp

582 lines
16 KiB
C++

#include "stdafx.h"
//#define RL_MSVC_OUTPUT
#include "../relacy/relacy_std.hpp"
#include "memory_order.hpp"
#include "fence.hpp"
#include "data_race.hpp"
#include "mutex.hpp"
#include "condvar.hpp"
#include "semaphore.hpp"
#include "event.hpp"
#include "scheduler.hpp"
#include "compare_swap.hpp"
#include "wfmo.hpp"
#include "thread_local.hpp"
#include "dyn_thread.hpp"
#include "memory.hpp"
#include "pthread.hpp"
#include "windows.hpp"
#include "addr_hash.hpp"
#include "futex.hpp"
#include "../relacy/windows.h"
#include "../relacy/pthread.h"
#include <cstdio>
#include <climits>
class queue_t
{
public:
queue_t()
{
VAR(head) = 0;
VAR(tail) = 0;
pthread_mutex_init(&mtx, 0);
pthread_cond_init(&cv, 0);
}
~queue_t()
{
pthread_mutex_destroy(&mtx);
pthread_cond_destroy(&cv);
}
void enqueue(void* data)
{
node_t* n = new node_t;
n->VAR(next) = 0;
n->VAR(data) = data;
bool was_empty = false;
pthread_mutex_lock(&mtx);
if (VAR(head) == 0)
{
was_empty = true;
VAR(head) = n;
VAR(tail) = n;
}
else
{
VAR(tail)->VAR(next) = n;
VAR(tail) = n;
}
pthread_mutex_unlock(&mtx);
if (was_empty)
pthread_cond_broadcast(&cv);
}
void* dequeue()
{
node_t* n = 0;
pthread_mutex_lock(&mtx);
while (VAR(head) == 0)
pthread_cond_wait(&cv, &mtx);
n = VAR(head);
if (n->VAR(next) == 0)
VAR(tail) = 0;
VAR(head) = n->VAR(next);
pthread_mutex_unlock(&mtx);
void* data = n->VAR(data);
delete n;
return data;
}
private:
struct node_t
{
VAR_T(node_t*) next;
VAR_T(void*) data;
};
VAR_T(node_t*) head;
VAR_T(node_t*) tail;
pthread_mutex_t mtx;
pthread_cond_t cv;
};
void* enqueue_thread(void* ctx)
{
queue_t* q = static_cast<queue_t*>(ctx);
for (size_t i = 0; i != 4; i += 1)
q->enqueue((void*)(i + 1));
return 0;
}
void* dequeue_thread(void* ctx)
{
queue_t* q = static_cast<queue_t*>(ctx);
for (size_t i = 0; i != 4; i += 1)
{
void* data = q->dequeue();
assert((int)(uintptr_t)data >= 1 && (int)(uintptr_t)data <= 4);
}
return 0;
}
void queue_test()
{
queue_t q;
pthread_t th [4];
for (size_t i = 0; i != 2; i += 1)
pthread_create(&th[i], 0, enqueue_thread, &q);
for (size_t i = 2; i != 4; i += 1)
pthread_create(&th[i], 0, dequeue_thread, &q);
void* res = 0;
for (size_t i = 0; i != 4; i += 1)
pthread_join(th[i], &res);
}
/*
class recursive_timed_mutex
{
public:
recursive_timed_mutex()
{
sema.init(false, 1, 1, $);
owner = -1;
recursion_count = 0;
}
~recursive_timed_mutex()
{
assert(owner == -1 && recursion_count == 0);
sema.deinit($);
}
void lock(rl::debug_info_param info)
{
rl::context& c = rl::ctx();
if (owner == c.current_thread())
{
RL_HIST(rl::user_msg_event) {"recursive mutex lock"} RL_HIST_END();
assert(recursion_count > 0);
recursion_count += 1;
}
else
{
sema.wait(false, false, info);
assert(owner == -1 && recursion_count == 0);
owner = c.current_thread();
recursion_count = 1;
}
}
bool try_lock(rl::debug_info_param info)
{
rl::context& c = rl::ctx();
if (owner == c.current_thread())
{
RL_HIST(rl::user_msg_event) {"recursive mutex try lock"} RL_HIST_END();
assert(recursion_count > 0);
recursion_count += 1;
return true;
}
else
{
rl::sema_wakeup_reason r = sema.wait(true, false, info);
if (r == rl::sema_wakeup_reason_success)
{
assert(owner == -1 && recursion_count == 0);
owner = c.current_thread();
recursion_count = 1;
return true;
}
else
{
return false;
}
}
}
void unlock(rl::debug_info_param info)
{
rl::context& c = rl::ctx();
assert(owner == c.current_thread() && recursion_count > 0);
RL_HIST(rl::user_msg_event) {"recursive mutex unlock"} RL_HIST_END();
recursion_count -= 1;
if (recursion_count == 0)
{
owner = -1;
unsigned prev;
sema.post(1, prev, info);
}
}
bool timed_lock(rl::debug_info_param info, ... )
{
rl::context& c = rl::ctx();
if (owner == c.current_thread())
{
RL_HIST(rl::user_msg_event) {"recursive mutex timed lock"} RL_HIST_END();
assert(recursion_count > 0);
recursion_count += 1;
return true;
}
else
{
rl::sema_wakeup_reason r = sema.wait(false, true, info);
if (r == rl::sema_wakeup_reason_success)
{
assert(owner == -1 && recursion_count == 0);
owner = c.current_thread();
recursion_count = 1;
return true;
}
else
{
return false;
}
}
}
private:
struct tag_t;
rl::semaphore<tag_t> sema;
rl::thread_id_t owner;
int recursion_count;
recursive_timed_mutex(recursive_timed_mutex const&);
recursive_timed_mutex& operator = (recursive_timed_mutex const&);
};
*/
class recursive_timed_mutex
{
public:
recursive_timed_mutex()
{
mtx = CreateMutex(0, 0, 0);
}
~recursive_timed_mutex()
{
CloseHandle(mtx);
}
void lock(rl::debug_info_param info)
{
rl::rl_WaitForSingleObject(mtx, INFINITE, info);
}
bool try_lock(rl::debug_info_param info)
{
return WAIT_OBJECT_0 == rl::rl_WaitForSingleObject(mtx, 0, info);
}
void unlock(rl::debug_info_param info)
{
rl::rl_ReleaseMutex(mtx, info);
}
bool timed_lock(rl::debug_info_param info, ... /*abs_time*/)
{
return WAIT_OBJECT_0 == rl::rl_WaitForSingleObject(mtx, 1, info);
}
private:
HANDLE mtx;
recursive_timed_mutex(recursive_timed_mutex const&);
recursive_timed_mutex& operator = (recursive_timed_mutex const&);
};
struct recursive_timed_mutex_test : rl::test_suite<recursive_timed_mutex_test, 3>
{
recursive_timed_mutex mtx;
VAR_T(int) data;
void thread(unsigned idx)
{
if (idx)
{
mtx.lock($);
mtx.lock($);
VAR(data) = 1;
mtx.unlock($);
mtx.unlock($);
}
else
{
if (mtx.timed_lock($))
{
VAR(data) = 2;
mtx.unlock($);
}
}
}
void after()
{
//assert(VAR(data) != 2);
}
};
int main()
{
//rl::test_params p;
//p.search_type = rl::sched_full;
//p.context_bound = 5;
//p.execution_depth_limit = 200;
//rl::simulate<test_pthread_condvar>(p);
//if (rand() <= RAND_MAX) return 0;
//rl::execute<queue_test, 4>();
//if (rand() <= RAND_MAX) return 0;
//rl::test_params p;
//p.initial_state = "1000000";
//p.iteration_count = 2000000;
//p.collect_history = true;
//p.output_history = true;
//p.search_type = rl::sched_bound;
//p.search_type = rl::sched_full;
//p.execution_depth_limit = 500;
//p.context_bound = 1;
//rl::simulate<test_pthread_condvar>(p);
//std::cout << "scheduler state = \"" << p.final_state << "\"" << std::endl;
//std::cout << std::endl;
//if (rand() <= RAND_MAX) return 0;
//rl::test_params p;
//p.iteration_count = 80000000;
//p.initial_state = "50000000";
//p.search_type = rl::fair_context_bound_scheduler_type;
//p.context_bound = 1;
//p.collect_history = true;
//p.output_history = true;
//rl::simulate<test>(p);
//if (rand() <= RAND_MAX) return 0;
//rl::test_params p;
//p.context_bound = 1;
//p.iteration_count = 1000;
//p.search_type = rl::fair_full_search_scheduler_type;
//p.search_type = rl::random_scheduler_type;
//p.collect_history = true;
//p.output_history = true;
//p.execution_depth_limit = 1000;
//p.initial_state = "550 24 3 0 0 3 0 0 3 0 0 3 0 0 2 0 4 2 0 0 2 0 4 2 1 0 2 0 4 3 1 0 3 0 0 2 0 0 1 0 4 2 0 4 3 0 0 3 0 0 2 0 4 3 1 0 3 0 0 2 1 0 2 0 4 2 1 0 2 1 0 2 1 4";
//bool result = rl::simulate<test>(p);
//std::cout << "result=" << result << std::endl;
//simulate<my_test>();
//if (rand() <= RAND_MAX) return 0;
rl::simulate_f tests[] =
{
#if 1
&rl::simulate<test_FlushProcessWriteBuffers>,
&rl::simulate<test_addr_hash>,
&rl::simulate<test_addr_hash2>,
//!!! fails &rl::simulate<sched_load_test>,
&rl::simulate<test_memory_allocation>,
// memory model
&rl::simulate<test_pthread_thread>,
&rl::simulate<test_pthread_mutex>,
&rl::simulate<test_pthread_rwlock>,
&rl::simulate<test_pthread_condvar>,
&rl::simulate<test_pthread_condvar2>,
&rl::simulate<test_pthread_sem>,
&rl::simulate<coherent_read_read_test>,
&rl::simulate<order_relaxed_test<0> >,
&rl::simulate<order_relaxed_test<1> >,
&rl::simulate<order_relaxed_test<2> >,
&rl::simulate<order_relaxed_test<3> >,
&rl::simulate<order_relaxed_test<4> >,
&rl::simulate<reorder_single_var_test>,
&rl::simulate<acq_rel_test>,
&rl::simulate<seq_cst_test<0> >,
&rl::simulate<seq_cst_test<1> >,
&rl::simulate<reordering_test>,
&rl::simulate<reordering_test2>,
&rl::simulate<test_win_thread>,
&rl::simulate<test_win_mutex>,
&rl::simulate<test_win_cs>,
&rl::simulate<test_win_condvar>,
&rl::simulate<test_win_condvar_srw>,
&rl::simulate<test_win_sem>,
&rl::simulate<test_win_event>,
&rl::simulate<modification_order_test>,
&rl::simulate<transitive_test>,
&rl::simulate<cc_transitive_test>,
&rl::simulate<occasional_test>,
// fences
&rl::simulate<fence_synch_test<0, 0> >,
&rl::simulate<fence_synch_test<1, 0> >,
&rl::simulate<fence_synch_test<2, 0> >,
&rl::simulate<fence_synch_test<0, 1> >,
&rl::simulate<fence_synch_test<1, 1> >,
&rl::simulate<fence_synch_test<2, 1> >,
&rl::simulate<two_fence_synch_test>,
&rl::simulate<seq_cst_fence_test<0> >,
&rl::simulate<seq_cst_fence_test<1> >,
// data races
&rl::simulate<race_ld_ld_test>,
&rl::simulate<race_ld_st_test>,
&rl::simulate<race_st_st_test>,
&rl::simulate<race_seq_ld_ld_test>,
&rl::simulate<race_seq_ld_st_test>,
&rl::simulate<race_seq_st_ld_test>,
&rl::simulate<race_seq_st_st_test>,
&rl::simulate<race_uninit_test>,
&rl::simulate<race_indirect_test>,
// compare_exchange
&rl::simulate<cas_spurious_fail_test<0> >,
&rl::simulate<cas_spurious_fail_test<1> >,
&rl::simulate<cas_spurious_fail_test<2> >,
// mutex
&rl::simulate<test_deadlock>,
&rl::simulate<test_deadlock2>,
&rl::simulate<test_mutex_destuction>,
&rl::simulate<test_mutex_destuction2>,
&rl::simulate<test_mutex_recursion>,
&rl::simulate<test_mutex_recursion_error>,
&rl::simulate<test_mutex_unlock_error>,
&rl::simulate<test_mutex_leak>,
&rl::simulate<test_mutex>,
&rl::simulate<test_mutex_try_lock>,
// futex
&rl::simulate<test_futex>,
&rl::simulate<test_futex_deadlock>,
&rl::simulate<test_futex_sync1>,
&rl::simulate<test_futex_sync2>,
&rl::simulate<test_futex_intr>,
// condition variable
&rl::simulate<test_condvar>,
&rl::simulate<test_condvar2>,
// semaphore
&rl::simulate<test_semaphore>,
&rl::simulate<test_semaphore_atomic>,
// event
&rl::simulate<test_event_auto>,
&rl::simulate<test_event_manual>,
&rl::simulate<test_event_atomic>,
//wfmo
&rl::simulate<test_wfmo_all>,
&rl::simulate<test_wfmo_single>,
&rl::simulate<test_wfmo_timeout>,
&rl::simulate<test_wfmo_try>,
&rl::simulate<test_wfmo_mixed>,
&rl::simulate<test_wfmo_mixed2>,
&rl::simulate<test_wfmo_event_all>,
&rl::simulate<test_wfmo_event_any>,
&rl::simulate<test_wfmo_atomic>,
// thread local storage
&rl::simulate<tls_basic_test>,
&rl::simulate<tls_reset_test>,
&rl::simulate<tls_global_test>,
&rl::simulate<tls_win32_test>,
// dynamic thread
&rl::simulate<dyn_thread_basic_test>,
&rl::simulate<dyn_thread_win32_test>,
&rl::simulate<dyn_thread_visibility_test>,
#endif
};
for (size_t sched = 0; sched != rl::sched_count; ++sched)
{
std::cout << format((rl::scheduler_type_e)sched) << " tests:" << std::endl;
for (size_t i = 0; i != sizeof(tests)/sizeof(*tests); ++i)
{
//!!! make it work under sched_full
if (sched == rl::sched_full
&& (tests[i] == (rl::simulate_f)&rl::simulate<test_pthread_condvar>
|| tests[i] == (rl::simulate_f)&rl::simulate<test_win_condvar>))
continue;
rl::ostringstream stream;
rl::test_params params;
params.search_type = (rl::scheduler_type_e)sched;
params.iteration_count =
(params.test_result == rl::test_result_success ? 100000 : 500);
params.output_stream = &stream;
params.progress_stream = &stream;
params.context_bound = 2;
params.execution_depth_limit = 500;
if (false == tests[i](params))
{
std::cout << std::endl;
std::cout << "FAILED" << std::endl;
std::cout << stream.str();
std::cout << std::endl;
return 1;
}
else
{
std::cout << params.test_name << "...OK" << std::endl;
}
}
std::cout << std::endl;
}
rl::simulate_f scheduler_tests[] =
{
&rl::simulate<livelock_test>,
&rl::simulate<yield_livelock_test>,
};
std::cout << "full search scheduler tests:" << std::endl;
for (size_t i = 0; i != sizeof(scheduler_tests)/sizeof(*scheduler_tests); ++i)
{
rl::ostringstream stream;
rl::test_params params;
params.search_type = rl::sched_full;
params.output_stream = &stream;
params.progress_stream = &stream;
params.context_bound = 2;
params.execution_depth_limit = 500;
if (false == scheduler_tests[i](params))
{
std::cout << std::endl;
std::cout << "FAILED" << std::endl;
std::cout << stream.str();
return 1;
}
else
{
std::cout << params.test_name << "...OK" << std::endl;
}
}
std::cout << std::endl;
std::cout << "SUCCESS" << std::endl;
}