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/sys/util.h>
10 #include <zephyr/ztest.h>
11 
12 #define N_THR 3
13 #define STACKSZ (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
14 
15 K_THREAD_STACK_ARRAY_DEFINE(stack, N_THR, STACKSZ);
16 pthread_rwlock_t rwlock;
17 
thread_top(void * p1)18 static void *thread_top(void *p1)
19 {
20 	pthread_t pthread;
21 	uint32_t policy, ret = 0U;
22 	struct sched_param param;
23 	int id = POINTER_TO_INT(p1);
24 
25 	pthread = (pthread_t) pthread_self();
26 	pthread_getschedparam(pthread, &policy, &param);
27 	printk("Thread %d scheduling policy = %d & priority %d started\n",
28 	       id, policy, param.sched_priority);
29 
30 	ret = pthread_rwlock_tryrdlock(&rwlock);
31 	if (ret) {
32 		printk("Not able to get RD lock on trying, try again\n");
33 		zassert_false(pthread_rwlock_rdlock(&rwlock),
34 			      "Failed to acquire write lock");
35 	}
36 
37 	printk("Thread %d got RD lock\n", id);
38 	usleep(USEC_PER_MSEC);
39 	printk("Thread %d releasing RD lock\n", id);
40 	zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
41 
42 	printk("Thread %d acquiring WR lock\n", id);
43 	ret = pthread_rwlock_trywrlock(&rwlock);
44 	if (ret != 0U) {
45 		zassert_false(pthread_rwlock_wrlock(&rwlock),
46 			      "Failed to acquire WR lock");
47 	}
48 
49 	printk("Thread %d acquired WR lock\n", id);
50 	usleep(USEC_PER_MSEC);
51 	printk("Thread %d releasing WR lock\n", id);
52 	zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
53 	pthread_exit(NULL);
54 	return NULL;
55 }
56 
ZTEST(posix_apis,test_rw_lock)57 ZTEST(posix_apis, test_rw_lock)
58 {
59 	int32_t i, ret;
60 	pthread_attr_t attr[N_THR];
61 	struct sched_param schedparam;
62 	pthread_t newthread[N_THR];
63 	struct timespec time;
64 	void *status;
65 
66 	time.tv_sec = 1;
67 	time.tv_nsec = 0;
68 
69 	zassert_equal(pthread_rwlock_destroy(&rwlock), EINVAL);
70 	zassert_equal(pthread_rwlock_rdlock(&rwlock), EINVAL);
71 	zassert_equal(pthread_rwlock_wrlock(&rwlock), EINVAL);
72 	zassert_equal(pthread_rwlock_trywrlock(&rwlock), EINVAL);
73 	zassert_equal(pthread_rwlock_tryrdlock(&rwlock), EINVAL);
74 	zassert_equal(pthread_rwlock_timedwrlock(&rwlock, &time), EINVAL);
75 	zassert_equal(pthread_rwlock_timedrdlock(&rwlock, &time), EINVAL);
76 	zassert_equal(pthread_rwlock_unlock(&rwlock), EINVAL);
77 
78 	zassert_false(pthread_rwlock_init(&rwlock, NULL),
79 		      "Failed to create rwlock");
80 	printk("\nmain acquire WR lock and 3 threads acquire RD lock\n");
81 	zassert_false(pthread_rwlock_timedwrlock(&rwlock, &time),
82 		      "Failed to acquire write lock");
83 
84 	/* Creating N preemptive threads in increasing order of priority */
85 	for (i = 0; i < N_THR; i++) {
86 		zassert_equal(pthread_attr_init(&attr[i]), 0,
87 			      "Unable to create pthread object attrib");
88 
89 		/* Setting scheduling priority */
90 		schedparam.sched_priority = i + 1;
91 		pthread_attr_setschedparam(&attr[i], &schedparam);
92 
93 		/* Setting stack */
94 		pthread_attr_setstack(&attr[i], &stack[i][0], STACKSZ);
95 
96 		ret = pthread_create(&newthread[i], &attr[i], thread_top,
97 				     INT_TO_POINTER(i));
98 		zassert_false(ret, "Low memory to thread new thread");
99 
100 	}
101 
102 	/* Delay to give change to child threads to run */
103 	usleep(USEC_PER_MSEC);
104 	printk("Parent thread releasing WR lock\n");
105 	zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
106 
107 	/* Let child threads acquire RD Lock */
108 	usleep(USEC_PER_MSEC);
109 	printk("Parent thread acquiring WR lock again\n");
110 
111 	time.tv_sec = 2;
112 	time.tv_nsec = 0;
113 	ret = pthread_rwlock_timedwrlock(&rwlock, &time);
114 
115 	if (ret) {
116 		zassert_false(pthread_rwlock_wrlock(&rwlock),
117 			      "Failed to acquire write lock");
118 	}
119 
120 	printk("Parent thread acquired WR lock again\n");
121 	usleep(USEC_PER_MSEC);
122 	printk("Parent thread releasing WR lock again\n");
123 	zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
124 
125 	printk("\n3 threads acquire WR lock\n");
126 	printk("Main thread acquiring RD lock\n");
127 
128 	ret = pthread_rwlock_timedrdlock(&rwlock, &time);
129 
130 	if (ret != 0) {
131 		zassert_false(pthread_rwlock_rdlock(&rwlock), "Failed to lock");
132 	}
133 
134 	printk("Main thread acquired RD lock\n");
135 	usleep(USEC_PER_MSEC);
136 	printk("Main thread releasing RD lock\n");
137 	zassert_false(pthread_rwlock_unlock(&rwlock), "Failed to unlock");
138 
139 	for (i = 0; i < N_THR; i++) {
140 		zassert_false(pthread_join(newthread[i], &status),
141 			      "Failed to join");
142 	}
143 
144 	zassert_false(pthread_rwlock_destroy(&rwlock),
145 		      "Failed to destroy rwlock");
146 }
147