xref: /freebsd/contrib/sendmail/libsm/t-sem.c (revision f0a75d274af375d15b97b830966b99a02b7db911)
1 /*
2  * Copyright (c) 2000-2001, 2005-2006 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  */
9 
10 #include <sm/gen.h>
11 SM_RCSID("@(#)$Id: t-sem.c,v 1.15 2006/03/13 20:40:43 msk Exp $")
12 
13 #include <stdio.h>
14 
15 #if SM_CONF_SEM
16 # include <stdlib.h>
17 # include <unistd.h>
18 # include <sysexits.h>
19 # include <sm/heap.h>
20 # include <sm/string.h>
21 # include <sm/signal.h>
22 # include <sm/test.h>
23 # include <sm/sem.h>
24 
25 static void
26 delay(t, s)
27 	int t;
28 	char *s;
29 {
30 	if (t > 0)
31 	{
32 #if DEBUG
33 		fprintf(stderr, "sleep(%d) before %s\n", t, s);
34 #endif /* DEBUG */
35 		sleep(t);
36 	}
37 #if DEBUG
38 	fprintf(stderr, "%s\n", s);
39 #endif /* DEBUG */
40 }
41 
42 
43 /*
44 **  SEMINTER -- interactive testing of semaphores.
45 **
46 **	Parameters:
47 **		owner -- create semaphores.
48 **
49 **	Returns:
50 **		0 on success
51 **		< 0 on failure.
52 */
53 
54 static int
55 seminter(owner)
56 	bool owner;
57 {
58 	int semid;
59 	int t;
60 
61 	semid = sm_sem_start(SM_SEM_KEY, SM_NSEM, 0, owner);
62 	if (semid < 0)
63 	{
64 		perror("sm_sem_start failed");
65 		return 1;
66 	}
67 
68 	while ((t = getchar()) != EOF)
69 	{
70 		switch (t)
71 		{
72 		  case 'a':
73 			delay(0, "try to acq");
74 			if (sm_sem_acq(semid, 0, 2) < 0)
75 			{
76 				perror("sm_sem_acq failed");
77 				return 1;
78 			}
79 			delay(0, "acquired");
80 			break;
81 
82 		  case 'r':
83 			delay(0, "try to rel");
84 			if (sm_sem_rel(semid, 0, 2) < 0)
85 			{
86 				perror("sm_sem_rel failed");
87 				return 1;
88 			}
89 			delay(0, "released");
90 			break;
91 
92 		  case 'v':
93 			if ((t = sm_sem_get(semid, 0)) < 0)
94 			{
95 				perror("get_sem failed");
96 				return 1;
97 			}
98 			printf("semval: %d\n", t);
99 			break;
100 
101 		}
102 	}
103 	if (owner)
104 		return sm_sem_stop(semid);
105 	return 0;
106 }
107 
108 /*
109 **  SEM_CLEANUP -- cleanup if something breaks
110 **
111 **	Parameters:
112 **		sig -- signal.
113 **
114 **	Returns:
115 **		none.
116 */
117 
118 static int semid_c = -1;
119 void
120 sem_cleanup(sig)
121 	int sig;
122 {
123 	if (semid_c >= 0)
124 		(void) sm_sem_stop(semid_c);
125 	exit(EX_UNAVAILABLE);
126 }
127 
128 /*
129 **  SEMTEST -- test of semaphores
130 **
131 **	Parameters:
132 **		owner -- create semaphores.
133 **
134 **	Returns:
135 **		0 on success
136 **		< 0 on failure.
137 */
138 
139 # define MAX_CNT	10
140 
141 static int
142 semtest(owner)
143 	int owner;
144 {
145 	int semid, r;
146 	int cnt = 0;
147 
148 	semid = sm_sem_start(SM_SEM_KEY, 1, 0, owner);
149 	if (semid < 0)
150 	{
151 		perror("sm_sem_start failed");
152 		return -1;
153 	}
154 
155 	if (owner)
156 	{
157 		/* just in case someone kills the program... */
158 		semid_c = semid;
159 		(void) sm_signal(SIGHUP, sem_cleanup);
160 		(void) sm_signal(SIGINT, sem_cleanup);
161 		(void) sm_signal(SIGTERM, sem_cleanup);
162 
163 		delay(1, "parent: acquire 1");
164 		cnt = 0;
165 		do
166 		{
167 			r = sm_sem_acq(semid, 0, 0);
168 			if (r < 0)
169 			{
170 				sleep(1);
171 				++cnt;
172 			}
173 		} while (r < 0 && cnt <= MAX_CNT);
174 		SM_TEST(r >= 0);
175 		if (r < 0)
176 			return r;
177 
178 		delay(3, "parent: release 1");
179 		cnt = 0;
180 		do
181 		{
182 			r = sm_sem_rel(semid, 0, 0);
183 			if (r < 0)
184 			{
185 				sleep(1);
186 				++cnt;
187 			}
188 		} while (r < 0 && cnt <= MAX_CNT);
189 		SM_TEST(r >= 0);
190 		if (r < 0)
191 			return r;
192 
193 		delay(1, "parent: getval");
194 		cnt = 0;
195 		do
196 		{
197 			r = sm_sem_get(semid, 0);
198 			if (r <= 0)
199 			{
200 				sleep(1);
201 				++cnt;
202 			}
203 		} while (r <= 0 && cnt <= MAX_CNT);
204 		SM_TEST(r > 0);
205 		if (r <= 0)
206 			return r;
207 
208 		delay(1, "parent: acquire 2");
209 		cnt = 0;
210 		do
211 		{
212 			r = sm_sem_acq(semid, 0, 0);
213 			if (r < 0)
214 			{
215 				sleep(1);
216 				++cnt;
217 			}
218 		} while (r < 0 && cnt <= MAX_CNT);
219 		SM_TEST(r >= 0);
220 		if (r < 0)
221 			return r;
222 
223 		cnt = 0;
224 		do
225 		{
226 			r = sm_sem_rel(semid, 0, 0);
227 			if (r < 0)
228 			{
229 				sleep(1);
230 				++cnt;
231 			}
232 		} while (r < 0 && cnt <= MAX_CNT);
233 		SM_TEST(r >= 0);
234 		if (r < 0)
235 			return r;
236 	}
237 	else
238 	{
239 		delay(1, "child: acquire 1");
240 		cnt = 0;
241 		do
242 		{
243 			r = sm_sem_acq(semid, 0, 0);
244 			if (r < 0)
245 			{
246 				sleep(1);
247 				++cnt;
248 			}
249 		} while (r < 0 && cnt <= MAX_CNT);
250 		SM_TEST(r >= 0);
251 		if (r < 0)
252 			return r;
253 
254 		delay(1, "child: release 1");
255 		cnt = 0;
256 		do
257 		{
258 			r = sm_sem_rel(semid, 0, 0);
259 			if (r < 0)
260 			{
261 				sleep(1);
262 				++cnt;
263 			}
264 		} while (r < 0 && cnt <= MAX_CNT);
265 		SM_TEST(r >= 0);
266 		if (r < 0)
267 			return r;
268 
269 	}
270 	if (owner)
271 		return sm_sem_stop(semid);
272 	return 0;
273 }
274 
275 int
276 main(argc, argv)
277 	int argc;
278 	char *argv[];
279 {
280 	bool interactive = false;
281 	bool owner = false;
282 	int ch;
283 	int r = 0;
284 
285 # define OPTIONS	"io"
286 	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
287 	{
288 		switch ((char) ch)
289 		{
290 		  case 'i':
291 			interactive = true;
292 			break;
293 
294 		  case 'o':
295 			owner = true;
296 			break;
297 
298 		  default:
299 			break;
300 		}
301 	}
302 
303 	if (interactive)
304 		r = seminter(owner);
305 	else
306 	{
307 		pid_t pid;
308 
309 		printf("This test takes about 8 seconds.\n");
310 		printf("If it takes longer than 30 seconds, please interrupt it\n");
311 		printf("and compile again without semaphore support, i.e.,");
312 		printf("-DSM_CONF_SEM=0\n");
313 		if ((pid = fork()) < 0)
314 		{
315 			perror("fork failed\n");
316 			return -1;
317 		}
318 
319 		sm_test_begin(argc, argv, "test semaphores");
320 		if (pid == 0)
321 		{
322 			/* give the parent the chance to setup data */
323 			sleep(1);
324 			r = semtest(false);
325 		}
326 		else
327 		{
328 			r = semtest(true);
329 		}
330 		SM_TEST(r == 0);
331 		return sm_test_end();
332 	}
333 	return r;
334 }
335 #else /* SM_CONF_SEM */
336 int
337 main(argc, argv)
338 	int argc;
339 	char *argv[];
340 {
341 	printf("No support for semaphores configured on this machine\n");
342 	return 0;
343 }
344 #endif /* SM_CONF_SEM */
345