1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "lint.h"
28 #include "mtlib.h"
29 #include <sys/types.h>
30 #include <semaphore.h>
31 #include <synch.h>
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <limits.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <sys/mman.h>
39 #include <unistd.h>
40 #include <thread.h>
41 #include "pos4obj.h"
42
43 typedef struct semaddr {
44 struct semaddr *sad_next; /* next in the link */
45 char sad_name[PATH_MAX + 1]; /* name of sem object */
46 sem_t *sad_addr; /* mmapped address of semaphore */
47 ino64_t sad_inode; /* inode # of the mmapped file */
48 } semaddr_t;
49
50 static long semvaluemax = 0;
51 static semaddr_t *semheadp = NULL;
52 static mutex_t semlock = DEFAULTMUTEX;
53
54 sem_t *
sem_open(const char * path,int oflag,...)55 sem_open(const char *path, int oflag, /* mode_t mode, int value */ ...)
56 {
57 va_list ap;
58 mode_t crmode = 0;
59 sem_t *sem = NULL;
60 struct stat64 statbuf;
61 semaddr_t *next = NULL;
62 int fd = 0;
63 int error = 0;
64 int cr_flag = 0;
65 uint_t value = 0;
66
67 if (__pos4obj_check(path) == -1)
68 return (SEM_FAILED);
69
70 /* acquire semaphore lock to have atomic operation */
71 if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0)
72 return (SEM_FAILED);
73
74 /* modify oflag to have RDWR and filter CREATE mode only */
75 oflag = (oflag & (O_CREAT|O_EXCL)) | (O_RDWR);
76 if (oflag & O_CREAT) {
77 if (semvaluemax == 0 &&
78 (semvaluemax = _sysconf(_SC_SEM_VALUE_MAX)) <= 0)
79 semvaluemax = -1;
80 va_start(ap, oflag);
81 crmode = va_arg(ap, mode_t);
82 value = va_arg(ap, uint_t);
83 va_end(ap);
84 /* check value < the max for a named semaphore */
85 if (semvaluemax < 0 ||
86 (ulong_t)value > (ulong_t)semvaluemax) {
87 errno = EINVAL;
88 goto out;
89 }
90 }
91
92 errno = 0;
93
94 if ((fd = __pos4obj_open(path, SEM_DATA_TYPE,
95 oflag, crmode, &cr_flag)) < 0)
96 goto out;
97
98 if (cr_flag)
99 cr_flag = DFILE_CREATE | DFILE_OPEN;
100 else
101 cr_flag = DFILE_OPEN;
102
103 /* find out inode # for the opened file */
104 if (fstat64(fd, &statbuf) < 0)
105 goto out;
106
107 /* if created, acquire total_size in the file */
108 if ((cr_flag & DFILE_CREATE) != 0) {
109 if (ftruncate64(fd, (off64_t)sizeof (sem_t)) < 0)
110 goto out;
111 } else {
112 /*
113 * if this semaphore has already been opened, inode
114 * will indicate then return the same semaphore address
115 */
116 lmutex_lock(&semlock);
117 for (next = semheadp; next != NULL; next = next->sad_next) {
118 if (statbuf.st_ino == next->sad_inode &&
119 strcmp(path, next->sad_name) == 0) {
120 (void) __close_nc(fd);
121 lmutex_unlock(&semlock);
122 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
123 return (next->sad_addr);
124 }
125 }
126 lmutex_unlock(&semlock);
127 }
128
129
130 /* new sem descriptor to be allocated and new address to be mapped */
131 if ((next = malloc(sizeof (semaddr_t))) == NULL) {
132 errno = ENOMEM;
133 goto out;
134 }
135 cr_flag |= ALLOC_MEM;
136
137 /* LINTED */
138 sem = (sem_t *)mmap64(NULL, sizeof (sem_t), PROT_READ|PROT_WRITE,
139 MAP_SHARED, fd, (off64_t)0);
140 (void) __close_nc(fd);
141 cr_flag &= ~DFILE_OPEN;
142 if (sem == MAP_FAILED)
143 goto out;
144 cr_flag |= DFILE_MMAP;
145
146 /* if created, initialize */
147 if (cr_flag & DFILE_CREATE) {
148 error = sema_init((sema_t *)sem, value, USYNC_PROCESS, 0);
149 if (error) {
150 errno = error;
151 goto out;
152 }
153 }
154
155 if (__pos4obj_unlock(path, SEM_LOCK_TYPE) == 0) {
156 /* add to the list pointed by semheadp */
157 lmutex_lock(&semlock);
158 next->sad_next = semheadp;
159 semheadp = next;
160 next->sad_addr = sem;
161 next->sad_inode = statbuf.st_ino;
162 (void) strcpy(next->sad_name, path);
163 lmutex_unlock(&semlock);
164 return (sem);
165 }
166 /* fall into the error case */
167 out:
168 error = errno;
169 if ((cr_flag & DFILE_OPEN) != 0)
170 (void) __close_nc(fd);
171 if ((cr_flag & DFILE_CREATE) != 0)
172 (void) __pos4obj_unlink(path, SEM_DATA_TYPE);
173 if ((cr_flag & ALLOC_MEM) != 0)
174 free(next);
175 if ((cr_flag & DFILE_MMAP) != 0)
176 (void) munmap((caddr_t)sem, sizeof (sem_t));
177 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
178 errno = error;
179 return (SEM_FAILED);
180 }
181
182 int
sem_close(sem_t * sem)183 sem_close(sem_t *sem)
184 {
185 semaddr_t **next;
186 semaddr_t *freeit;
187
188 lmutex_lock(&semlock);
189 for (next = &semheadp; (freeit = *next) != NULL;
190 next = &(freeit->sad_next)) {
191 if (freeit->sad_addr == sem) {
192 *next = freeit->sad_next;
193 lmutex_unlock(&semlock);
194 free(freeit);
195 return (munmap((caddr_t)sem, sizeof (sem_t)));
196 }
197 }
198 lmutex_unlock(&semlock);
199 errno = EINVAL;
200 return (-1);
201 }
202
203 int
sem_unlink(const char * path)204 sem_unlink(const char *path)
205 {
206 int error;
207 int oerrno;
208
209 if (__pos4obj_check(path) < 0)
210 return (-1);
211
212 if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0)
213 return (-1);
214
215 error = __pos4obj_unlink(path, SEM_DATA_TYPE);
216
217 oerrno = errno;
218
219 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
220
221 errno = oerrno;
222
223 return (error);
224 }
225
226 /*
227 * SUSV3 requires ("shall fail") an EINVAL failure for operations
228 * on invalid semaphores, including uninitialized unnamed semaphores.
229 * The best we can do is check that the magic number is correct.
230 * This is not perfect, but it allows the test suite to pass.
231 * (Standards bodies are filled with fools and idiots.)
232 */
233 static int
sem_invalid(sem_t * sem)234 sem_invalid(sem_t *sem)
235 {
236 if (sem->sem_magic != SEMA_MAGIC) {
237 errno = EINVAL;
238 return (-1);
239 }
240 return (0);
241 }
242
243 int
sem_init(sem_t * sem,int pshared,uint_t value)244 sem_init(sem_t *sem, int pshared, uint_t value)
245 {
246 int error;
247
248 if ((error = sema_init((sema_t *)sem, value,
249 pshared ? USYNC_PROCESS : USYNC_THREAD, NULL)) != 0) {
250 errno = error;
251 return (-1);
252 }
253 return (0);
254 }
255
256 int
sem_destroy(sem_t * sem)257 sem_destroy(sem_t *sem)
258 {
259 int error;
260
261 if (sem_invalid(sem))
262 return (-1);
263 if ((error = sema_destroy((sema_t *)sem)) != 0) {
264 errno = error;
265 return (-1);
266 }
267 return (0);
268 }
269
270 int
sem_post(sem_t * sem)271 sem_post(sem_t *sem)
272 {
273 int error;
274
275 if (sem_invalid(sem))
276 return (-1);
277 if ((error = sema_post((sema_t *)sem)) != 0) {
278 errno = error;
279 return (-1);
280 }
281 return (0);
282 }
283
284 int
sem_wait(sem_t * sem)285 sem_wait(sem_t *sem)
286 {
287 int error;
288
289 if (sem_invalid(sem))
290 return (-1);
291 if ((error = sema_wait((sema_t *)sem)) != 0) {
292 errno = error;
293 return (-1);
294 }
295 return (0);
296 }
297
298 int
sem_timedwait(sem_t * sem,const timespec_t * abstime)299 sem_timedwait(sem_t *sem, const timespec_t *abstime)
300 {
301 int error;
302
303 if (sem_invalid(sem))
304 return (-1);
305 if ((error = sema_timedwait((sema_t *)sem, abstime)) != 0) {
306 if (error == ETIME)
307 error = ETIMEDOUT;
308 errno = error;
309 return (-1);
310 }
311 return (0);
312 }
313
314 int
sem_reltimedwait_np(sem_t * sem,const timespec_t * reltime)315 sem_reltimedwait_np(sem_t *sem, const timespec_t *reltime)
316 {
317 int error;
318
319 if (sem_invalid(sem))
320 return (-1);
321 if ((error = sema_reltimedwait((sema_t *)sem, reltime)) != 0) {
322 if (error == ETIME)
323 error = ETIMEDOUT;
324 errno = error;
325 return (-1);
326 }
327 return (0);
328 }
329
330 int
sem_trywait(sem_t * sem)331 sem_trywait(sem_t *sem)
332 {
333 int error;
334
335 if (sem_invalid(sem))
336 return (-1);
337 if ((error = sema_trywait((sema_t *)sem)) != 0) {
338 if (error == EBUSY)
339 error = EAGAIN;
340 errno = error;
341 return (-1);
342 }
343 return (0);
344 }
345
346 int
sem_getvalue(sem_t * sem,int * sval)347 sem_getvalue(sem_t *sem, int *sval)
348 {
349 if (sem_invalid(sem))
350 return (-1);
351 *sval = (int)sem->sem_count;
352 return (0);
353 }
354