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