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