Unleashed v1.4
[unleashed.git] / usr / src / lib / libc / port / rt / sem.c
blobca596b410ede8849f5951a5dfbce93b449de89fc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "lint.h"
30 #include "mtlib.h"
31 #include <sys/types.h>
32 #include <semaphore.h>
33 #include <synch.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <limits.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <sys/mman.h>
41 #include <unistd.h>
42 #include <thread.h>
43 #include "pos4obj.h"
45 typedef struct semaddr {
46 struct semaddr *sad_next; /* next in the link */
47 char sad_name[PATH_MAX + 1]; /* name of sem object */
48 sem_t *sad_addr; /* mmapped address of semaphore */
49 ino64_t sad_inode; /* inode # of the mmapped file */
50 } semaddr_t;
52 static long semvaluemax = 0;
53 static semaddr_t *semheadp = NULL;
54 static mutex_t semlock = DEFAULTMUTEX;
56 sem_t *
57 sem_open(const char *path, int oflag, /* mode_t mode, int value */ ...)
59 va_list ap;
60 mode_t crmode = 0;
61 sem_t *sem = NULL;
62 struct stat statbuf;
63 semaddr_t *next = NULL;
64 int fd = 0;
65 int error = 0;
66 int cr_flag = 0;
67 uint_t value = 0;
69 if (__pos4obj_check(path) == -1)
70 return (SEM_FAILED);
72 /* acquire semaphore lock to have atomic operation */
73 if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0)
74 return (SEM_FAILED);
76 /* modify oflag to have RDWR and filter CREATE mode only */
77 oflag = (oflag & (O_CREAT|O_EXCL)) | (O_RDWR);
78 if (oflag & O_CREAT) {
79 if (semvaluemax == 0 &&
80 (semvaluemax = _sysconf(_SC_SEM_VALUE_MAX)) <= 0)
81 semvaluemax = -1;
82 va_start(ap, oflag);
83 crmode = va_arg(ap, mode_t);
84 value = va_arg(ap, uint_t);
85 va_end(ap);
86 /* check value < the max for a named semaphore */
87 if (semvaluemax < 0 ||
88 (ulong_t)value > (ulong_t)semvaluemax) {
89 errno = EINVAL;
90 goto out;
94 errno = 0;
96 if ((fd = __pos4obj_open(path, SEM_DATA_TYPE,
97 oflag, crmode, &cr_flag)) < 0)
98 goto out;
100 if (cr_flag)
101 cr_flag = DFILE_CREATE | DFILE_OPEN;
102 else
103 cr_flag = DFILE_OPEN;
105 /* find out inode # for the opened file */
106 if (fstat(fd, &statbuf) < 0)
107 goto out;
109 /* if created, acquire total_size in the file */
110 if ((cr_flag & DFILE_CREATE) != 0) {
111 if (ftruncate(fd, (off64_t)sizeof (sem_t)) < 0)
112 goto out;
113 } else {
115 * if this semaphore has already been opened, inode
116 * will indicate then return the same semaphore address
118 lmutex_lock(&semlock);
119 for (next = semheadp; next != NULL; next = next->sad_next) {
120 if (statbuf.st_ino == next->sad_inode &&
121 strcmp(path, next->sad_name) == 0) {
122 (void) __close_nc(fd);
123 lmutex_unlock(&semlock);
124 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
125 return (next->sad_addr);
128 lmutex_unlock(&semlock);
132 /* new sem descriptor to be allocated and new address to be mapped */
133 if ((next = malloc(sizeof (semaddr_t))) == NULL) {
134 errno = ENOMEM;
135 goto out;
137 cr_flag |= ALLOC_MEM;
139 /* LINTED */
140 sem = mmap(NULL, sizeof (sem_t), PROT_READ|PROT_WRITE,
141 MAP_SHARED, fd, (off64_t)0);
142 (void) __close_nc(fd);
143 cr_flag &= ~DFILE_OPEN;
144 if (sem == MAP_FAILED)
145 goto out;
146 cr_flag |= DFILE_MMAP;
148 /* if created, initialize */
149 if (cr_flag & DFILE_CREATE) {
150 error = sema_init((sema_t *)sem, value, USYNC_PROCESS, 0);
151 if (error) {
152 errno = error;
153 goto out;
157 if (__pos4obj_unlock(path, SEM_LOCK_TYPE) == 0) {
158 /* add to the list pointed by semheadp */
159 lmutex_lock(&semlock);
160 next->sad_next = semheadp;
161 semheadp = next;
162 next->sad_addr = sem;
163 next->sad_inode = statbuf.st_ino;
164 (void) strcpy(next->sad_name, path);
165 lmutex_unlock(&semlock);
166 return (sem);
168 /* fall into the error case */
169 out:
170 error = errno;
171 if ((cr_flag & DFILE_OPEN) != 0)
172 (void) __close_nc(fd);
173 if ((cr_flag & DFILE_CREATE) != 0)
174 (void) __pos4obj_unlink(path, SEM_DATA_TYPE);
175 if ((cr_flag & ALLOC_MEM) != 0)
176 free(next);
177 if ((cr_flag & DFILE_MMAP) != 0)
178 (void) munmap((caddr_t)sem, sizeof (sem_t));
179 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
180 errno = error;
181 return (SEM_FAILED);
185 sem_close(sem_t *sem)
187 semaddr_t **next;
188 semaddr_t *freeit;
190 lmutex_lock(&semlock);
191 for (next = &semheadp; (freeit = *next) != NULL;
192 next = &(freeit->sad_next)) {
193 if (freeit->sad_addr == sem) {
194 *next = freeit->sad_next;
195 lmutex_unlock(&semlock);
196 free(freeit);
197 return (munmap((caddr_t)sem, sizeof (sem_t)));
200 lmutex_unlock(&semlock);
201 errno = EINVAL;
202 return (-1);
206 sem_unlink(const char *path)
208 int error;
209 int oerrno;
211 if (__pos4obj_check(path) < 0)
212 return (-1);
214 if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0)
215 return (-1);
217 error = __pos4obj_unlink(path, SEM_DATA_TYPE);
219 oerrno = errno;
221 (void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
223 errno = oerrno;
225 return (error);
229 * SUSV3 requires ("shall fail") an EINVAL failure for operations
230 * on invalid semaphores, including uninitialized unnamed semaphores.
231 * The best we can do is check that the magic number is correct.
232 * This is not perfect, but it allows the test suite to pass.
233 * (Standards bodies are filled with fools and idiots.)
235 static int
236 sem_invalid(sem_t *sem)
238 if (sem->sem_magic != SEMA_MAGIC) {
239 errno = EINVAL;
240 return (-1);
242 return (0);
246 sem_init(sem_t *sem, int pshared, uint_t value)
248 int error;
250 if ((error = sema_init((sema_t *)sem, value,
251 pshared ? USYNC_PROCESS : USYNC_THREAD, NULL)) != 0) {
252 errno = error;
253 return (-1);
255 return (0);
259 sem_destroy(sem_t *sem)
261 int error;
263 if (sem_invalid(sem))
264 return (-1);
265 if ((error = sema_destroy((sema_t *)sem)) != 0) {
266 errno = error;
267 return (-1);
269 return (0);
273 sem_post(sem_t *sem)
275 int error;
277 if (sem_invalid(sem))
278 return (-1);
279 if ((error = sema_post((sema_t *)sem)) != 0) {
280 errno = error;
281 return (-1);
283 return (0);
287 sem_wait(sem_t *sem)
289 int error;
291 if (sem_invalid(sem))
292 return (-1);
293 if ((error = sema_wait((sema_t *)sem)) != 0) {
294 errno = error;
295 return (-1);
297 return (0);
301 sem_timedwait(sem_t *sem, const timespec_t *abstime)
303 int error;
305 if (sem_invalid(sem))
306 return (-1);
307 if ((error = sema_timedwait((sema_t *)sem, abstime)) != 0) {
308 if (error == ETIME)
309 error = ETIMEDOUT;
310 errno = error;
311 return (-1);
313 return (0);
317 sem_reltimedwait_np(sem_t *sem, const timespec_t *reltime)
319 int error;
321 if (sem_invalid(sem))
322 return (-1);
323 if ((error = sema_reltimedwait((sema_t *)sem, reltime)) != 0) {
324 if (error == ETIME)
325 error = ETIMEDOUT;
326 errno = error;
327 return (-1);
329 return (0);
333 sem_trywait(sem_t *sem)
335 int error;
337 if (sem_invalid(sem))
338 return (-1);
339 if ((error = sema_trywait((sema_t *)sem)) != 0) {
340 if (error == EBUSY)
341 error = EAGAIN;
342 errno = error;
343 return (-1);
345 return (0);
349 sem_getvalue(sem_t *sem, int *sval)
351 if (sem_invalid(sem))
352 return (-1);
353 *sval = (int)sem->sem_count;
354 return (0);