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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <sys/types.h>
32 #include <semaphore.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 */
52 static long semvaluemax
= 0;
53 static semaddr_t
*semheadp
= NULL
;
54 static mutex_t semlock
= DEFAULTMUTEX
;
57 sem_open(const char *path
, int oflag
, /* mode_t mode, int value */ ...)
62 struct stat64 statbuf
;
63 semaddr_t
*next
= NULL
;
69 if (__pos4obj_check(path
) == -1)
72 /* acquire semaphore lock to have atomic operation */
73 if (__pos4obj_lock(path
, SEM_LOCK_TYPE
) < 0)
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)
83 crmode
= va_arg(ap
, mode_t
);
84 value
= va_arg(ap
, uint_t
);
86 /* check value < the max for a named semaphore */
87 if (semvaluemax
< 0 ||
88 (ulong_t
)value
> (ulong_t
)semvaluemax
) {
96 if ((fd
= __pos4obj_open(path
, SEM_DATA_TYPE
,
97 oflag
, crmode
, &cr_flag
)) < 0)
101 cr_flag
= DFILE_CREATE
| DFILE_OPEN
;
103 cr_flag
= DFILE_OPEN
;
105 /* find out inode # for the opened file */
106 if (fstat64(fd
, &statbuf
) < 0)
109 /* if created, acquire total_size in the file */
110 if ((cr_flag
& DFILE_CREATE
) != 0) {
111 if (ftruncate64(fd
, (off64_t
)sizeof (sem_t
)) < 0)
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
) {
137 cr_flag
|= ALLOC_MEM
;
140 sem
= mmap64(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
)
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);
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
;
162 next
->sad_addr
= sem
;
163 next
->sad_inode
= statbuf
.st_ino
;
164 (void) strcpy(next
->sad_name
, path
);
165 lmutex_unlock(&semlock
);
168 /* fall into the error case */
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)
177 if ((cr_flag
& DFILE_MMAP
) != 0)
178 (void) munmap((caddr_t
)sem
, sizeof (sem_t
));
179 (void) __pos4obj_unlock(path
, SEM_LOCK_TYPE
);
185 sem_close(sem_t
*sem
)
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
);
197 return (munmap((caddr_t
)sem
, sizeof (sem_t
)));
200 lmutex_unlock(&semlock
);
206 sem_unlink(const char *path
)
211 if (__pos4obj_check(path
) < 0)
214 if (__pos4obj_lock(path
, SEM_LOCK_TYPE
) < 0)
217 error
= __pos4obj_unlink(path
, SEM_DATA_TYPE
);
221 (void) __pos4obj_unlock(path
, SEM_LOCK_TYPE
);
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.)
236 sem_invalid(sem_t
*sem
)
238 if (sem
->sem_magic
!= SEMA_MAGIC
) {
246 sem_init(sem_t
*sem
, int pshared
, uint_t value
)
250 if ((error
= sema_init((sema_t
*)sem
, value
,
251 pshared
? USYNC_PROCESS
: USYNC_THREAD
, NULL
)) != 0) {
259 sem_destroy(sem_t
*sem
)
263 if (sem_invalid(sem
))
265 if ((error
= sema_destroy((sema_t
*)sem
)) != 0) {
277 if (sem_invalid(sem
))
279 if ((error
= sema_post((sema_t
*)sem
)) != 0) {
291 if (sem_invalid(sem
))
293 if ((error
= sema_wait((sema_t
*)sem
)) != 0) {
301 sem_timedwait(sem_t
*sem
, const timespec_t
*abstime
)
305 if (sem_invalid(sem
))
307 if ((error
= sema_timedwait((sema_t
*)sem
, abstime
)) != 0) {
317 sem_reltimedwait_np(sem_t
*sem
, const timespec_t
*reltime
)
321 if (sem_invalid(sem
))
323 if ((error
= sema_reltimedwait((sema_t
*)sem
, reltime
)) != 0) {
333 sem_trywait(sem_t
*sem
)
337 if (sem_invalid(sem
))
339 if ((error
= sema_trywait((sema_t
*)sem
)) != 0) {
349 sem_getvalue(sem_t
*sem
, int *sval
)
351 if (sem_invalid(sem
))
353 *sval
= (int)sem
->sem_count
;