sem.c revision 261363
1/*
2 * Copyright (c) 2000-2001, 2005, 2008 Proofpoint, 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: sem.c,v 1.15 2013/11/22 20:51:43 ca Exp $")
12
13#if SM_CONF_SEM
14# include <stdlib.h>
15# include <unistd.h>
16# include <sm/string.h>
17# include <sm/sem.h>
18# include <sm/heap.h>
19# include <errno.h>
20
21/*
22**  SM_SEM_START -- initialize semaphores
23**
24**	Parameters:
25**		key -- key for semaphores.
26**		nsem -- number of semaphores.
27**		semflg -- flag for semget(), if 0, use a default.
28**		owner -- create semaphores.
29**
30**	Returns:
31**		id for semaphores.
32**		< 0 on failure.
33*/
34
35int
36sm_sem_start(key, nsem, semflg, owner)
37	key_t key;
38	int nsem;
39	int semflg;
40	bool owner;
41{
42	int semid, i, err;
43	unsigned short *semvals;
44
45	semvals = NULL;
46	if (semflg == 0)
47		semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
48	if (owner)
49		semflg |= IPC_CREAT|IPC_EXCL;
50	semid = semget(key, nsem, semflg);
51	if (semid < 0)
52		goto error;
53
54	if (owner)
55	{
56		union semun semarg;
57
58		semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
59		if (semvals == NULL)
60			goto error;
61		semarg.array = semvals;
62
63		/* initialize semaphore values to be available */
64		for (i = 0; i < nsem; i++)
65			semvals[i] = 1;
66		if (semctl(semid, 0, SETALL, semarg) < 0)
67			goto error;
68	}
69	return semid;
70
71error:
72	err = errno;
73	if (semvals != NULL)
74		sm_free(semvals);
75	if (semid >= 0)
76		sm_sem_stop(semid);
77	return (err > 0) ? (0 - err) : -1;
78}
79
80/*
81**  SM_SEM_STOP -- stop using semaphores.
82**
83**	Parameters:
84**		semid -- id for semaphores.
85**
86**	Returns:
87**		0 on success.
88**		< 0 on failure.
89*/
90
91int
92sm_sem_stop(semid)
93	int semid;
94{
95	return semctl(semid, 0, IPC_RMID, NULL);
96}
97
98/*
99**  SM_SEM_ACQ -- acquire semaphore.
100**
101**	Parameters:
102**		semid -- id for semaphores.
103**		semnum -- number of semaphore.
104**		timeout -- how long to wait for operation to succeed.
105**
106**	Returns:
107**		0 on success.
108**		< 0 on failure.
109*/
110
111int
112sm_sem_acq(semid, semnum, timeout)
113	int semid;
114	int semnum;
115	int timeout;
116{
117	int r;
118	struct sembuf semops[1];
119
120	semops[0].sem_num = semnum;
121	semops[0].sem_op = -1;
122	semops[0].sem_flg = SEM_UNDO |
123			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
124	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
125		return semop(semid, semops, 1);
126	do
127	{
128		r = semop(semid, semops, 1);
129		if (r == 0)
130			return r;
131		sleep(1);
132		--timeout;
133	} while (timeout > 0);
134	return r;
135}
136
137/*
138**  SM_SEM_REL -- release semaphore.
139**
140**	Parameters:
141**		semid -- id for semaphores.
142**		semnum -- number of semaphore.
143**		timeout -- how long to wait for operation to succeed.
144**
145**	Returns:
146**		0 on success.
147**		< 0 on failure.
148*/
149
150int
151sm_sem_rel(semid, semnum, timeout)
152	int semid;
153	int semnum;
154	int timeout;
155{
156	int r;
157	struct sembuf semops[1];
158
159#if PARANOID
160	/* XXX should we check whether the value is already 0 ? */
161	SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
162#endif /* PARANOID */
163
164	semops[0].sem_num = semnum;
165	semops[0].sem_op = 1;
166	semops[0].sem_flg = SEM_UNDO |
167			    (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
168	if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
169		return semop(semid, semops, 1);
170	do
171	{
172		r = semop(semid, semops, 1);
173		if (r == 0)
174			return r;
175		sleep(1);
176		--timeout;
177	} while (timeout > 0);
178	return r;
179}
180
181/*
182**  SM_SEM_GET -- get semaphore value.
183**
184**	Parameters:
185**		semid -- id for semaphores.
186**		semnum -- number of semaphore.
187**
188**	Returns:
189**		value of semaphore on success.
190**		< 0 on failure.
191*/
192
193int
194sm_sem_get(semid, semnum)
195	int semid;
196	int semnum;
197{
198	int semval;
199
200	if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
201		return -1;
202	return semval;
203}
204
205/*
206**  SM_SEMSETOWNER -- set owner/group/mode of semaphores.
207**
208**	Parameters:
209**		semid -- id for semaphores.
210**		uid -- uid to use
211**		gid -- gid to use
212**		mode -- mode to use
213**
214**	Returns:
215**		0 on success.
216**		< 0 on failure.
217*/
218
219int
220sm_semsetowner(semid, uid, gid, mode)
221	int semid;
222	uid_t uid;
223	gid_t gid;
224	mode_t mode;
225{
226	int r;
227	struct semid_ds	semidds;
228	union semun {
229		int		val;
230		struct semid_ds	*buf;
231		ushort		*array;
232	} arg;
233
234	memset(&semidds, 0, sizeof(semidds));
235	arg.buf = &semidds;
236	if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
237		return r;
238	semidds.sem_perm.uid = uid;
239	semidds.sem_perm.gid = gid;
240	semidds.sem_perm.mode = mode;
241	if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
242		return r;
243	return 0;
244}
245#endif /* SM_CONF_SEM */
246