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(posix_rw_locks,test_rw_lock)50 ZTEST(posix_rw_locks, 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 
test_pthread_rwlockattr_pshared_common(bool set,int pshared)120 static void test_pthread_rwlockattr_pshared_common(bool set, int pshared)
121 {
122 	int tmp_pshared = 4242;
123 	pthread_rwlockattr_t attr;
124 
125 	zassert_ok(pthread_rwlockattr_init(&attr));
126 	zassert_ok(pthread_rwlockattr_getpshared(&attr, &tmp_pshared));
127 	zassert_equal(tmp_pshared, PTHREAD_PROCESS_PRIVATE);
128 	if (set) {
129 		zassert_ok(pthread_rwlockattr_setpshared(&attr, pshared));
130 		zassert_ok(pthread_rwlockattr_getpshared(&attr, &tmp_pshared));
131 		zassert_equal(tmp_pshared, pshared);
132 	}
133 	zassert_ok(pthread_rwlockattr_destroy(&attr));
134 }
135 
ZTEST(posix_rw_locks,test_pthread_rwlockattr_getpshared)136 ZTEST(posix_rw_locks, test_pthread_rwlockattr_getpshared)
137 {
138 	test_pthread_rwlockattr_pshared_common(false, 0);
139 }
140 
ZTEST(posix_rw_locks,test_pthread_rwlockattr_setpshared)141 ZTEST(posix_rw_locks, test_pthread_rwlockattr_setpshared)
142 {
143 	test_pthread_rwlockattr_pshared_common(true, PTHREAD_PROCESS_PRIVATE);
144 	test_pthread_rwlockattr_pshared_common(true, PTHREAD_PROCESS_SHARED);
145 }
146 
before(void * arg)147 static void before(void *arg)
148 {
149 	ARG_UNUSED(arg);
150 
151 	if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) {
152 		/* skip redundant testing if there is no thread pool / heap allocation */
153 		ztest_test_skip();
154 	}
155 }
156 
157 ZTEST_SUITE(posix_rw_locks, NULL, NULL, before, NULL, NULL);
158