mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 15:32:25 +00:00
parent
a47adecdcd
commit
07a40d028a
@ -1,7 +1,7 @@
|
||||
<runtime ram="72M" caps="1000" binary="init">
|
||||
|
||||
<events>
|
||||
<timeout meaning="failed" sec="30" />
|
||||
<timeout meaning="failed" sec="60" />
|
||||
<log meaning="succeeded">--- returning from main ---</log>
|
||||
<log meaning="failed">Error: </log>
|
||||
<log meaning="failed">child "test-pthread" exited</log>
|
||||
@ -19,11 +19,7 @@
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
|
@ -175,6 +175,197 @@ Libc::Pthread_registry &pthread_registry()
|
||||
}
|
||||
|
||||
|
||||
/***********
|
||||
** Mutex **
|
||||
***********/
|
||||
|
||||
namespace Libc {
|
||||
struct Pthread_mutex_normal;
|
||||
struct Pthread_mutex_errorcheck;
|
||||
struct Pthread_mutex_recursive;
|
||||
}
|
||||
|
||||
/*
|
||||
* This class is named 'struct pthread_mutex_attr' because the
|
||||
* 'pthread_mutexattr_t' type is defined as 'struct pthread_mutex_attr *'
|
||||
* in '_pthreadtypes.h'
|
||||
*/
|
||||
struct pthread_mutex_attr { pthread_mutextype type; };
|
||||
|
||||
|
||||
/*
|
||||
* This class is named 'struct pthread_mutex' because the 'pthread_mutex_t'
|
||||
* type is defined as 'struct pthread_mutex *' in '_pthreadtypes.h'
|
||||
*/
|
||||
struct pthread_mutex
|
||||
{
|
||||
Lock _lock; /* actual lock for blocking/deblocking */
|
||||
|
||||
pthread_t _owner { nullptr };
|
||||
unsigned _lock_count { 0 };
|
||||
Lock _owner_and_counter_mutex;
|
||||
|
||||
pthread_mutex() { }
|
||||
|
||||
virtual ~pthread_mutex() { }
|
||||
|
||||
/*
|
||||
* The behavior of the following function follows the "robust mutex"
|
||||
* described IEEE Std 1003.1 POSIX.1-2017
|
||||
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html
|
||||
*/
|
||||
virtual int lock() = 0;
|
||||
virtual int trylock() = 0;
|
||||
virtual int unlock() = 0;
|
||||
};
|
||||
|
||||
|
||||
struct Libc::Pthread_mutex_normal : pthread_mutex
|
||||
{
|
||||
int lock() override final
|
||||
{
|
||||
while (trylock() == EBUSY) {
|
||||
/*
|
||||
* We did not get the lock, so, yield the CPU and retry. This
|
||||
* may implicitly dead-lock if we are already the lock owner.
|
||||
*/
|
||||
_lock.lock();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trylock() override final
|
||||
{
|
||||
Lock::Guard lock_guard(_owner_and_counter_mutex);
|
||||
|
||||
if (!_owner) {
|
||||
_owner = pthread_self();
|
||||
_lock.lock(); /* always succeeds */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
int unlock() override final
|
||||
{
|
||||
Lock::Guard lock_guard(_owner_and_counter_mutex);
|
||||
|
||||
if (_owner != pthread_self())
|
||||
return EPERM;
|
||||
|
||||
_owner = nullptr;
|
||||
_lock.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Libc::Pthread_mutex_errorcheck : pthread_mutex
|
||||
{
|
||||
int lock() override final
|
||||
{
|
||||
/*
|
||||
* We can't use trylock() as it returns EBUSY also for the
|
||||
* EDEADLK case.
|
||||
*/
|
||||
while (true) {
|
||||
{
|
||||
Lock::Guard lock_guard(_owner_and_counter_mutex);
|
||||
|
||||
if (!_owner) {
|
||||
_owner = pthread_self();
|
||||
_lock.lock(); /* always succeeds */
|
||||
return 0;
|
||||
} else if (_owner == pthread_self()) {
|
||||
return EDEADLK;
|
||||
}
|
||||
}
|
||||
/* mutex has another owner, so, yield the CPU and retry */
|
||||
_lock.lock();
|
||||
_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int trylock() override final
|
||||
{
|
||||
Lock::Guard lock_guard(_owner_and_counter_mutex);
|
||||
|
||||
if (!_owner) {
|
||||
_owner = pthread_self();
|
||||
_lock.lock(); /* always succeeds */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
int unlock() override final
|
||||
{
|
||||
Lock::Guard lock_guard(_owner_and_counter_mutex);
|
||||
|
||||
if (_owner != pthread_self())
|
||||
return EPERM;
|
||||
|
||||
_owner = nullptr;
|
||||
_lock.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Libc::Pthread_mutex_recursive : pthread_mutex
|
||||
{
|
||||
int lock() override final
|
||||
{
|
||||
while (trylock() == EBUSY) {
|
||||
/* mutex has another owner, so, yield the CPU and retry */
|
||||
_lock.lock();
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trylock() override final
|
||||
{
|
||||
Lock::Guard lock_guard(_owner_and_counter_mutex);
|
||||
|
||||
if (!_owner) {
|
||||
_owner = pthread_self();
|
||||
_lock_count = 1;
|
||||
_lock.lock(); /* always succeeds */
|
||||
return 0;
|
||||
} else if (_owner == pthread_self()) {
|
||||
++_lock_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
int unlock() override final
|
||||
{
|
||||
Lock::Guard lock_guard(_owner_and_counter_mutex);
|
||||
|
||||
if (_owner != pthread_self())
|
||||
return EPERM;
|
||||
|
||||
--_lock_count;
|
||||
if (_lock_count == 0) {
|
||||
_owner = nullptr;
|
||||
_lock.unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* Thread */
|
||||
@ -345,176 +536,13 @@ extern "C" {
|
||||
|
||||
/* Mutex */
|
||||
|
||||
|
||||
struct pthread_mutex_attr
|
||||
{
|
||||
int type;
|
||||
|
||||
pthread_mutex_attr() : type(PTHREAD_MUTEX_NORMAL) { }
|
||||
};
|
||||
|
||||
|
||||
struct pthread_mutex
|
||||
{
|
||||
pthread_mutex_attr mutexattr;
|
||||
|
||||
Lock mutex_lock;
|
||||
|
||||
pthread_t owner;
|
||||
int lock_count;
|
||||
Lock owner_and_counter_lock;
|
||||
|
||||
pthread_mutex(const pthread_mutexattr_t *__restrict attr)
|
||||
: owner(0),
|
||||
lock_count(0)
|
||||
{
|
||||
if (attr && *attr)
|
||||
mutexattr = **attr;
|
||||
}
|
||||
|
||||
int lock()
|
||||
{
|
||||
if (mutexattr.type == PTHREAD_MUTEX_RECURSIVE) {
|
||||
|
||||
Lock::Guard lock_guard(owner_and_counter_lock);
|
||||
|
||||
if (lock_count == 0) {
|
||||
owner = pthread_self();
|
||||
lock_count++;
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the mutex is already locked */
|
||||
if (pthread_self() == owner) {
|
||||
lock_count++;
|
||||
return 0;
|
||||
} else {
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mutexattr.type == PTHREAD_MUTEX_ERRORCHECK) {
|
||||
|
||||
Lock::Guard lock_guard(owner_and_counter_lock);
|
||||
|
||||
if (lock_count == 0) {
|
||||
owner = pthread_self();
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the mutex is already locked */
|
||||
if (pthread_self() != owner) {
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
} else
|
||||
return EDEADLK;
|
||||
}
|
||||
|
||||
/* PTHREAD_MUTEX_NORMAL or PTHREAD_MUTEX_DEFAULT */
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trylock()
|
||||
{
|
||||
if (mutexattr.type == PTHREAD_MUTEX_RECURSIVE) {
|
||||
|
||||
Lock::Guard lock_guard(owner_and_counter_lock);
|
||||
|
||||
if (lock_count == 0) {
|
||||
owner = pthread_self();
|
||||
lock_count++;
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the mutex is already locked */
|
||||
if (pthread_self() == owner) {
|
||||
lock_count++;
|
||||
return 0;
|
||||
} else {
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
if (mutexattr.type == PTHREAD_MUTEX_ERRORCHECK) {
|
||||
|
||||
Lock::Guard lock_guard(owner_and_counter_lock);
|
||||
|
||||
if (lock_count == 0) {
|
||||
owner = pthread_self();
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the mutex is already locked */
|
||||
if (pthread_self() != owner) {
|
||||
return EBUSY;
|
||||
} else
|
||||
return EDEADLK;
|
||||
}
|
||||
|
||||
/* PTHREAD_MUTEX_NORMAL or PTHREAD_MUTEX_DEFAULT */
|
||||
Lock::Guard lock_guard(owner_and_counter_lock);
|
||||
|
||||
if (lock_count == 0) {
|
||||
owner = pthread_self();
|
||||
mutex_lock.lock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
int unlock()
|
||||
{
|
||||
|
||||
if (mutexattr.type == PTHREAD_MUTEX_RECURSIVE) {
|
||||
|
||||
Lock::Guard lock_guard(owner_and_counter_lock);
|
||||
|
||||
if (pthread_self() != owner)
|
||||
return EPERM;
|
||||
|
||||
lock_count--;
|
||||
|
||||
if (lock_count == 0) {
|
||||
owner = 0;
|
||||
mutex_lock.unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mutexattr.type == PTHREAD_MUTEX_ERRORCHECK) {
|
||||
|
||||
Lock::Guard lock_guard(owner_and_counter_lock);
|
||||
|
||||
if (pthread_self() != owner)
|
||||
return EPERM;
|
||||
|
||||
owner = 0;
|
||||
mutex_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PTHREAD_MUTEX_NORMAL or PTHREAD_MUTEX_DEFAULT */
|
||||
mutex_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t *attr)
|
||||
{
|
||||
if (!attr)
|
||||
return EINVAL;
|
||||
|
||||
Libc::Allocator alloc { };
|
||||
*attr = new (alloc) pthread_mutex_attr;
|
||||
*attr = new (alloc) pthread_mutex_attr { PTHREAD_MUTEX_NORMAL };
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -527,7 +555,7 @@ extern "C" {
|
||||
|
||||
Libc::Allocator alloc { };
|
||||
destroy(alloc, *attr);
|
||||
*attr = 0;
|
||||
*attr = nullptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -538,20 +566,32 @@ extern "C" {
|
||||
if (!attr || !*attr)
|
||||
return EINVAL;
|
||||
|
||||
(*attr)->type = type;
|
||||
(*attr)->type = (pthread_mutextype)type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *__restrict mutex,
|
||||
const pthread_mutexattr_t *__restrict attr)
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||
pthread_mutexattr_t const *attr)
|
||||
{
|
||||
if (!mutex)
|
||||
return EINVAL;
|
||||
|
||||
|
||||
Libc::Allocator alloc { };
|
||||
*mutex = new (alloc) pthread_mutex(attr);
|
||||
|
||||
pthread_mutextype const type = (!attr || !*attr)
|
||||
? PTHREAD_MUTEX_NORMAL : (*attr)->type;
|
||||
switch (type) {
|
||||
case PTHREAD_MUTEX_NORMAL: *mutex = new (alloc) Pthread_mutex_normal; break;
|
||||
case PTHREAD_MUTEX_ERRORCHECK: *mutex = new (alloc) Pthread_mutex_errorcheck; break;
|
||||
case PTHREAD_MUTEX_RECURSIVE: *mutex = new (alloc) Pthread_mutex_recursive; break;
|
||||
|
||||
default:
|
||||
*mutex = nullptr;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -576,11 +616,9 @@ extern "C" {
|
||||
return EINVAL;
|
||||
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER)
|
||||
pthread_mutex_init(mutex, 0);
|
||||
pthread_mutex_init(mutex, nullptr);
|
||||
|
||||
(*mutex)->lock();
|
||||
|
||||
return 0;
|
||||
return (*mutex)->lock();
|
||||
}
|
||||
|
||||
|
||||
@ -590,7 +628,7 @@ extern "C" {
|
||||
return EINVAL;
|
||||
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER)
|
||||
pthread_mutex_init(mutex, 0);
|
||||
pthread_mutex_init(mutex, nullptr);
|
||||
|
||||
return (*mutex)->trylock();
|
||||
}
|
||||
@ -602,11 +640,9 @@ extern "C" {
|
||||
return EINVAL;
|
||||
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER)
|
||||
pthread_mutex_init(mutex, 0);
|
||||
return EINVAL;
|
||||
|
||||
(*mutex)->unlock();
|
||||
|
||||
return 0;
|
||||
return (*mutex)->unlock();
|
||||
}
|
||||
|
||||
|
||||
@ -967,30 +1003,28 @@ extern "C" {
|
||||
{
|
||||
if (!once || ((once->state != PTHREAD_NEEDS_INIT) &&
|
||||
(once->state != PTHREAD_DONE_INIT)))
|
||||
return EINTR;
|
||||
return EINVAL;
|
||||
|
||||
if (!once->mutex) {
|
||||
Libc::Allocator alloc { };
|
||||
pthread_mutex_t p = new (alloc) pthread_mutex(0);
|
||||
/* be paranoid */
|
||||
if (!p)
|
||||
return EINTR;
|
||||
pthread_mutex_t p;
|
||||
pthread_mutex_init(&p, nullptr);
|
||||
if (!p) return EINVAL;
|
||||
|
||||
static Lock lock;
|
||||
{
|
||||
static Lock lock;
|
||||
Lock::Guard guard(lock);
|
||||
|
||||
lock.lock();
|
||||
if (!once->mutex) {
|
||||
once->mutex = p;
|
||||
p = nullptr;
|
||||
if (!once->mutex) {
|
||||
once->mutex = p;
|
||||
p = nullptr;
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
/*
|
||||
* If another thread concurrently allocated a mutex and was faster,
|
||||
* free our mutex since it is not used.
|
||||
*/
|
||||
if (p)
|
||||
destroy(alloc, p);
|
||||
if (p) pthread_mutex_destroy(&p);
|
||||
}
|
||||
|
||||
once->mutex->lock();
|
||||
|
@ -32,7 +32,7 @@ extern "C" {
|
||||
* This class is named 'struct sem' because the 'sem_t' type is
|
||||
* defined as 'struct sem*' in 'semaphore.h'
|
||||
*/
|
||||
struct sem : Semaphore
|
||||
struct sem : Genode::Semaphore
|
||||
{
|
||||
sem(int value) : Semaphore(value) { }
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief POSIX thread and semaphore test
|
||||
* \author Christian Prochaska
|
||||
* \author Christian Helmuth
|
||||
* \date 2012-04-04
|
||||
*/
|
||||
|
||||
@ -17,6 +18,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <base/log.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
|
||||
enum { NUM_THREADS = 2 };
|
||||
|
||||
@ -71,7 +75,7 @@ void test_self_destruct(void *(*start_routine)(void*), uintptr_t num_iterations)
|
||||
}
|
||||
|
||||
pthread_join(t, &retval);
|
||||
|
||||
|
||||
if (retval != (void*)i) {
|
||||
printf("error: return value does not match\n");
|
||||
exit(-1);
|
||||
@ -94,10 +98,10 @@ void *thread_func_self_destruct(void *arg)
|
||||
|
||||
static inline void compare_semaphore_values(int reported_value, int expected_value)
|
||||
{
|
||||
if (reported_value != expected_value) {
|
||||
printf("error: sem_getvalue() did not return the expected value\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (reported_value != expected_value) {
|
||||
printf("error: sem_getvalue() did not return the expected value\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -125,9 +129,15 @@ struct Test_mutex_data
|
||||
pthread_mutex_init(&errorcheck_mutex, &errorcheck_mutex_attr);
|
||||
pthread_mutexattr_destroy(&errorcheck_mutex_attr);
|
||||
}
|
||||
|
||||
~Test_mutex_data()
|
||||
{
|
||||
pthread_mutex_destroy(&errorcheck_mutex);
|
||||
pthread_mutex_destroy(&recursive_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
void *thread_mutex_func(void *arg)
|
||||
static void *thread_mutex_func(void *arg)
|
||||
{
|
||||
Test_mutex_data *test_mutex_data = (Test_mutex_data*)arg;
|
||||
|
||||
@ -251,17 +261,17 @@ void *thread_mutex_func(void *arg)
|
||||
/* wake up main thread */
|
||||
sem_post(&test_mutex_data->test_thread_ready_sem);
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void test_mutex()
|
||||
static void test_mutex()
|
||||
{
|
||||
pthread_t t;
|
||||
|
||||
Test_mutex_data test_mutex_data;
|
||||
|
||||
if (pthread_create(&t, 0, thread_mutex_func, &test_mutex_data) != 0) {
|
||||
printf("error: pthread_create() failed\n");
|
||||
printf("Error: pthread_create() failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -317,6 +327,134 @@ void test_mutex()
|
||||
pthread_join(t, NULL);
|
||||
}
|
||||
|
||||
|
||||
template <pthread_mutextype MUTEX_TYPE>
|
||||
struct Test_mutex_stress
|
||||
{
|
||||
static const char *type_string(pthread_mutextype t)
|
||||
{
|
||||
switch (t) {
|
||||
case PTHREAD_MUTEX_NORMAL: return "PTHREAD_MUTEX_NORMAL";
|
||||
case PTHREAD_MUTEX_ERRORCHECK: return "PTHREAD_MUTEX_ERRORCHECK";
|
||||
case PTHREAD_MUTEX_RECURSIVE: return "PTHREAD_MUTEX_RECURSIVE";
|
||||
|
||||
default: break;
|
||||
}
|
||||
return "<unexpected mutex type>";
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
pthread_mutexattr_t _attr;
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
Data()
|
||||
{
|
||||
pthread_mutexattr_init(&_attr);
|
||||
pthread_mutexattr_settype(&_attr, MUTEX_TYPE);
|
||||
pthread_mutex_init(&_mutex, &_attr);
|
||||
pthread_mutexattr_destroy(&_attr);
|
||||
}
|
||||
|
||||
~Data()
|
||||
{
|
||||
pthread_mutex_destroy(&_mutex);
|
||||
}
|
||||
|
||||
pthread_mutex_t * mutex() { return &_mutex; }
|
||||
} data;
|
||||
|
||||
struct Thread
|
||||
{
|
||||
pthread_mutex_t *_mutex;
|
||||
sem_t _startup_sem;
|
||||
pthread_t _thread;
|
||||
|
||||
static void * _entry_trampoline(void *arg)
|
||||
{
|
||||
Thread *t = (Thread *)arg;
|
||||
t->_entry();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void _lock()
|
||||
{
|
||||
if (int const err = pthread_mutex_lock(_mutex))
|
||||
Genode::error("lock() returned ", err);
|
||||
}
|
||||
|
||||
void _unlock()
|
||||
{
|
||||
if (int const err = pthread_mutex_unlock(_mutex))
|
||||
Genode::error("unlock() returned ", err);
|
||||
}
|
||||
|
||||
void _entry()
|
||||
{
|
||||
sem_wait(&_startup_sem);
|
||||
|
||||
enum { ROUNDS = 800 };
|
||||
|
||||
for (unsigned i = 0; i < ROUNDS; ++i) {
|
||||
_lock();
|
||||
if (MUTEX_TYPE == PTHREAD_MUTEX_RECURSIVE) {
|
||||
_lock();
|
||||
_lock();
|
||||
}
|
||||
|
||||
/* stay in mutex for some time */
|
||||
for (unsigned volatile d = 0; d < 30000; ++d) ;
|
||||
|
||||
if (MUTEX_TYPE == PTHREAD_MUTEX_RECURSIVE) {
|
||||
_unlock();
|
||||
_unlock();
|
||||
}
|
||||
_unlock();
|
||||
}
|
||||
Genode::log("thread ", this, ": ", (int)ROUNDS, " rounds done");
|
||||
}
|
||||
|
||||
Thread(pthread_mutex_t *mutex) : _mutex(mutex)
|
||||
{
|
||||
sem_init(&_startup_sem, 0, 0);
|
||||
|
||||
if (pthread_create(&_thread, 0, _entry_trampoline, this) != 0) {
|
||||
printf("Error: pthread_create() failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void start() { sem_post(&_startup_sem); }
|
||||
void join() { pthread_join(_thread, nullptr); }
|
||||
} threads[10] = {
|
||||
data.mutex(), data.mutex(), data.mutex(), data.mutex(), data.mutex(),
|
||||
data.mutex(), data.mutex(), data.mutex(), data.mutex(), data.mutex(),
|
||||
};
|
||||
|
||||
Test_mutex_stress()
|
||||
{
|
||||
printf("main thread: start %s stress test\n", type_string(MUTEX_TYPE));
|
||||
for (Thread &t : threads) t.start();
|
||||
for (Thread &t : threads) t.join();
|
||||
printf("main thread: finished %s stress test\n", type_string(MUTEX_TYPE));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern "C" void wait_for_continue();
|
||||
|
||||
static void test_mutex_stress()
|
||||
{
|
||||
printf("main thread: stressing mutexes\n");
|
||||
|
||||
{ Test_mutex_stress<PTHREAD_MUTEX_NORMAL> test_normal; }
|
||||
{ Test_mutex_stress<PTHREAD_MUTEX_ERRORCHECK> test_errorcheck; }
|
||||
{ Test_mutex_stress<PTHREAD_MUTEX_RECURSIVE> test_recursive; }
|
||||
|
||||
printf("main thread: mutex stress testing done\n");
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("--- pthread test ---\n");
|
||||
@ -399,7 +537,7 @@ int main(int argc, char **argv)
|
||||
for (int i = 0; i < NUM_THREADS; i++)
|
||||
sem_destroy(&thread[i].thread_args.thread_finished_sem);
|
||||
|
||||
printf("main thread: create pthreads which self de-struct\n");
|
||||
printf("main thread: create pthreads which self destruct\n");
|
||||
|
||||
test_self_destruct(thread_func_self_destruct, 100);
|
||||
|
||||
@ -407,6 +545,8 @@ int main(int argc, char **argv)
|
||||
|
||||
test_mutex();
|
||||
|
||||
test_mutex_stress();
|
||||
|
||||
printf("--- returning from main ---\n");
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user