/* * Copyright (c) 2018 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #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(posix_rw_locks, 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(posix_rw_locks, test_pthread_rwlockattr_getpshared) { test_pthread_rwlockattr_pshared_common(false, 0); } ZTEST(posix_rw_locks, 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(posix_rw_locks, NULL, NULL, before, NULL, NULL);