xref: /aosp_15_r20/external/ltp/testcases/open_posix_testsuite/conformance/interfaces/sem_post/8-1.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 /*
2  * Copyright (c) 2003-2004, Intel Corporation. All rights reserved.
3  * This file is licensed under the GPL license.  For the full content
4  * of this license, see the COPYING file at the top level of this
5  * source tree.
6  * [email protected] 2004-03
7  *
8  * Cleaned up the code and uncommented the lock synchronization.
9  * Cyril Hrubis <[email protected]> 2011
10  */
11 
12 /*
13  * If the Process Scheduling option is supported, the thread to be unblocked
14  * shall be chosen in a manner appropriate to the scheduling policies
15  * and parameters in effect for the blocked threads.
16  * In the case of the schedulers SCHED_FIFO and SCHED_RR, the highest
17  * priority waiting thread shall be unblocked, and if there is
18  * more than one highest priority thread blocked waiting for the semaphore,
19  * then the highest priority thread that has been waiting the
20  * longest shall be unblocked.
21  * If the Process Scheduling option is not defined, the choice of a thread
22  * to unblock is unspecified.
23  *
24  * Test Steps:
25  * Here we test SCHED_FIFO
26  * 1. Parent locks a semaphore, it has highest priority P0.
27  * 2. It forks 2 child processes 1, 2, as for priority P1, P2, P0 > P2 > P1
28  * 3. The children lock the semaphore.
29  *    Make sure the two children are waiting.
30  * 4. Parent forks another child 3, with priority P3, P3 = P2, it locks
31  *    the semaphore too.
32  * 5. Parent unlocks the semaphore, make sure the children
33  *    wake up in the order of  2 -> 3 -> 1
34  */
35 
36 #include <stdio.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <semaphore.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include "posixtest.h"
43 #include <sched.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <stdlib.h>
47 #include "proc.h"
48 
49 #define TEST "sem_post_8-1"
50 
51 static char semname[28];
52 static char semname_1[28];	/* Used to record state */
53 
set_my_prio(int priority)54 static int set_my_prio(int priority)
55 {
56 	struct sched_param sp;
57 	sp.sched_priority = priority;
58 
59 	if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) {
60 		perror("sched_setscheduler()");
61 		return -1;
62 	}
63 
64 	return 0;
65 }
66 
get_my_prio(void)67 static int get_my_prio(void)
68 {
69 	struct sched_param sp;
70 
71 	if (sched_getparam(0, &sp) == -1) {
72 		perror("sched_getparam()");
73 		return -1;
74 	}
75 
76 	return sp.sched_priority;
77 }
78 
child_fn(int priority,int id)79 static int child_fn(int priority, int id)
80 {
81 	sem_t *sem, *sem_1;
82 
83 	if (set_my_prio(priority))
84 		exit(-1);
85 
86 	sem = sem_open(semname, 0);
87 	if (sem == SEM_FAILED) {
88 		perror("sem_open(semname)");
89 		exit(-1);
90 	}
91 
92 	sem_1 = sem_open(semname_1, 0);
93 	if (sem_1 == SEM_FAILED) {
94 		perror("sem_open(semname_1)");
95 		exit(-1);
96 	}
97 
98 	fprintf(stderr, "child %d try to get lock, prio: %d\n",
99 		id, get_my_prio());
100 
101 	sem_wait(sem_1);
102 
103 	if (sem_wait(sem) == -1) {
104 		perror("Error at sem_wait");
105 		fprintf(stderr, "Child %d: Cannot get lock", id);
106 		exit(-1);
107 	}
108 
109 	fprintf(stderr, "child %d got lock\n", id);
110 	exit(0);
111 }
112 
main(void)113 int main(void)
114 {
115 #ifndef _POSIX_PRIORITY_SCHEDULING
116 	printf("_POSIX_PRIORITY_SCHEDULING not defined\n");
117 	return PTS_UNTESTED;
118 #endif
119 	sem_t *sem, *sem_1;
120 	int val;
121 	int priority;
122 	pid_t c_1, c_2, c_3, ret_pid;
123 	int retval = PTS_UNRESOLVED;
124 	int status;
125 	struct timespec sync_wait_ts = {0, 100000};
126 
127 	snprintf(semname, sizeof(semname), "/" TEST "_%d", getpid());
128 
129 	sem = sem_open(semname, O_CREAT | O_EXCL, 0777, 1);
130 	if (sem == SEM_FAILED) {
131 		perror("sem_open(semname)");
132 		return PTS_UNRESOLVED;
133 	}
134 
135 	snprintf(semname_1, sizeof(semname_1), "/" TEST "_%d_1", getpid());
136 
137 	sem_1 = sem_open(semname_1, O_CREAT | O_EXCL, 0777, 3);
138 	if (sem_1 == SEM_FAILED) {
139 		perror("sem_open(semname_1)");
140 		sem_unlink(semname);
141 		return PTS_UNRESOLVED;
142 	}
143 
144 	/* The parent has highest priority */
145 	priority = sched_get_priority_min(SCHED_FIFO) + 3;
146 	if (set_my_prio(priority) == -1) {
147 		retval = PTS_UNRESOLVED;
148 		goto clean_up;
149 	}
150 
151 	/* Lock Semaphore */
152 	if (sem_wait(sem) == -1) {
153 		perror("sem_wait()");
154 		retval = PTS_UNRESOLVED;
155 		goto clean_up;
156 	}
157 
158 	c_1 = fork();
159 	switch (c_1) {
160 	case 0:
161 		child_fn(priority - 2, 1);
162 		break;
163 	case -1:
164 		perror("fork()");
165 		retval = PTS_UNRESOLVED;
166 		goto clean_up;
167 		break;
168 	}
169 	fprintf(stderr, "P: child_1: %d forked\n", c_1);
170 
171 	c_2 = fork();
172 	switch (c_2) {
173 	case 0:
174 		child_fn(priority - 1, 2);
175 		break;
176 	case -1:
177 		perror("fork()");
178 		retval = PTS_UNRESOLVED;
179 		goto clean_up;
180 		break;
181 	}
182 	fprintf(stderr, "P: child_2: %d forked\n", c_2);
183 
184 	/* Make sure the two children has been waiting */
185 	do {
186 		nanosleep(&sync_wait_ts, NULL);
187 		sem_getvalue(sem_1, &val);
188 	} while (val != 1);
189 	tst_process_state_wait3(c_1, 'S', 2);
190 	tst_process_state_wait3(c_2, 'S', 2);
191 
192 	c_3 = fork();
193 	switch (c_3) {
194 	case 0:
195 		child_fn(priority - 1, 3);
196 		break;
197 	case -1:
198 		perror("fork()");
199 		retval = PTS_UNRESOLVED;
200 		goto clean_up;
201 		break;
202 	}
203 	fprintf(stderr, "P: child_3: %d forked\n", c_3);
204 
205 	/* Make sure child 3 has been waiting for the lock */
206 	do {
207 		nanosleep(&sync_wait_ts, NULL);
208 		sem_getvalue(sem_1, &val);
209 	} while (val != 0);
210 	tst_process_state_wait3(c_3, 'S', 2);
211 
212 	/* Ok, let's release the lock */
213 	fprintf(stderr, "P: release lock\n");
214 	sem_post(sem);
215 	ret_pid = wait(&status);
216 	if (ret_pid == c_2 && WIFEXITED(status)
217 	    && WEXITSTATUS(status) == 0) {
218 		fprintf(stderr, "P: release lock\n");
219 		sem_post(sem);
220 		ret_pid = wait(&status);
221 		if (ret_pid == c_3 && WIFEXITED(status)
222 		    && WEXITSTATUS(status) == 0) {
223 			fprintf(stderr, "P: release lock\n");
224 			sem_post(sem);
225 			ret_pid = wait(&status);
226 			if (ret_pid == c_1 && WIFEXITED(status)
227 			    && WEXITSTATUS(status) == 0) {
228 				printf("Test PASSED\n");
229 				retval = PTS_PASS;
230 				goto clean_up;
231 			}
232 			printf("Test Fail: Expect child_1: %d, got %d\n",
233 			       c_1, ret_pid);
234 			retval = PTS_FAIL;
235 			goto clean_up;
236 		} else {
237 			printf("Test Fail: Expect child_3: %d, got %d\n",
238 			       c_3, ret_pid);
239 			retval = PTS_FAIL;
240 			sem_post(sem);
241 			while ((wait(NULL) > 0)) ;
242 			goto clean_up;
243 		}
244 	} else {
245 		printf("Test Fail: Expect child_2: %d, got %d\n", c_2, ret_pid);
246 		retval = PTS_FAIL;
247 		sem_post(sem);
248 		sem_post(sem);
249 		while ((wait(NULL) > 0)) ;
250 		goto clean_up;
251 	}
252 
253 clean_up:
254 	sem_close(sem);
255 	sem_close(sem_1);
256 	sem_unlink(semname);
257 	sem_unlink(semname_1);
258 	return retval;
259 }
260