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