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