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