1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <pthread.h>
8
9 #include <zephyr/logging/log.h>
10 #include <zephyr/sys/util.h>
11 #include <zephyr/ztest.h>
12
13 #define N_THR 3
14
15 LOG_MODULE_REGISTER(posix_rwlock_test);
16
17 static pthread_rwlock_t rwlock;
18
thread_top(void * p1)19 static void *thread_top(void *p1)
20 {
21 int ret;
22 pthread_t id;
23
24 id = (pthread_t)pthread_self();
25 ret = pthread_rwlock_tryrdlock(&rwlock);
26 if (ret != 0) {
27 LOG_DBG("Not able to get RD lock on trying, try again");
28 zassert_ok(pthread_rwlock_rdlock(&rwlock), "Failed to acquire write lock");
29 }
30
31 LOG_DBG("Thread %d got RD lock", id);
32 usleep(USEC_PER_MSEC);
33 LOG_DBG("Thread %d releasing RD lock", id);
34 zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
35
36 LOG_DBG("Thread %d acquiring WR lock", id);
37 ret = pthread_rwlock_trywrlock(&rwlock);
38 if (ret != 0) {
39 zassert_ok(pthread_rwlock_wrlock(&rwlock), "Failed to acquire WR lock");
40 }
41
42 LOG_DBG("Thread %d acquired WR lock", id);
43 usleep(USEC_PER_MSEC);
44 LOG_DBG("Thread %d releasing WR lock", id);
45 zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
46
47 return NULL;
48 }
49
ZTEST(rwlock,test_rw_lock)50 ZTEST(rwlock, test_rw_lock)
51 {
52 int ret;
53 pthread_t newthread[N_THR];
54 struct timespec time;
55 void *status;
56
57 time.tv_sec = 1;
58 time.tv_nsec = 0;
59
60 zassert_equal(pthread_rwlock_destroy(&rwlock), EINVAL);
61 zassert_equal(pthread_rwlock_rdlock(&rwlock), EINVAL);
62 zassert_equal(pthread_rwlock_wrlock(&rwlock), EINVAL);
63 zassert_equal(pthread_rwlock_trywrlock(&rwlock), EINVAL);
64 zassert_equal(pthread_rwlock_tryrdlock(&rwlock), EINVAL);
65 zassert_equal(pthread_rwlock_timedwrlock(&rwlock, &time), EINVAL);
66 zassert_equal(pthread_rwlock_timedrdlock(&rwlock, &time), EINVAL);
67 zassert_equal(pthread_rwlock_unlock(&rwlock), EINVAL);
68
69 zassert_ok(pthread_rwlock_init(&rwlock, NULL), "Failed to create rwlock");
70 LOG_DBG("main acquire WR lock and 3 threads acquire RD lock");
71 zassert_ok(pthread_rwlock_timedwrlock(&rwlock, &time), "Failed to acquire write lock");
72
73 /* Creating N preemptive threads in increasing order of priority */
74 for (int i = 0; i < N_THR; i++) {
75 zassert_ok(pthread_create(&newthread[i], NULL, thread_top, NULL),
76 "Low memory to thread new thread");
77 }
78
79 /* Delay to give change to child threads to run */
80 usleep(USEC_PER_MSEC);
81 LOG_DBG("Parent thread releasing WR lock");
82 zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
83
84 /* Let child threads acquire RD Lock */
85 usleep(USEC_PER_MSEC);
86 LOG_DBG("Parent thread acquiring WR lock again");
87
88 time.tv_sec = 2;
89 time.tv_nsec = 0;
90 ret = pthread_rwlock_timedwrlock(&rwlock, &time);
91 if (ret) {
92 zassert_ok(pthread_rwlock_wrlock(&rwlock), "Failed to acquire write lock");
93 }
94
95 LOG_DBG("Parent thread acquired WR lock again");
96 usleep(USEC_PER_MSEC);
97 LOG_DBG("Parent thread releasing WR lock again");
98 zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
99
100 LOG_DBG("3 threads acquire WR lock");
101 LOG_DBG("Main thread acquiring RD lock");
102
103 ret = pthread_rwlock_timedrdlock(&rwlock, &time);
104 if (ret != 0) {
105 zassert_ok(pthread_rwlock_rdlock(&rwlock), "Failed to lock");
106 }
107
108 LOG_DBG("Main thread acquired RD lock");
109 usleep(USEC_PER_MSEC);
110 LOG_DBG("Main thread releasing RD lock");
111 zassert_ok(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
112
113 for (int i = 0; i < N_THR; i++) {
114 zassert_ok(pthread_join(newthread[i], &status), "Failed to join");
115 }
116
117 zassert_ok(pthread_rwlock_destroy(&rwlock), "Failed to destroy rwlock");
118 }
119
before(void * arg)120 static void before(void *arg)
121 {
122 ARG_UNUSED(arg);
123
124 if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) {
125 /* skip redundant testing if there is no thread pool / heap allocation */
126 ztest_test_skip();
127 }
128 }
129
130 ZTEST_SUITE(rwlock, NULL, NULL, before, NULL, NULL);
131