Merge from vendor branch CVS:
[dragonfly.git] / contrib / sendmail-8.13.8 / libsm / sem.c
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 */