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