]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/sendmail/libsm/sem.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / sendmail / libsm / sem.c
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
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
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
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
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
220 sm_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 */