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