• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   Copyright (C) Bull S.A. 1996
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 /*---------------------------------------------------------------------+
20 |                           semaphore_test_02                          |
21 | ==================================================================== |
22 |                                                                      |
23 | Description:  Verify semget () and semctl () options                 |
24 |               Also uses semop in linux (semctl(GETPID) requires semop|
25 |                                                                      |
26 | Algorithm:    o  Spawn N child processes                             |
27 |                                                                      |
28 |               o  Obtain N semaphores with semget (IPC_PRIVATE)       |
29 |                                                                      |
30 |               o  Call semctl () with following commands:             |
31 |                     IPC_SET:  set uid, gid & mode                    |
32 |                     IPC_STAT: get uid, gid, mode & verify            |
33 |                     SETVAL:   set each semaphore value individually  |
34 |                     GETVAL:   get each semaphore value & verify      |
35 |                #if linux then call semop
36 |                     GETPID:   get pid of last operation & verify     |
37 |                     GETNCNT:  get semncnt & verify                   |
38 |                     GETZCNT:  get semzcnt & verify                   |
39 |                     SETALL:   set all the semaphores                 |
40 |                     GETALL:   get all the semaphores & verify values |
41 |                     IPC_RMID: remove the N semaphores                |
42 |                                                                      |
43 | System calls: The following system calls are made                    |
44 |                                                                      |
45 |               semget () - Gets a set of semaphores                   |
46 |               semctl () - Controls semaphore operations              |
47 |                                                                      |
48 | Usage:        semaphore_test_02 [-p nprocs]                          |
49 |                                                                      |
50 | To compile:   cc -o semaphore_test_02 semaphore_test_02.c            |
51 |                                                                      |
52 | Last update:   Ver. 1.2, 2/14/94 00:18:23                           |
53 |                                                                      |
54 | Change Activity                                                      |
55 |                                                                      |
56 |   Version  Date    Name  Reason                                      |
57 |    0.1     050689  CTU   Initial version                             |
58 |    0.2     111993  DJK   Modify for AIX version 4.1                  |
59 |    1.2     021494  DJK   Moved to "prod" directory                   |
60 |							               |
61 |    1.3     Jan-28-02 	Manoj Iyer, IBM Austin TX. manjo@austin.ibm.com|
62 |			Modified semctl() to work in linux. Also the   |
63 |			#ifdef _LINUX_ was removed from the code.      |
64 |								       |
65 |                                                                      |
66 +---------------------------------------------------------------------*/
67 
68 #include <errno.h>
69 #include <stdio.h>
70 #include <unistd.h>
71 #include <sys/ipc.h>
72 #include <sys/param.h>
73 #include <sys/sem.h>
74 #include <sys/shm.h>
75 #include <sys/stat.h>
76 #include <sys/types.h>
77 #include <sys/wait.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include "lapi/semun.h"
81 
82 /*
83  * Defines
84  *
85  * NUM_SEMAPHORES: number of semaphores to create
86  */
87 #define MAX_SEMAPHORES	250
88 #define MAX_CHILDREN		200
89 #define DEFAULT_NUM_SEMAPHORES	96
90 #define DEFAULT_NUM_CHILDREN	0
91 
92 #define USAGE	"\nUsage: %s [-s nsems] [-p nproc]\n\n" \
93 		"\t-s nsems  number of semaphores (per process)\n\n"	\
94 		"\t-p nproc  number of child processes to spawn\n\n"
95 
96 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
97 /*
98  * Function prototypes
99  *
100  * test_commands (): Tests semget () and semctl () commands
101  * parse_args (): Parse command line arguments
102  * sys_error (): System error message function
103  * error (): Error message function
104  */
105 static void test_commands(pid_t);
106 static void sys_error(const char *, int);
107 static void error(const char *, int);
108 static void parse_args(int, char **);
109 
110 /*
111  * Structures and Global variables:
112  *
113  * nsems: number of semaphores to create (per process)
114  * nprocs: number of child processes to spawn
115  * childpid: array containing process id's of the child processes
116  * parent_pid: process id of parent process
117  */
118 int nsems = DEFAULT_NUM_SEMAPHORES;
119 int nprocs = DEFAULT_NUM_CHILDREN;
120 int childpid[MAX_CHILDREN];
121 int errors = 0;
122 pid_t parent_pid;
123 
124 union semun arg;
125 
126 /*---------------------------------------------------------------------+
127 |                               main                                   |
128 | ==================================================================== |
129 |                                                                      |
130 | Function:  Main program  (see prolog for more details)               |
131 |                                                                      |
132 | Returns:   (0)  Successful completion                                |
133 |            (-1) Error occurred                                       |
134 |                                                                      |
135 +---------------------------------------------------------------------*/
main(int argc,char ** argv)136 int main(int argc, char **argv)
137 {
138 	int proc;		/* fork loop index */
139 	pid_t pid;		/* Process id */
140 	int status;		/* Child's exit status */
141 
142 	/*
143 	 * Parse command line arguments and print out program header
144 	 */
145 	parse_args(argc, argv);
146 	printf("%s: IPC Semaphore TestSuite program\n", *argv);
147 	fflush(stdout);
148 	parent_pid = getpid();
149 
150 	/*
151 	 * Fork off the additional processes.
152 	 */
153 	if (nprocs > 0) {
154 		printf("\n\tParent: spawning %d child processes\n", nprocs);
155 		fflush(stdout);
156 	}
157 	for (proc = 1; proc < nprocs; proc++) {
158 		/*
159 		 * Child leaves loop, parent continues to fork.
160 		 */
161 		if ((pid = fork()) < 0)
162 			error("fork failed", __LINE__);
163 		else if (pid == 0)
164 			break;
165 		else
166 			childpid[proc] = pid;
167 	}
168 	pid = getpid();
169 
170 	/*
171 	 * Test the semget () and semctl () commands
172 	 */
173 	test_commands(pid);
174 
175 	/*
176 	 * Finished testing commands, only parent process needs to continue
177 	 */
178 	if (pid != parent_pid)
179 		exit(0);
180 
181 	/*
182 	 * Wait for all of the child processes to complete & check their
183 	 * exit status.
184 	 *
185 	 * Upon completion of the child proccesses, exit program with success.
186 	 */
187 	for (proc = 1; proc < nprocs; proc++) {
188 		waitpid(childpid[proc], &status, 0);
189 
190 		if (!WIFEXITED(status))
191 			error("child process terminated abnormally", __LINE__);
192 	}
193 	if (nprocs > 0)
194 		printf
195 		    ("\n\tAll child processes verified commands successfully\n");
196 	printf("\nsuccessful!\n");
197 	return (errors);
198 }
199 
200 /*---------------------------------------------------------------------+
201 |                   test_commands (pid_t pid)                          |
202 | ==================================================================== |
203 |                                                                      |
204 | Function:  test semget() and semctl()                                |
205 |                                                                      |
206 +---------------------------------------------------------------------*/
test_commands(pid_t pid)207 static void test_commands(pid_t pid)
208 {
209 	int i;			/* loop index */
210 	int semid;		/* Unique semaphore id */
211 	int val;		/* Misc value */
212 	gid_t gid = getgid();	/* User's group id */
213 	mode_t mode = 0666;	/* User's mode value */
214 	uid_t uid = getuid();	/* User's user id */
215 	struct sembuf sops;
216 	union semun semunptr;	/* This union has struct semid_ds *buf */
217 	/*
218 	 * Test semget () with IPC_PRIVATE command
219 	 *
220 	 * Create nsems semaphores and store the returned unique
221 	 * semaphore identifier as semid.
222 	 */
223 	if (pid == parent_pid)
224 		printf("\n\tTesting semctl (IPC_SET) command operation\n");
225 	if ((semid = semget(IPC_PRIVATE, nsems, IPC_CREAT | 0666)) < 0)
226 		error("semget failed", __LINE__);
227 
228 	/*
229 	 * Test semctl () with IPC_SET command
230 	 *
231 	 * Set the uid, gid and mode fields
232 	 */
233 	if (pid == parent_pid)
234 		printf("\n\tTesting semctl (IPC_SET) command operation\n");
235 
236 	semunptr.buf = (struct semid_ds *)calloc(1, sizeof(struct semid_ds));
237 	if (!semunptr.buf)
238 		error("calloc failed", __LINE__);
239 
240 	semunptr.buf->sem_perm.uid = uid;
241 	semunptr.buf->sem_perm.gid = gid;
242 	semunptr.buf->sem_perm.mode = mode;
243 
244 	if (semctl(semid, 0, IPC_SET, semunptr) < 0)
245 		sys_error("semctl failed", __LINE__);
246 
247 	/*
248 	 * Test semctl () with IPC_STAT command
249 	 *
250 	 * Get the semid_ds structure and verify it's fields.
251 	 */
252 	if (pid == parent_pid)
253 		printf("\n\tTesting semctl (IPC_STAT) command operation\n");
254 
255 	if (semctl(semid, 0, IPC_STAT, semunptr) < 0)
256 		sys_error("semctl failed", __LINE__);
257 	if (semunptr.buf->sem_perm.uid != uid)
258 		sys_error("semctl: uid was not set", __LINE__);
259 	if (semunptr.buf->sem_perm.gid != gid)
260 		sys_error("semctl: gid was not set", __LINE__);
261 	if ((semunptr.buf->sem_perm.mode & 0777) != mode)
262 		sys_error("semctl: mode was not set", __LINE__);
263 	if (semunptr.buf->sem_nsems != nsems)
264 		sys_error("semctl: nsems (number of semaphores) was not set",
265 			  __LINE__);
266 	SAFE_FREE(semunptr.buf);
267 
268 	/*
269 	 * Test semctl () with SETVAL command
270 	 *
271 	 * Loop through all the semaphores and set the semaphore value
272 	 * to the loop index (i).
273 	 */
274 	if (pid == parent_pid)
275 		printf("\n\tTesting semctl (SETVAL) command operation\n");
276 	for (i = 0; i < nsems; i++) {
277 		arg.val = i;
278 		if (semctl(semid, i, SETVAL, arg) < 0)
279 			sys_error("semctl failed", __LINE__);
280 	}
281 
282 	/*
283 	 * Test semctl () with GETVAL command
284 	 *
285 	 * Loop through all the semaphores and retrieve the semaphore values
286 	 * and compare with the expected value, the loop index (i).
287 	 */
288 	if (pid == parent_pid)
289 		printf("\n\tTesting semctl (GETVAL) command operation\n");
290 	for (i = 0; i < nsems; i++) {
291 		if ((val = semctl(semid, i, GETVAL, arg)) < 0)
292 			sys_error("semctl failed", __LINE__);
293 		if (val != i)
294 			sys_error("semctl (GETVAL) failed", __LINE__);
295 	}
296 
297 	// testing in linux.  before semctl(GETPID) works, we must call semop
298 	if (pid == parent_pid)
299 		printf("\n\tTesting semop (signal and wait) operations\n");
300 	sops.sem_flg = 0;
301 	for (i = 0; i < nsems; i++) {
302 		sops.sem_num = i;
303 		sops.sem_op = 1;
304 		if ((val = semop(semid, &sops, 1)) < 0)
305 			sys_error("semop signal failed", __LINE__);
306 		sops.sem_op = -1;
307 		if ((val = semop(semid, &sops, 1)) < 0)
308 			sys_error("semop wait failed", __LINE__);
309 	}
310 
311 	/*
312 	 * Test semctl () with GETPID command
313 	 */
314 	if (pid == parent_pid)
315 		printf("\n\tTesting semctl (GETPID) command operation\n");
316 	for (i = 0; i < nsems; i++) {
317 		if ((val = semctl(semid, i, GETPID, arg)) < 0)
318 			sys_error("semctl failed", __LINE__);
319 		if (val != pid)
320 			sys_error("semctl (GETPID) failed", __LINE__);
321 	}
322 
323 	/*
324 	 * Test semctl () with GETNCNT command
325 	 *
326 	 * Get semncnt (the number of processes awaiting semval > currval)
327 	 * and insure that this value is 0...
328 	 *
329 	 * Note: A better test would include forking off a process that
330 	 *       waits for the semaphore so that semncnt would be nonzero.
331 	 */
332 	if (pid == parent_pid)
333 		printf("\n\tTesting semctl (GETNCNT) command operation\n");
334 	for (i = 0; i < nsems; i++) {
335 		if ((val = semctl(semid, i, GETNCNT, arg)) < 0)
336 			sys_error("semctl failed", __LINE__);
337 		if (val != 0)
338 			sys_error("semctl (GETNCNT) returned wrong value",
339 				  __LINE__);
340 	}
341 
342 	/*
343 	 * Test semctl () with GETZCNT command
344 	 *
345 	 * Get semzcnt (the number of processes awaiting semval = currval)
346 	 * and insure that this value is 0...
347 	 *
348 	 * Note: A better test would include forking off a process that
349 	 *       waits for the semaphore so that semzcnt would be nonzero.
350 	 */
351 	if (pid == parent_pid)
352 		printf("\n\tTesting semctl (GETZCNT) command operation\n");
353 	for (i = 0; i < nsems; i++) {
354 		if ((val = semctl(semid, i, GETZCNT, arg)) < 0)
355 			sys_error("semctl failed", __LINE__);
356 		if (val != 0)
357 			sys_error("semctl (GETZCNT) returned wrong value",
358 				  __LINE__);
359 	}
360 
361 	/*
362 	 * Test semctl () with SETALL command
363 	 *
364 	 * Set all of the semaphore values in the set.
365 	 */
366 	arg.array = malloc(sizeof(int) * nsems);
367 	if (!arg.array)
368 		error("malloc failed", __LINE__);
369 	if (pid == parent_pid)
370 		printf("\n\tTesting semctl (SETALL) command operation\n");
371 	for (i = 0; i < nsems; i++)
372 		arg.array[i] = i;
373 	if (semctl(semid, 0, SETALL, arg) < 0)
374 		sys_error("semctl failed", __LINE__);
375 
376 	/*
377 	 * Test semctl () with GETALL command
378 	 *
379 	 * Get all of the semaphore values in the set, and verify that
380 	 * they are all correct.
381 	 */
382 	if (pid == parent_pid)
383 		printf("\n\tTesting semctl (GETALL) command operation\n");
384 	if (semctl(semid, nsems, GETALL, arg) < 0)
385 		sys_error("semctl failed", __LINE__);
386 	for (i = 0; i < nsems; i++) {
387 		if (arg.array[i] != i)
388 			sys_error("semaphore does not match expected value",
389 				  __LINE__);
390 	}
391 
392 	/*
393 	 * Test semctl () with IPC_RMID command
394 	 *
395 	 * Remove the semaphores
396 	 */
397 	if (pid == parent_pid)
398 		printf("\n\tTesting semctl (IPC_RMID) command operation\n");
399 	if (semctl(semid, nsems, IPC_RMID, arg) < 0)
400 		sys_error("semctl failed", __LINE__);
401 	SAFE_FREE(arg.array);
402 
403 }
404 
405 /*---------------------------------------------------------------------+
406 |                             parse_args ()                            |
407 | ==================================================================== |
408 |                                                                      |
409 | Function:  Parse the command line arguments & initialize global      |
410 |            variables.                                                |
411 |                                                                      |
412 | Updates:   (command line options)                                    |
413 |                                                                      |
414 |            [-p] nproc: number of child processes                     |
415 |                                                                      |
416 +---------------------------------------------------------------------*/
parse_args(int argc,char ** argv)417 void parse_args(int argc, char **argv)
418 {
419 	int opt;
420 	int errflag = 0;
421 	char *program_name = *argv;
422 	extern char *optarg;	/* Command line option */
423 
424 	while ((opt = getopt(argc, argv, "s:p:")) != EOF) {
425 		switch (opt) {
426 		case 's':
427 			nsems = atoi(optarg);
428 			break;
429 		case 'p':
430 			nprocs = atoi(optarg);
431 			break;
432 		default:
433 			errflag++;
434 			break;
435 		}
436 	}
437 	if (nsems >= MAX_SEMAPHORES) {
438 		errflag++;
439 		fprintf(stderr, "ERROR: nsems must be less than %d\n",
440 			MAX_SEMAPHORES);
441 	}
442 	if (nprocs >= MAX_CHILDREN) {
443 		errflag++;
444 		fprintf(stderr, "ERROR: nproc must be less than %d\n",
445 			MAX_CHILDREN);
446 	}
447 
448 	if (errflag) {
449 		fprintf(stderr, USAGE, program_name);
450 		exit(2);
451 	}
452 }
453 
454 /*---------------------------------------------------------------------+
455 |                             sys_error ()                             |
456 | ==================================================================== |
457 |                                                                      |
458 | Function:  Creates system error message and increments errors	       |
459 |                                                                      |
460 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)461 static void sys_error(const char *msg, int line)
462 {
463 	char syserr_msg[256];
464 
465 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
466 	fprintf(stderr, "ERROR [line: %d] %s\n", line, syserr_msg);
467 	errors++;
468 	/* error (syserr_msg, line); */
469 }
470 
471 /*---------------------------------------------------------------------+
472 |                               error ()                               |
473 | ==================================================================== |
474 |                                                                      |
475 | Function:  Prints out message and exits...                           |
476 |                                                                      |
477 +---------------------------------------------------------------------*/
error(const char * msg,int line)478 static void error(const char *msg, int line)
479 {
480 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
481 	exit(-1);
482 }
483