posix: pthread: add option for pthread_create() barrier
To enable testing, introduce `CONFIG_PTHREAD_CREATE_BARRIER`. Some observations were made that running several Qemu SMP targets concurrently could lead to synchronization problems. On such targets, it was found that the synchronization issues were mitigated by introducing a `pthread_barrier_t` shared between `pthread_create()` and the spawned thread. It is suggested to enable the option when running many SMP tests concurrently in several parallel Qemu processes, e.g. with `twister`. Signed-off-by: Christopher Friedt <cfriedt@meta.com>
This commit is contained in:
parent
85e18746b8
commit
e1f8ea1ad7
@ -35,6 +35,17 @@ config MAX_PTHREAD_COUNT
|
||||
help
|
||||
Maximum number of simultaneously active threads in a POSIX application.
|
||||
|
||||
config PTHREAD_CREATE_BARRIER
|
||||
bool "Use a pthread_barrier_t to serialize pthread_create()"
|
||||
help
|
||||
When running several SMP applications in parallel instances of Qemu,
|
||||
e.g. via twister, explicit serialization may be required between
|
||||
pthread_create() and zephyr_thread_wrapper() when spawning and joining
|
||||
many pthreads concurrently.
|
||||
|
||||
On such systems, say Y here to introduce explicit serialization
|
||||
via pthread_barrier_wait().
|
||||
|
||||
config MAX_PTHREAD_MUTEX_COUNT
|
||||
int "Maximum simultaneously active mutex count in POSIX application"
|
||||
default 5
|
||||
|
||||
@ -266,9 +266,18 @@ static void posix_thread_finalize(struct posix_thread *t, void *retval)
|
||||
FUNC_NORETURN
|
||||
static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
int err;
|
||||
int barrier;
|
||||
void *(*fun_ptr)(void *arg) = arg2;
|
||||
struct posix_thread *t = CONTAINER_OF(k_current_get(), struct posix_thread, thread);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) {
|
||||
/* cross the barrier so that pthread_create() can continue */
|
||||
barrier = POINTER_TO_UINT(arg3);
|
||||
err = pthread_barrier_wait(&barrier);
|
||||
__ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD);
|
||||
}
|
||||
|
||||
posix_thread_finalize(t, fun_ptr(arg1));
|
||||
|
||||
CODE_UNREACHABLE;
|
||||
@ -285,7 +294,9 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
|
||||
int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadroutine)(void *),
|
||||
void *arg)
|
||||
{
|
||||
int err;
|
||||
k_spinlock_key_t key;
|
||||
pthread_barrier_t barrier;
|
||||
struct posix_thread *safe_t;
|
||||
struct posix_thread *t = NULL;
|
||||
const struct pthread_attr *attr = (const struct pthread_attr *)_attr;
|
||||
@ -324,6 +335,19 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou
|
||||
}
|
||||
k_spin_unlock(&pthread_pool_lock, key);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) {
|
||||
err = pthread_barrier_init(&barrier, NULL, 2);
|
||||
if (err != 0) {
|
||||
/* cannot allocate barrier. move thread back to ready_q */
|
||||
key = k_spin_lock(&pthread_pool_lock);
|
||||
sys_dlist_remove(&t->q_node);
|
||||
sys_dlist_append(&ready_q, &t->q_node);
|
||||
t->qid = POSIX_THREAD_READY_Q;
|
||||
k_spin_unlock(&pthread_pool_lock, key);
|
||||
t = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (t == NULL) {
|
||||
/* no threads are ready */
|
||||
return EAGAIN;
|
||||
@ -331,10 +355,20 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou
|
||||
|
||||
/* spawn the thread */
|
||||
k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper,
|
||||
(void *)arg, threadroutine, NULL,
|
||||
(void *)arg, threadroutine,
|
||||
IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier)
|
||||
: NULL,
|
||||
posix_to_zephyr_priority(attr->priority, attr->schedpolicy), attr->flags,
|
||||
K_MSEC(attr->delayedstart));
|
||||
|
||||
if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) {
|
||||
/* wait for the spawned thread to cross our barrier */
|
||||
err = pthread_barrier_wait(&barrier);
|
||||
__ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD);
|
||||
err = pthread_barrier_destroy(&barrier);
|
||||
__ASSERT_NO_MSG(err == 0);
|
||||
}
|
||||
|
||||
/* finally provide the initialized thread to the caller */
|
||||
*th = mark_pthread_obj_initialized(posix_thread_to_offset(t));
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user