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