xref: /illumos-gate/usr/src/lib/libc/port/rt/sem.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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