1/*
2 *
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/*
21 *  FILE        : sem01.c
22 *  DESCRIPTION : Creates a semaphore and two processes.  The processes
23 *                each go through a loop where they semdown, delay for a
24 *                random amount of time, and semup, so they will almost
25 *                always be fighting for control of the semaphore.
26 *  HISTORY:
27 *    01/15/2001 Paul Larson (plars@us.ibm.com)
28 *      -written
29 *    11/09/2001 Manoj Iyer (manjo@ausin.ibm.com)
30 *    Modified.
31 *    - Removed compiler warnings.
32 *      added exit to the end of function main()
33 *
34 */
35
36#include <unistd.h>
37#include <stdlib.h>
38#include <stdio.h>
39#include <errno.h>
40#include <sys/types.h>
41#include <sys/wait.h>
42#include <sys/ipc.h>
43#include <sys/sem.h>
44#include "lapi/semun.h"
45
46int verbose = 0;
47int loops = 100;
48int errors = 0;
49
50int semup(int semid)
51{
52	struct sembuf semops;
53	semops.sem_num = 0;
54	semops.sem_op = 1;
55	semops.sem_flg = SEM_UNDO;
56	if (semop(semid, &semops, 1) == -1) {
57		perror("semup");
58		errors++;
59		return 1;
60	}
61	return 0;
62}
63
64int semdown(int semid)
65{
66	struct sembuf semops;
67	semops.sem_num = 0;
68	semops.sem_op = -1;
69	semops.sem_flg = SEM_UNDO;
70	if (semop(semid, &semops, 1) == -1) {
71		perror("semdown");
72		errors++;
73		return 1;
74	}
75	return 0;
76}
77
78void delayloop()
79{
80	int delay;
81	delay = 1 + ((100.0 * rand()) / RAND_MAX);
82	if (verbose)
83		printf("in delay function for %d microseconds\n", delay);
84	usleep(delay);
85}
86
87void mainloop(int semid)
88{
89	int i;
90	for (i = 0; i < loops; i++) {
91		if (semdown(semid)) {
92			printf("semdown failed\n");
93		}
94		if (verbose)
95			printf("sem is down\n");
96		delayloop();
97		if (semup(semid)) {
98			printf("semup failed\n");
99		}
100		if (verbose)
101			printf("sem is up\n");
102	}
103}
104
105int main(int argc, char *argv[])
106{
107	int semid, opt;
108	union semun semunion;
109	extern char *optarg;
110	pid_t pid;
111	int chstat;
112
113	while ((opt = getopt(argc, argv, "l:vh")) != EOF) {
114		switch ((char)opt) {
115		case 'l':
116			loops = atoi(optarg);
117			break;
118		case 'v':
119			verbose = 1;
120			break;
121		case 'h':
122		default:
123			printf("Usage: -l loops [-v]\n");
124			exit(1);
125		}
126	}
127
128	/* set up the semaphore */
129	if ((semid = semget((key_t) 9142, 1, 0666 | IPC_CREAT)) < 0) {
130		printf("error in semget()\n");
131		exit(-1);
132	}
133	semunion.val = 1;
134	if (semctl(semid, 0, SETVAL, semunion) == -1) {
135		printf("error in semctl\n");
136	}
137
138	if ((pid = fork()) < 0) {
139		printf("fork error\n");
140		exit(-1);
141	}
142	if (pid) {
143		/* parent */
144		srand(pid);
145		mainloop(semid);
146		waitpid(pid, &chstat, 0);
147		if (!WIFEXITED(chstat)) {
148			printf("child exited with status\n");
149			exit(-1);
150		}
151		if (semctl(semid, 0, IPC_RMID, semunion) == -1) {
152			printf("error in semctl\n");
153		}
154		if (errors) {
155			printf("FAIL: there were %d errors\n", errors);
156		} else {
157			printf("PASS: error count is 0\n");
158		}
159		exit(errors);
160	} else {
161		/* child */
162		mainloop(semid);
163	}
164	exit(0);
165}
166