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