1 /*
2 * Copyright (c) 2000-2001, 2005, 2008 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.14 2008/05/30 16:26:38 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
35 int
36 sm_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
71 error:
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
91 int
sm_sem_stop(semid)92 sm_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
111 int
sm_sem_acq(semid,semnum,timeout)112 sm_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
150 int
sm_sem_rel(semid,semnum,timeout)151 sm_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
193 int
sm_sem_get(semid,semnum)194 sm_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
219 int
sm_semsetowner(semid,uid,gid,mode)220 sm_semsetowner(semid, uid, gid, mode)
221 int semid;
222 uid_t uid;
223 gid_t gid;
224 mode_t mode;
225 {
226 # ifndef WIN32
227 int r;
228 struct semid_ds semidds;
229 union semun {
230 int val;
231 struct semid_ds *buf;
232 ushort *array;
233 } arg;
234
235 memset(&semidds, 0, sizeof(semidds));
236 arg.buf = &semidds;
237 if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
238 return r;
239 semidds.sem_perm.uid = uid;
240 semidds.sem_perm.gid = gid;
241 semidds.sem_perm.mode = mode;
242 if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
243 return r;
244 # endif /* WIN32 */
245 return 0;
246 }
247 #endif /* SM_CONF_SEM */
248