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