xref: /haiku/src/tests/system/libroot/posix/xsi_sem_test1.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/mman.h>
14 #include <sys/sem.h>
15 #include <sys/stat.h>
16 #include <sys/time.h>
17 #include <sys/wait.h>
18 #include <time.h>
19 
20 #include <OS.h>
21 
22 #include "TestUnitUtils.h"
23 
24 #define KEY			((key_t)12345)
25 #define NUM_OF_SEMS	10
26 
27 union semun {
28 	int val;
29 	struct semid_ds *buf;
30 	unsigned short *array;
31 };
32 
33 
34 static status_t
35 remove_semaphore(int semID)
36 {
37 	return semctl(semID, 0, IPC_RMID, 0);
38 }
39 
40 
41 static void
42 test_semget()
43 {
44 	TEST_SET("semget({IPC_PRIVATE, key})");
45 
46 	const char* currentTest = NULL;
47 
48 	// Open private set with IPC_PRIVATE
49 	TEST("semget(IPC_PRIVATE) - private");
50 	int semID = semget(IPC_PRIVATE, NUM_OF_SEMS, S_IRUSR | S_IWUSR);
51 	assert_posix_bool_success(semID != -1);
52 
53 	// Destroy private semaphore
54 	TEST("semctl(IPC_RMID) - private");
55 	status_t status = remove_semaphore(semID);
56 	assert_posix_bool_success(status != -1);
57 
58 	// Open non-private non-existing set with IPC_CREAT
59 	TEST("semget(KEY, IPC_CREAT) non-existing");
60 	semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
61 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
62 	assert_posix_bool_success(status != -1);
63 
64 	// Re-open non-private existing without IPC_CREAT
65 	TEST("semget(KEY) re-open existing without IPC_CREAT");
66 	int returnID = semget(KEY, 0, 0);
67 	assert_equals(semID, returnID);
68 
69 	// Re-open non-private existing with IPC_CREAT
70 	TEST("semget(IPC_CREATE) re-open existing with IPC_CREAT");
71 	returnID = semget(KEY, 0, IPC_CREAT | IPC_EXCL);
72 	assert_posix_bool_success(errno == EEXIST);
73 
74 	// Destroy non-private semaphore
75 	TEST("semctl(IPC_RMID)");
76 	status = remove_semaphore(semID);
77 	assert_posix_bool_success(status != -1);
78 
79 	// Open non-private non-existing without IPC_CREAT
80 	TEST("semget(IPC_CREATE) non-existing without IPC_CREAT");
81 	semID = semget(KEY, NUM_OF_SEMS, IPC_EXCL | S_IRUSR | S_IWUSR
82 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
83 	assert_posix_bool_success(errno == ENOENT);
84 
85 	// Destroy non-existing semaphore
86 	TEST("semctl()");
87 	status = remove_semaphore(semID);
88 	assert_posix_bool_success(errno == EINVAL);
89 
90 	TEST("done");
91 }
92 
93 
94 static void
95 test_semop2()
96 {
97 	TEST_SET("semop2()");
98 
99 	const char* currentTest = NULL;
100 
101 	// Re-open non-private existing without IPC_CREAT
102 	TEST("semget(KEY) re-open existing without IPC_CREAT");
103 	int returnedID = semget(KEY, 0, 0);
104 	assert_posix_bool_success(returnedID != -1);
105 
106 	TEST("semop(IPC_NOWAIT) - wait for zero");
107 	// Set up array of semaphores
108 	struct sembuf array[NUM_OF_SEMS];
109 	for (int i = 0; i < NUM_OF_SEMS; i++) {
110 		array[i].sem_num = i;
111 		array[i].sem_op = 0;
112 		array[i].sem_flg = IPC_NOWAIT;
113 	}
114 	semop(returnedID, array, NUM_OF_SEMS);
115 	assert_posix_bool_success(errno == EAGAIN);
116 
117 	TEST("semop(IPC_NOWAIT) - wait to increase");
118 	for (int i = 0; i < NUM_OF_SEMS; i++) {
119 		array[i].sem_num = i;
120 		array[i].sem_op = -9;
121 		array[i].sem_flg = IPC_NOWAIT;
122 	}
123 	semop(returnedID, array, NUM_OF_SEMS);
124 	assert_posix_bool_success(errno == EAGAIN);
125 
126 	TEST("semop(IPC_NOWAIT) - acquire resource sem #0");
127 	struct sembuf ops;
128 	ops.sem_num = 0;
129 	ops.sem_op = -8;
130 	ops.sem_flg = 0;
131 	status_t status = semop(returnedID, &ops, 1);
132 	assert_posix_bool_success(status != -1);
133 
134 	TEST("semop(IPC_NOWAIT) - acquire zero sem #0");
135 	ops.sem_num = 0;
136 	ops.sem_op = 0;
137 	ops.sem_flg = 0;
138 	status = semop(returnedID, &ops, 1);
139 
140 	TEST("semop(IPC_NOWAIT) - revert semop sem #0");
141 	ops.sem_num = 0;
142 	ops.sem_op = 8;
143 	ops.sem_flg = 0;
144 	status = semop(returnedID, &ops, 1);
145 
146 	// Decrease to zero even semaphores and
147 	// use SEM_UNDO flag on odd semaphores in order
148 	// to wake up the father on exit
149 	// Set up array of semaphores
150 	for (int i = 0; i < NUM_OF_SEMS; i++) {
151 		array[i].sem_num = i;
152 		array[i].sem_op = -8;
153 		if (i % 2)
154 			array[i].sem_flg = 0;
155 		else
156 			array[i].sem_flg = SEM_UNDO;
157 	}
158 	TEST("semop() - father");
159 	status = semop(returnedID, array, NUM_OF_SEMS);
160 	assert_posix_bool_success(status != -1);
161 
162 	TEST("done");
163 }
164 
165 
166 static void
167 test_semop()
168 {
169 	TEST_SET("semop()");
170 	const char* currentTest = NULL;
171 
172 	// Open non-private non-existing set with IPC_CREAT
173 	TEST("semget(IPC_CREATE) non-existing");
174 	int semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
175 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
176 	assert_posix_bool_success(semID != -1);
177 
178 	// SETALL
179 	TEST("semctl(SETALL)");
180 	union semun args;
181 	args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS);
182 	for (int i = 0; i < NUM_OF_SEMS; i++)
183 		args.array[i] = 8;
184 	status_t status = semctl(semID, 0, SETALL, args);
185 	assert_posix_bool_success(status != -1);
186 	free(args.array);
187 
188 	pid_t child = fork();
189 	if (child == 0) {
190 		// The child first will test the IPC_NOWAIT
191 		// feature, while the father waits for him,
192 		// by waiting for zero on even semaphores,
193 		// and to increase for odd semaphores, which
194 		// will happen on process exit due to SEM_UNDO
195 		// feature.
196 		test_semop2();
197 		exit(0);
198 	}
199 
200 	wait_for_child(child);
201 
202 	// Set up array of semaphores
203 	struct sembuf array[NUM_OF_SEMS];
204 	for (int i = 0; i < NUM_OF_SEMS; i++) {
205 		array[i].sem_num = i;
206 		if (i % 2)
207 			array[i].sem_op = 0; // wait for zero
208 		else
209 			array[i].sem_op = -8; // wait to increase
210 		array[i].sem_flg = 0;
211 	}
212 	TEST("semop() - father acquired set");
213 	status = semop(semID, array, NUM_OF_SEMS);
214 	assert_posix_bool_success(status != -1);
215 
216 	// Destroy non-private semaphore
217 	TEST("semctl(IPC_RMID)");
218 	status = remove_semaphore(semID);
219 	assert_posix_bool_success(status != 1);
220 
221 	TEST("done");
222 }
223 
224 
225 static void
226 test_semctl()
227 {
228 	TEST_SET("semctl({GETVAL, SETVAL, GETPID, GETNCNT, GETZCNT, GETALL, SETALL, IPC_STAT, IPC_SET, IPC_RMID})");
229 
230 	const char* currentTest = NULL;
231 
232 	// Open non-private non-existing set with IPC_CREAT
233 	TEST("semget(IPC_CREATE) non-existing");
234 	int semID = semget(KEY, NUM_OF_SEMS, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
235 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
236 	assert_posix_bool_success(semID != -1);
237 
238 	// GETVAL
239 	TEST("semctl(GETVAL)");
240 	union semun args;
241 	status_t status = semctl(semID, NUM_OF_SEMS - 1, GETVAL, args);
242 	// Semaphore is not initialized. Value is unknown.
243 	// We care about not crashing into KDL.
244 	assert_posix_bool_success(status != -1);
245 
246 	// SETALL
247 	TEST("semctl(SETALL)");
248 	args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS);
249 	for (int i = 0; i < NUM_OF_SEMS; i++)
250 		args.array[i] = 5;
251 	status = semctl(semID, 0, SETALL, args);
252 	assert_posix_bool_success(status != -1);
253 	free(args.array);
254 
255 	// GETVAL semaphore 4
256 	int returnedValue = semctl(semID, 4, GETVAL, 0);
257 	assert_equals((unsigned short)returnedValue, (unsigned short)5);
258 
259 	// GETALL
260 	TEST("semctl(GETALL)");
261 	args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS);
262 	semctl(semID, 0, GETALL, args);
263 	// Check only last semaphore value
264 	assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5);
265 	free(args.array);
266 
267 	// SETVAL semaphore 2
268 	TEST("semctl(SETVAL) - semaphore #2");
269 	args.val = 7;
270 	status = semctl(semID, 2, SETVAL, args);
271 	assert_posix_bool_success(status != 1);
272 
273 	// GETALL
274 	TEST("semctl(GETALL)");
275 	args.array = (unsigned short *)malloc(sizeof(unsigned short) * NUM_OF_SEMS);
276 	status = semctl(semID, 0, GETALL, args);
277 	assert_posix_bool_success(status != -1);
278 	TEST("semctl(GETALL) - semaphore #10");
279 	assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5);
280 	TEST("semctl(GETALL) - semaphore #2");
281 	assert_equals(args.array[NUM_OF_SEMS - 1], (unsigned short)5);
282 	free(args.array);
283 
284 	// IPC_SET
285 	TEST("semctl(IPC_SET)");
286 	struct semid_ds semaphore;
287 	memset(&semaphore, 0, sizeof(struct semid_ds));
288 	semaphore.sem_perm.uid = getuid() + 3;
289 	semaphore.sem_perm.gid = getgid() + 3;
290 	semaphore.sem_perm.mode = 0666;
291 	args.buf = &semaphore;
292 	status = semctl(semID, 0, IPC_SET, args);
293 	assert_posix_bool_success(status != 1);
294 
295 	// IPC_STAT set
296 	TEST("semctl(IPC_STAT)");
297 	memset(&semaphore, 0, sizeof(struct semid_ds));
298 	args.buf = &semaphore;
299 	status = semctl(semID, 0, IPC_STAT, args);
300 	assert_posix_bool_success(status != 1);
301 	TEST("semctl(IPC_STAT): number of sems");
302 	assert_equals((unsigned short)args.buf->sem_nsems, (unsigned short)NUM_OF_SEMS);
303 	TEST("semctl(IPC_STAT): uid");
304 	assert_equals(args.buf->sem_perm.uid, getuid() + 3);
305 	TEST("semctl(IPC_STAT): gid");
306 	assert_equals(args.buf->sem_perm.gid, getgid() + 3);
307 
308 	// Destroy non-private semaphore
309 	TEST("semctl(IPC_RMID)");
310 	status = remove_semaphore(semID);
311 	assert_posix_bool_success(status != 1);
312 
313 	TEST("done");
314 }
315 
316 
317 int
318 main()
319 {
320 	test_semget();
321 	test_semctl();
322 	test_semop();
323 
324 	printf("\nAll tests OK\n");
325 }
326