blob: a7012fc58327a127556ba959b74747ea04952c0d [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <pthread.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
#include <zephyr/ztest.h>
#define N_THR 3
LOG_MODULE_REGISTER(posix_rwlock_test);
static pthread_rwlock_t rwlock;
static void *thread_top(void *p1)
{
int ret;
pthread_t id;
id = (pthread_t)pthread_self();
ret = pthread_rwlock_tryrdlock(&rwlock);
if (ret != 0) {
LOG_DBG("Not able to get RD lock on trying, try again");
zassert_ok(pthread_rwlock_rdlock(&rwlock), "Failed to acquire write lock");
}
LOG_DBG("Thread %d got RD lock", id);
usleep(USEC_PER_MSEC);
LOG_DBG("Thread %d releasing RD lock", id);
zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
LOG_DBG("Thread %d acquiring WR lock", id);
ret = pthread_rwlock_trywrlock(&rwlock);
if (ret != 0) {
zassert_ok(pthread_rwlock_wrlock(&rwlock), "Failed to acquire WR lock");
}
LOG_DBG("Thread %d acquired WR lock", id);
usleep(USEC_PER_MSEC);
LOG_DBG("Thread %d releasing WR lock", id);
zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
return NULL;
}
ZTEST(rwlock, test_rw_lock)
{
int ret;
pthread_t newthread[N_THR];
struct timespec time;
void *status;
time.tv_sec = 1;
time.tv_nsec = 0;
zassert_equal(pthread_rwlock_destroy(&rwlock), EINVAL);
zassert_equal(pthread_rwlock_rdlock(&rwlock), EINVAL);
zassert_equal(pthread_rwlock_wrlock(&rwlock), EINVAL);
zassert_equal(pthread_rwlock_trywrlock(&rwlock), EINVAL);
zassert_equal(pthread_rwlock_tryrdlock(&rwlock), EINVAL);
zassert_equal(pthread_rwlock_timedwrlock(&rwlock, &time), EINVAL);
zassert_equal(pthread_rwlock_timedrdlock(&rwlock, &time), EINVAL);
zassert_equal(pthread_rwlock_unlock(&rwlock), EINVAL);
zassert_ok(pthread_rwlock_init(&rwlock, NULL), "Failed to create rwlock");
LOG_DBG("main acquire WR lock and 3 threads acquire RD lock");
zassert_ok(pthread_rwlock_timedwrlock(&rwlock, &time), "Failed to acquire write lock");
/* Creating N preemptive threads in increasing order of priority */
for (int i = 0; i < N_THR; i++) {
zassert_ok(pthread_create(&newthread[i], NULL, thread_top, NULL),
"Low memory to thread new thread");
}
/* Delay to give change to child threads to run */
usleep(USEC_PER_MSEC);
LOG_DBG("Parent thread releasing WR lock");
zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
/* Let child threads acquire RD Lock */
usleep(USEC_PER_MSEC);
LOG_DBG("Parent thread acquiring WR lock again");
time.tv_sec = 2;
time.tv_nsec = 0;
ret = pthread_rwlock_timedwrlock(&rwlock, &time);
if (ret) {
zassert_ok(pthread_rwlock_wrlock(&rwlock), "Failed to acquire write lock");
}
LOG_DBG("Parent thread acquired WR lock again");
usleep(USEC_PER_MSEC);
LOG_DBG("Parent thread releasing WR lock again");
zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
LOG_DBG("3 threads acquire WR lock");
LOG_DBG("Main thread acquiring RD lock");
ret = pthread_rwlock_timedrdlock(&rwlock, &time);
if (ret != 0) {
zassert_ok(pthread_rwlock_rdlock(&rwlock), "Failed to lock");
}
LOG_DBG("Main thread acquired RD lock");
usleep(USEC_PER_MSEC);
LOG_DBG("Main thread releasing RD lock");
zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
for (int i = 0; i < N_THR; i++) {
zassert_ok(pthread_join(newthread[i], &status), "Failed to join");
}
zassert_ok(pthread_rwlock_destroy(&rwlock), "Failed to destroy rwlock");
}
static void test_pthread_rwlockattr_pshared_common(bool set, int pshared)
{
int tmp_pshared = 4242;
pthread_rwlockattr_t attr;
zassert_ok(pthread_rwlockattr_init(&attr));
zassert_ok(pthread_rwlockattr_getpshared(&attr, &tmp_pshared));
zassert_equal(tmp_pshared, PTHREAD_PROCESS_PRIVATE);
if (set) {
zassert_ok(pthread_rwlockattr_setpshared(&attr, pshared));
zassert_ok(pthread_rwlockattr_getpshared(&attr, &tmp_pshared));
zassert_equal(tmp_pshared, pshared);
}
zassert_ok(pthread_rwlockattr_destroy(&attr));
}
ZTEST(rwlock, test_pthread_rwlockattr_getpshared)
{
test_pthread_rwlockattr_pshared_common(false, 0);
}
ZTEST(rwlock, test_pthread_rwlockattr_setpshared)
{
test_pthread_rwlockattr_pshared_common(true, PTHREAD_PROCESS_PRIVATE);
test_pthread_rwlockattr_pshared_common(true, PTHREAD_PROCESS_SHARED);
}
static void before(void *arg)
{
ARG_UNUSED(arg);
if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) {
/* skip redundant testing if there is no thread pool / heap allocation */
ztest_test_skip();
}
}
ZTEST_SUITE(rwlock, NULL, NULL, before, NULL, NULL);