• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License version 2.
4  *
5  *  This program is distributed in the hope that it will be useful,
6  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
7  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8  *  GNU General Public License for more details.
9  *
10  *
11  * Test that the process specified by the pid argument preempt a lowest
12  * priority running process, if the priority of the process specified by the
13  * pid argument is set higher than that of the lowest priority running process
14  * and if the specified process is ready to run.
15  *
16  * NO OTHER REALTIME PROCESS SHOULD RUN WHEN RUNNING THIS TEST.
17  *
18  * There is no portable way to get the number of CPUs but the test should work
19  * for most of UNIX system (including but not limited to: Linux, Solaris, AIX,
20  * HPUX, *BSD).
21  * This test used shared memory.
22  * Steps:
23  *   1. Create a share memory segment.
24  *   2. Change the policy to SCHED_FIFO and set minimum priority.
25  *   3. Create NB_CPU-1 children processes which set their own priority to the
26  *      higher value and use all but one processor.
27  *   4. Create a child with the same priority.
28  *   4. Call sched_setparam with an mean priority and the pid value of the
29  *      last children.
30  *   5. Check if the shared value has been changed by the child process. If
31  *      not, the test fail.
32  */
33 #include "affinity.h"
34 
35 #include <errno.h>
36 #include <sched.h>
37 #include <stdio.h>
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <sys/ipc.h>
41 #include <sys/shm.h>
42 #include <time.h>
43 #include <unistd.h>
44 #include "posixtest.h"
45 #include "ncpu.h"
46 
47 static int nb_cpu;
48 static int *shmptr;
49 static int mean_prio;
50 
child_process(void)51 static void child_process(void)
52 {
53 	struct sched_param param;
54 	time_t t1, t2;
55 
56 	param.sched_priority = sched_get_priority_max(SCHED_FIFO);
57 	if (sched_setparam(getpid(), &param) != 0) {
58 		perror("An error occurs when calling sched_setparam()");
59 		return;
60 	}
61 
62 	t1 = time(NULL);
63 	do {
64 		t2 = time(NULL);
65 	} while (difftime(t2, t1) <= 2);
66 }
67 
test_process(void)68 static void test_process(void)
69 {
70 	struct sched_param param;
71 	time_t t1, t2;
72 
73 	t1 = time(NULL);
74 	do {
75 		sched_getparam(getpid(), &param);
76 		(*shmptr) = param.sched_priority;
77 		/* if we can see that our priority has changed
78 		 * that means we preempted parent, so we are done */
79 		if ((*shmptr) == mean_prio)
80 			break;
81 
82 		t2 = time(NULL);
83 		/* OS-es supporting set_affinity(), like Linux, will
84 		 * have only one parent and child process competing
85 		 * for same CPU. Since code path in parent does not
86 		 * block between fork() and sched_setparam(), child
87 		 * should run only after parent boosted its priority.
88 		 * Situation on other OS-es is a bit less predictable,
89 		 * as these will spawn ncpu-1 children, which run at max
90 		 * priority and could (though unlikely) preempt parent.
91 		 * Rather than risking deadlock, keep the sched_yield()
92 		 * call in loop as it is harmless. */
93 		sched_yield();
94 	} while (difftime(t2, t1) <= 2);
95 	pause();
96 }
97 
kill_children(int * child_pid,int count)98 static void kill_children(int *child_pid, int count)
99 {
100 	int i;
101 
102 	for (i = 0; i < count; i++)
103 		kill(child_pid[i], SIGTERM);
104 	free(child_pid);
105 }
106 
main(void)107 int main(void)
108 {
109 	int *child_pid, oldcount, newcount, shm_id, i;
110 	struct sched_param param;
111 	key_t key;
112 	int rc = set_affinity_single();
113 	if (rc) {
114 		nb_cpu = get_ncpu();
115 		if (nb_cpu == -1) {
116 			printf("Can not get the number of"
117 			       " CPUs of the machine.\n");
118 			return PTS_UNRESOLVED;
119 		}
120 	} else {
121 		nb_cpu = 1;
122 	}
123 
124 	mean_prio = (sched_get_priority_min(SCHED_FIFO) +
125 		sched_get_priority_max(SCHED_FIFO)) / 2;
126 	child_pid = malloc(nb_cpu * sizeof(int));
127 
128 	key = ftok("conformance/interfaces/sched_setparam/9-1.c", 1234);
129 	shm_id = shmget(key, sizeof(int), IPC_CREAT | 0600);
130 	if (shm_id < 0) {
131 		perror("An error occurs when calling shmget()");
132 		return PTS_UNRESOLVED;
133 	}
134 
135 	shmptr = shmat(shm_id, 0, 0);
136 	if (shmptr == (void *)-1) {
137 		perror("An error occurs when calling shmat()");
138 		return PTS_UNRESOLVED;
139 	}
140 	*shmptr = 0;
141 
142 	param.sched_priority = sched_get_priority_min(SCHED_FIFO);
143 	if (sched_setscheduler(getpid(), SCHED_FIFO, &param) != 0) {
144 		if (errno == EPERM) {
145 			printf("This process does not have the permission"
146 			       " to set its own scheduling parameter.\n"
147 			       "Try to launch this test as root\n");
148 		} else {
149 			perror("An error occurs when calling"
150 			       " sched_setscheduler()");
151 		}
152 		return PTS_UNRESOLVED;
153 	}
154 
155 	for (i = 0; i < (nb_cpu - 1); i++) {
156 		child_pid[i] = fork();
157 		if (child_pid[i] == -1) {
158 			perror("An error occurs when calling fork()");
159 			kill_children(child_pid, i);
160 			return PTS_UNRESOLVED;
161 		} else if (child_pid[i] == 0) {
162 
163 			child_process();
164 
165 			printf("This code should not be executed.\n");
166 			return PTS_UNRESOLVED;
167 		}
168 	}
169 
170 	child_pid[i] = fork();
171 	if (child_pid[i] == -1) {
172 		perror("An error occurs when calling fork()");
173 		kill_children(child_pid, i);
174 		return PTS_UNRESOLVED;
175 	} else if (child_pid[i] == 0) {
176 
177 		test_process();
178 
179 		printf("This code should not be executed.\n");
180 		return PTS_UNRESOLVED;
181 	}
182 
183 	param.sched_priority = mean_prio;
184 	oldcount = *shmptr;
185 	if (sched_setparam(child_pid[i], &param) != 0) {
186 		perror("An error occurs when calling sched_setparam()");
187 		kill_children(child_pid, nb_cpu);
188 		return PTS_UNRESOLVED;
189 	}
190 	newcount = *shmptr;
191 
192 	if (newcount == oldcount) {
193 		printf("The target process does not preempt"
194 		       " the calling process\n");
195 		kill_children(child_pid, nb_cpu);
196 		return PTS_FAIL;
197 	}
198 
199 	printf("Test PASSED\n");
200 	kill_children(child_pid, nb_cpu);
201 	return PTS_PASS;
202 }
203