mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
parent
505cd5e338
commit
131f8015f1
@ -25,6 +25,7 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
#include <base/sleep.h>
|
#include <base/sleep.h>
|
||||||
|
#include <cpu/atomic.h>
|
||||||
|
|
||||||
|
|
||||||
struct Thread_args {
|
struct Thread_args {
|
||||||
@ -1193,6 +1194,156 @@ static void test_thread_local_destructor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* test_pthread_once() counters */
|
||||||
|
static int volatile once_init, once_round, once_round_complete;
|
||||||
|
|
||||||
|
static int inc(int volatile *counter)
|
||||||
|
{
|
||||||
|
int next = *counter + 1;
|
||||||
|
while (!Genode::cmpxchg(counter, next - 1, next))
|
||||||
|
next++;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_once1() { inc(&once_init); }
|
||||||
|
static void init_once2() { inc(&once_init); }
|
||||||
|
static void init_once3() { inc(&once_init); }
|
||||||
|
|
||||||
|
static void init_once_nested()
|
||||||
|
{
|
||||||
|
pthread_once_t once_nested = PTHREAD_ONCE_INIT;
|
||||||
|
|
||||||
|
pthread_once(&once_nested, init_once1);
|
||||||
|
|
||||||
|
inc(&once_init);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Once_thread
|
||||||
|
{
|
||||||
|
enum { ROUNDS = 1'000 };
|
||||||
|
|
||||||
|
struct Arg
|
||||||
|
{
|
||||||
|
pthread_once_t *once;
|
||||||
|
void (*init_once)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned _tag;
|
||||||
|
|
||||||
|
Cond &_cond;
|
||||||
|
Mutex<PTHREAD_MUTEX_NORMAL> &_mutex;
|
||||||
|
|
||||||
|
Arg _once1, _once2, _once3;
|
||||||
|
|
||||||
|
pthread_t _thread;
|
||||||
|
|
||||||
|
static void * _entry_trampoline(void *arg)
|
||||||
|
{
|
||||||
|
Once_thread *t = (Once_thread *)arg;
|
||||||
|
t->_entry();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _entry()
|
||||||
|
{
|
||||||
|
for (int i = 1; i <= ROUNDS; ++i) {
|
||||||
|
pthread_mutex_lock(_mutex.mutex());
|
||||||
|
while (once_round != i)
|
||||||
|
pthread_cond_wait(_cond.cond(), _mutex.mutex());
|
||||||
|
pthread_mutex_unlock(_mutex.mutex());
|
||||||
|
|
||||||
|
pthread_once(_once1.once, _once1.init_once);
|
||||||
|
pthread_once(_once2.once, _once2.init_once);
|
||||||
|
pthread_once(_once3.once, _once3.init_once);
|
||||||
|
|
||||||
|
inc(&once_round_complete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Once_thread(unsigned tag, Cond &cond, Mutex<PTHREAD_MUTEX_NORMAL> &mutex,
|
||||||
|
Arg once1, Arg once2, Arg once3)
|
||||||
|
: _tag(tag), _cond(cond), _mutex(mutex), _once1(once1), _once2(once2), _once3(once3)
|
||||||
|
{
|
||||||
|
if (pthread_create(&_thread, 0, _entry_trampoline, this) != 0) {
|
||||||
|
printf("Error: pthread_create() failed\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void join() { pthread_join(_thread, nullptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void check_pthread_once(int num_init)
|
||||||
|
{
|
||||||
|
if (once_init == num_init) return;
|
||||||
|
|
||||||
|
Genode::error("unxpected pthread_once initializer call count ",
|
||||||
|
once_init, "/", num_init);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_pthread_once()
|
||||||
|
{
|
||||||
|
printf("main thread: test pthread_once()\n");
|
||||||
|
|
||||||
|
pthread_once_t once1, once2, once3;
|
||||||
|
|
||||||
|
/* test one thread and double-init prevention */
|
||||||
|
once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once(&once1, init_once1);
|
||||||
|
pthread_once(&once1, init_once1);
|
||||||
|
check_pthread_once(1);
|
||||||
|
|
||||||
|
/* test one thread with consecutive onces */
|
||||||
|
once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once(&once1, init_once1);
|
||||||
|
pthread_once(&once2, init_once2);
|
||||||
|
pthread_once(&once3, init_once3);
|
||||||
|
check_pthread_once(3);
|
||||||
|
|
||||||
|
/* test one thread and nested pthread_once() with different onces */
|
||||||
|
once_init = 0; once1 = once2 = once3 = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once(&once1, init_once_nested);
|
||||||
|
check_pthread_once(2);
|
||||||
|
|
||||||
|
Cond cond;
|
||||||
|
|
||||||
|
Mutex<PTHREAD_MUTEX_NORMAL> mutex;
|
||||||
|
|
||||||
|
enum { NUM_THREADS = 6 };
|
||||||
|
Once_thread threads[NUM_THREADS] = {
|
||||||
|
{ 1, cond, mutex, { &once1, init_once1 }, { &once2, init_once2 }, { &once3, init_once3 } },
|
||||||
|
{ 2, cond, mutex, { &once3, init_once3 }, { &once1, init_once1 }, { &once2, init_once2 } },
|
||||||
|
{ 3, cond, mutex, { &once2, init_once2 }, { &once3, init_once3 }, { &once1, init_once1 } },
|
||||||
|
{ 4, cond, mutex, { &once1, init_once1 }, { &once2, init_once2 }, { &once3, init_once3 } },
|
||||||
|
{ 5, cond, mutex, { &once3, init_once3 }, { &once1, init_once1 }, { &once2, init_once2 } },
|
||||||
|
{ 6, cond, mutex, { &once2, init_once2 }, { &once3, init_once3 }, { &once1, init_once1 } },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 1; i <= Once_thread::ROUNDS; ++i) {
|
||||||
|
pthread_mutex_lock(mutex.mutex());
|
||||||
|
|
||||||
|
once_round = i; once_init = 0; once_round_complete = 0;
|
||||||
|
once1 = once2 = once3 = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_cond_broadcast(cond.cond());
|
||||||
|
|
||||||
|
pthread_mutex_unlock(mutex.mutex());
|
||||||
|
|
||||||
|
pthread_once(&once1, init_once1);
|
||||||
|
pthread_once(&once2, init_once2);
|
||||||
|
pthread_once(&once3, init_once3);
|
||||||
|
|
||||||
|
while (once_round_complete != NUM_THREADS)
|
||||||
|
usleep(1000);
|
||||||
|
|
||||||
|
check_pthread_once(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Once_thread &t : threads) t.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
printf("--- pthread test ---\n");
|
printf("--- pthread test ---\n");
|
||||||
@ -1212,6 +1363,7 @@ int main(int argc, char **argv)
|
|||||||
test_cleanup();
|
test_cleanup();
|
||||||
test_tls();
|
test_tls();
|
||||||
test_thread_local_destructor();
|
test_thread_local_destructor();
|
||||||
|
test_pthread_once();
|
||||||
|
|
||||||
printf("--- returning from main ---\n");
|
printf("--- returning from main ---\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user