sem.c revision 147078
1226586Sdim/*
2226586Sdim * Copyright (c) 2000-2001, 2005 Sendmail, Inc. and its suppliers.
3226586Sdim *      All rights reserved.
4226586Sdim *
5226586Sdim * By using this file, you agree to the terms and conditions set
6226586Sdim * forth in the LICENSE file which can be found at the top level of
7226586Sdim * the sendmail distribution.
8226586Sdim */
9226586Sdim
10226586Sdim#include <sm/gen.h>
11226586SdimSM_RCSID("@(#)$Id: sem.c,v 1.12 2005/03/25 21:27:02 ca Exp $")
12226586Sdim
13226586Sdim#if SM_CONF_SEM
14226586Sdim# include <stdlib.h>
15226586Sdim# include <unistd.h>
16226586Sdim# include <sm/sem.h>
17226586Sdim# include <sm/heap.h>
18249423Sdim
19249423Sdim/*
20226586Sdim**  SM_SEM_START -- initialize semaphores
21226586Sdim**
22249423Sdim**	Parameters:
23226586Sdim**		key -- key for semaphores.
24249423Sdim**		nsem -- number of semaphores.
25226586Sdim**		semflg -- flag for semget(), if 0, use a default.
26226586Sdim**		owner -- create semaphores.
27226586Sdim**
28226586Sdim**	Returns:
29226586Sdim**		id for semaphores.
30226586Sdim**		< 0 on failure.
31226586Sdim*/
32226586Sdim
33226586Sdimint
34226586Sdimsm_sem_start(key, nsem, semflg, owner)
35226586Sdim	key_t key;
36226586Sdim	int nsem;
37226586Sdim	int semflg;
38226586Sdim	bool owner;
39226586Sdim{
40226586Sdim	int semid, i;
41226586Sdim	unsigned short *semvals;
42226586Sdim
43226586Sdim	semvals = NULL;
44226586Sdim	if (semflg == 0)
45226586Sdim		semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
46226586Sdim	if (owner)
47226586Sdim		semflg |= IPC_CREAT|IPC_EXCL;
48226586Sdim	semid = semget(key, nsem, semflg);
49226586Sdim	if (semid < 0)
50226586Sdim		goto error;
51226586Sdim
52226586Sdim	if (owner)
53234353Sdim	{
54226586Sdim		union semun semarg;
55226586Sdim
56226586Sdim		semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
57226586Sdim		if (semvals == NULL)
58226586Sdim			goto error;
59226586Sdim		semarg.array = semvals;
60226586Sdim
61226586Sdim		/* initialize semaphore values to be available */
62226586Sdim		for (i = 0; i < nsem; i++)
63226586Sdim			semvals[i] = 1;
64226586Sdim		if (semctl(semid, 0, SETALL, semarg) < 0)
65226586Sdim			goto error;
66226586Sdim	}
67226586Sdim	return semid;
68226586Sdim
69226586Sdimerror:
70226586Sdim	if (semvals != NULL)
71234353Sdim		sm_free(semvals);
72226586Sdim	if (semid >= 0)
73226586Sdim		sm_sem_stop(semid);
74226586Sdim	return -1;
75226586Sdim}
76226586Sdim
77226586Sdim/*
78226586Sdim**  SM_SEM_STOP -- stop using semaphores.
79226586Sdim**
80226586Sdim**	Parameters:
81234353Sdim**		semid -- id for semaphores.
82226586Sdim**
83226586Sdim**	Returns:
84234353Sdim**		0 on success.
85234353Sdim**		< 0 on failure.
86234353Sdim*/
87234353Sdim
88234353Sdimint
89234353Sdimsm_sem_stop(semid)
90234353Sdim	int semid;
91234353Sdim{
92234353Sdim	return semctl(semid, 0, IPC_RMID, NULL);
93234353Sdim}
94234353Sdim
95234353Sdim/*
96234353Sdim**  SM_SEM_ACQ -- acquire semaphore.
97234353Sdim**
98226586Sdim**	Parameters:
99226586Sdim**		semid -- id for semaphores.
100226586Sdim**		semnum -- number of semaphore.
101226586Sdim**		timeout -- how long to wait for operation to succeed.
102226586Sdim**
103226586Sdim**	Returns:
104226586Sdim**		0 on success.
105226586Sdim**		< 0 on failure.
106226586Sdim*/
107226586Sdim
108226586Sdimint
109226586Sdimsm_sem_acq(semid, semnum, timeout)
110226586Sdim	int semid;
111226586Sdim	int semnum;
112226586Sdim	int timeout;
113226586Sdim{
114226586Sdim	int r;
115226586Sdim	struct sembuf semops[1];
116226586Sdim
117226586Sdim	semops[0].sem_num = semnum;
118226586Sdim	semops[0].sem_op = -1;
119226586Sdim	semops[0].sem_flg = SEM_UNDO |
120226586Sdim			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
121226586Sdim	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
122234353Sdim		return semop(semid, semops, 1);
123234353Sdim	do
124226586Sdim	{
125234353Sdim		r = semop(semid, semops, 1);
126234353Sdim		if (r == 0)
127234353Sdim			return r;
128226586Sdim		sleep(1);
129226586Sdim		--timeout;
130226586Sdim	} while (timeout > 0);
131226586Sdim	return r;
132226586Sdim}
133226586Sdim
134226586Sdim/*
135226586Sdim**  SM_SEM_REL -- release semaphore.
136226586Sdim**
137226586Sdim**	Parameters:
138226586Sdim**		semid -- id for semaphores.
139226586Sdim**		semnum -- number of semaphore.
140226586Sdim**		timeout -- how long to wait for operation to succeed.
141226586Sdim**
142226586Sdim**	Returns:
143226586Sdim**		0 on success.
144226586Sdim**		< 0 on failure.
145226586Sdim*/
146226586Sdim
147226586Sdimint
148226586Sdimsm_sem_rel(semid, semnum, timeout)
149226586Sdim	int semid;
150226586Sdim	int semnum;
151226586Sdim	int timeout;
152226586Sdim{
153226586Sdim	int r;
154226586Sdim	struct sembuf semops[1];
155226586Sdim
156226586Sdim#if PARANOID
157226586Sdim	/* XXX should we check whether the value is already 0 ? */
158226586Sdim	SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
159226586Sdim#endif /* PARANOID */
160226586Sdim
161226586Sdim	semops[0].sem_num = semnum;
162226586Sdim	semops[0].sem_op = 1;
163226586Sdim	semops[0].sem_flg = SEM_UNDO |
164226586Sdim			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
165226586Sdim	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
166226586Sdim		return semop(semid, semops, 1);
167226586Sdim	do
168226586Sdim	{
169226586Sdim		r = semop(semid, semops, 1);
170226586Sdim		if (r == 0)
171226586Sdim			return r;
172226586Sdim		sleep(1);
173226586Sdim		--timeout;
174226586Sdim	} while (timeout > 0);
175226586Sdim	return r;
176226586Sdim}
177226586Sdim
178226586Sdim/*
179226586Sdim**  SM_SEM_GET -- get semaphore value.
180226586Sdim**
181226586Sdim**	Parameters:
182226586Sdim**		semid -- id for semaphores.
183226586Sdim**		semnum -- number of semaphore.
184226586Sdim**
185226586Sdim**	Returns:
186226586Sdim**		value of semaphore on success.
187226586Sdim**		< 0 on failure.
188226586Sdim*/
189226586Sdim
190226586Sdimint
191226586Sdimsm_sem_get(semid, semnum)
192226586Sdim	int semid;
193226586Sdim	int semnum;
194234353Sdim{
195234353Sdim	int semval;
196226586Sdim
197226586Sdim	if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
198226586Sdim		return -1;
199226586Sdim	return semval;
200234353Sdim}
201234353Sdim#endif /* SM_CONF_SEM */
202234353Sdim