xref: /illumos-gate/usr/src/cmd/sendmail/libsm/sem.c (revision 7c478bd9)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
11 
12 #include <sm/gen.h>
13 SM_RCSID("@(#)$Id: sem.c,v 1.12 2005/03/25 21:27:02 ca Exp $")
14 
15 #if SM_CONF_SEM
16 # include <stdlib.h>
17 # include <unistd.h>
18 # include <sm/sem.h>
19 # include <sm/heap.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;
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 	if (semvals != NULL)
73 		sm_free(semvals);
74 	if (semid >= 0)
75 		sm_sem_stop(semid);
76 	return -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 */
204