282 lines
6.1 KiB
C++
282 lines
6.1 KiB
C++
#pragma once
|
|
|
|
#include "../relacy/pthread.h"
|
|
|
|
|
|
|
|
struct test_pthread_thread : rl::test_suite<test_pthread_thread, 1>
|
|
{
|
|
static size_t const dynamic_thread_count = 2;
|
|
|
|
VAR_T(int) data;
|
|
|
|
static void* func(void* param)
|
|
{
|
|
static_cast<test_pthread_thread*>(param)->VAR(data) += 1;
|
|
return 0;
|
|
}
|
|
|
|
void thread(unsigned)
|
|
{
|
|
VAR(data) = 0;
|
|
|
|
pthread_t th1;
|
|
pthread_create(&th1, 0, &test_pthread_thread::func, this);
|
|
void* res1 = 0;
|
|
pthread_join(th1, &res1);
|
|
|
|
RL_ASSERT(VAR(data) == 1);
|
|
|
|
pthread_t th2;
|
|
pthread_create(&th2, 0, &test_pthread_thread::func, this);
|
|
void* res2 = 0;
|
|
pthread_join(th2, &res2);
|
|
|
|
RL_ASSERT(VAR(data) == 2);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
struct test_pthread_mutex : rl::test_suite<test_pthread_mutex, 2>
|
|
{
|
|
pthread_mutex_t mtx;
|
|
VAR_T(int) data;
|
|
|
|
void before()
|
|
{
|
|
pthread_mutexattr_t attr;
|
|
pthread_mutexattr_init(&attr);
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
|
pthread_mutex_init(&mtx, &attr);
|
|
pthread_mutexattr_destroy(&attr);
|
|
VAR(data) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
pthread_mutex_destroy(&mtx);
|
|
}
|
|
|
|
void thread(unsigned /*index*/)
|
|
{
|
|
pthread_mutex_lock(&mtx);
|
|
VAR(data) += 1;
|
|
pthread_mutex_unlock(&mtx);
|
|
|
|
if (0 == pthread_mutex_try_lock(&mtx))
|
|
{
|
|
VAR(data) += 1;
|
|
pthread_mutex_unlock(&mtx);
|
|
}
|
|
|
|
//pthread_mutex_timedlock
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
struct test_pthread_condvar : rl::test_suite<test_pthread_condvar, 3>
|
|
{
|
|
pthread_cond_t cv;
|
|
pthread_mutex_t mtx;
|
|
VAR_T(int) stage;
|
|
|
|
void before()
|
|
{
|
|
pthread_condattr_t attr;
|
|
pthread_cond_init(&cv, &attr);
|
|
pthread_mutex_init(&mtx, 0);
|
|
VAR(stage) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
pthread_cond_destroy(&cv);
|
|
pthread_mutex_destroy(&mtx);
|
|
}
|
|
|
|
void thread(unsigned index)
|
|
{
|
|
if (0 == index)
|
|
{
|
|
pthread_mutex_lock(&mtx);
|
|
VAR(stage) += 1;
|
|
pthread_cond_broadcast(&cv);
|
|
while (VAR(stage) != 2)
|
|
pthread_cond_wait(&cv, &mtx);
|
|
pthread_mutex_unlock(&mtx);
|
|
}
|
|
else if (1 == index)
|
|
{
|
|
pthread_mutex_lock(&mtx);
|
|
while (VAR(stage) != 1)
|
|
{
|
|
int ts = 1;
|
|
pthread_cond_timedwait(&cv, &mtx, &ts);
|
|
}
|
|
VAR(stage) += 1;
|
|
pthread_cond_broadcast(&cv);
|
|
pthread_mutex_unlock(&mtx);
|
|
}
|
|
else if (2 == index)
|
|
{
|
|
pthread_mutex_lock(&mtx);
|
|
while (VAR(stage) != 2)
|
|
pthread_cond_wait(&cv, &mtx);
|
|
pthread_mutex_unlock(&mtx);
|
|
pthread_cond_signal(&cv);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
struct test_pthread_condvar2 : rl::test_suite<test_pthread_condvar2, 2>
|
|
{
|
|
pthread_cond_t cv1, cv2;
|
|
pthread_mutex_t mtx1, mtx2;
|
|
VAR_T(int) stage;
|
|
|
|
void before()
|
|
{
|
|
pthread_cond_init(&cv1, 0);
|
|
pthread_cond_init(&cv2, 0);
|
|
pthread_mutex_init(&mtx1, 0);
|
|
pthread_mutex_init(&mtx2, 0);
|
|
VAR(stage) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
pthread_cond_destroy(&cv1);
|
|
pthread_cond_destroy(&cv2);
|
|
pthread_mutex_destroy(&mtx1);
|
|
pthread_mutex_destroy(&mtx2);
|
|
}
|
|
|
|
void thread(unsigned index)
|
|
{
|
|
if (0 == index)
|
|
{
|
|
pthread_mutex_lock(&mtx1);
|
|
int ts = 1;
|
|
pthread_cond_timedwait(&cv1, &mtx1, &ts);
|
|
pthread_mutex_unlock(&mtx1);
|
|
}
|
|
else if (1 == index)
|
|
{
|
|
pthread_mutex_lock(&mtx2);
|
|
int ts = 1;
|
|
pthread_cond_timedwait(&cv2, &mtx2, &ts);
|
|
pthread_mutex_unlock(&mtx2);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
struct test_pthread_rwlock : rl::test_suite<test_pthread_rwlock, 3>
|
|
{
|
|
pthread_rwlock_t mtx;
|
|
VAR_T(int) data;
|
|
|
|
void before()
|
|
{
|
|
pthread_mutexattr_t attr;
|
|
pthread_mutexattr_init(&attr);
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
|
pthread_rwlock_init(&mtx, &attr);
|
|
pthread_mutexattr_destroy(&attr);
|
|
VAR(data) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
pthread_rwlock_destroy(&mtx);
|
|
}
|
|
|
|
void thread(unsigned /*index*/)
|
|
{
|
|
pthread_rwlock_wrlock(&mtx);
|
|
VAR(data) += 1;
|
|
pthread_rwlock_unlock(&mtx);
|
|
|
|
if (0 == pthread_rwlock_trywrlock(&mtx))
|
|
{
|
|
VAR(data) += 1;
|
|
pthread_rwlock_unlock(&mtx);
|
|
}
|
|
|
|
pthread_rwlock_rdlock(&mtx);
|
|
(void)(int)VAR(data);
|
|
pthread_rwlock_unlock(&mtx);
|
|
|
|
if (0 == pthread_rwlock_tryrdlock(&mtx))
|
|
{
|
|
(void)(int)VAR(data);
|
|
pthread_rwlock_unlock(&mtx);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
struct test_pthread_sem : rl::test_suite<test_pthread_sem, 2>
|
|
{
|
|
sem_t sem1, sem2;
|
|
VAR_T(int) data;
|
|
|
|
void before()
|
|
{
|
|
sem_init(&sem1, 0, 0);
|
|
sem_init(&sem2, 0, 0);
|
|
VAR(data) = 0;
|
|
}
|
|
|
|
void after()
|
|
{
|
|
sem_destroy(&sem1);
|
|
sem_destroy(&sem2);
|
|
}
|
|
|
|
void thread(unsigned index)
|
|
{
|
|
if (index)
|
|
{
|
|
VAR(data) = 1;
|
|
sem_post(&sem1);
|
|
while (sem_trywait(&sem2))
|
|
{
|
|
assert(errno == EINTR || errno == EAGAIN);
|
|
pthread_yield();
|
|
}
|
|
RL_ASSERT(VAR(data) == 2);
|
|
VAR(data) = 3;
|
|
int count = -1;
|
|
sem_getvalue(&sem2, &count);
|
|
RL_ASSERT(count == 0);
|
|
sem_post(&sem2);
|
|
sem_getvalue(&sem2, &count);
|
|
RL_ASSERT(count == 1);
|
|
}
|
|
else
|
|
{
|
|
while (sem_wait(&sem1))
|
|
assert(errno == EINTR);
|
|
RL_ASSERT(VAR(data) == 1);
|
|
VAR(data) = 2;
|
|
sem_post(&sem2);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|