xref: /onnv-gate/usr/src/lib/libc/port/rt/sem.c (revision 6812:febeba71273d)
12248Sraf /*
22248Sraf  * CDDL HEADER START
32248Sraf  *
42248Sraf  * The contents of this file are subject to the terms of the
52248Sraf  * Common Development and Distribution License (the "License").
62248Sraf  * You may not use this file except in compliance with the License.
72248Sraf  *
82248Sraf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92248Sraf  * or http://www.opensolaris.org/os/licensing.
102248Sraf  * See the License for the specific language governing permissions
112248Sraf  * and limitations under the License.
122248Sraf  *
132248Sraf  * When distributing Covered Code, include this CDDL HEADER in each
142248Sraf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152248Sraf  * If applicable, add the following below this CDDL HEADER, with the
162248Sraf  * fields enclosed by brackets "[]" replaced with your own identifying
172248Sraf  * information: Portions Copyright [yyyy] [name of copyright owner]
182248Sraf  *
192248Sraf  * CDDL HEADER END
202248Sraf  */
212248Sraf 
222248Sraf /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242248Sraf  * Use is subject to license terms.
252248Sraf  */
262248Sraf 
272248Sraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
282248Sraf 
29*6812Sraf #include "lint.h"
302248Sraf #include "mtlib.h"
312248Sraf #include <sys/types.h>
322248Sraf #include <semaphore.h>
332248Sraf #include <synch.h>
342248Sraf #include <errno.h>
352248Sraf #include <stdarg.h>
362248Sraf #include <limits.h>
372248Sraf #include <stdlib.h>
382248Sraf #include <string.h>
392248Sraf #include <sys/stat.h>
402248Sraf #include <sys/mman.h>
412248Sraf #include <unistd.h>
422248Sraf #include <thread.h>
432248Sraf #include "pos4obj.h"
442248Sraf 
452248Sraf typedef	struct	semaddr {
462248Sraf 	struct	semaddr	*sad_next;	/* next in the link */
472248Sraf 	char		sad_name[PATH_MAX + 1]; /* name of sem object */
482248Sraf 	sem_t		*sad_addr;	/* mmapped address of semaphore */
492248Sraf 	ino64_t		sad_inode;	/* inode # of the mmapped file */
502248Sraf } semaddr_t;
512248Sraf 
522248Sraf static long semvaluemax = 0;
532248Sraf static semaddr_t *semheadp = NULL;
542248Sraf static mutex_t semlock = DEFAULTMUTEX;
552248Sraf 
562248Sraf sem_t *
sem_open(const char * path,int oflag,...)57*6812Sraf sem_open(const char *path, int oflag, /* mode_t mode, int value */ ...)
582248Sraf {
592248Sraf 	va_list	ap;
602248Sraf 	mode_t	crmode = 0;
612248Sraf 	sem_t	*sem = NULL;
622248Sraf 	struct	stat64 statbuf;
632248Sraf 	semaddr_t *next = NULL;
642248Sraf 	int	fd = 0;
652248Sraf 	int	error = 0;
662248Sraf 	int	cr_flag = 0;
672248Sraf 	uint_t	value = 0;
682248Sraf 
692248Sraf 	if (__pos4obj_check(path) == -1)
702248Sraf 		return (SEM_FAILED);
712248Sraf 
722248Sraf 	/* acquire semaphore lock to have atomic operation */
732248Sraf 	if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0)
742248Sraf 		return (SEM_FAILED);
752248Sraf 
762248Sraf 	/* modify oflag to have RDWR and filter CREATE mode only */
772248Sraf 	oflag = (oflag & (O_CREAT|O_EXCL)) | (O_RDWR);
782248Sraf 	if (oflag & O_CREAT) {
792248Sraf 		if (semvaluemax == 0 &&
802248Sraf 		    (semvaluemax = _sysconf(_SC_SEM_VALUE_MAX)) <= 0)
812248Sraf 			semvaluemax = -1;
822248Sraf 		va_start(ap, oflag);
832248Sraf 		crmode = va_arg(ap, mode_t);
842248Sraf 		value = va_arg(ap, uint_t);
852248Sraf 		va_end(ap);
862248Sraf 		/* check value < the max for a named semaphore */
872248Sraf 		if (semvaluemax < 0 ||
882248Sraf 		    (ulong_t)value > (ulong_t)semvaluemax) {
892248Sraf 			errno = EINVAL;
902248Sraf 			goto out;
912248Sraf 		}
922248Sraf 	}
932248Sraf 
942248Sraf 	errno = 0;
952248Sraf 
962248Sraf 	if ((fd = __pos4obj_open(path, SEM_DATA_TYPE,
97*6812Sraf 	    oflag, crmode, &cr_flag)) < 0)
982248Sraf 		goto out;
992248Sraf 
1002248Sraf 	if (cr_flag)
1012248Sraf 		cr_flag = DFILE_CREATE | DFILE_OPEN;
1022248Sraf 	else
1032248Sraf 		cr_flag = DFILE_OPEN;
1042248Sraf 
1052248Sraf 	/* find out inode # for the opened file */
1062248Sraf 	if (fstat64(fd, &statbuf) < 0)
1072248Sraf 		goto out;
1082248Sraf 
1092248Sraf 	/* if created, acquire total_size in the file */
1102248Sraf 	if ((cr_flag & DFILE_CREATE) != 0) {
1112248Sraf 		if (ftruncate64(fd, (off64_t)sizeof (sem_t)) < 0)
1122248Sraf 			goto out;
1132248Sraf 	} else {
1142248Sraf 		/*
1152248Sraf 		 * if this semaphore has already been opened, inode
1162248Sraf 		 * will indicate then return the same semaphore address
1172248Sraf 		 */
1182248Sraf 		lmutex_lock(&semlock);
1192248Sraf 		for (next = semheadp; next != NULL; next = next->sad_next) {
1202248Sraf 			if (statbuf.st_ino == next->sad_inode &&
1212248Sraf 			    strcmp(path, next->sad_name) == 0) {
1222248Sraf 				(void) __close_nc(fd);
1232248Sraf 				lmutex_unlock(&semlock);
1242248Sraf 				(void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
1252248Sraf 				return (next->sad_addr);
1262248Sraf 			}
1272248Sraf 		}
1282248Sraf 		lmutex_unlock(&semlock);
1292248Sraf 	}
1302248Sraf 
1312248Sraf 
1322248Sraf 	/* new sem descriptor to be allocated and new address to be mapped */
1332248Sraf 	if ((next = malloc(sizeof (semaddr_t))) == NULL) {
1342248Sraf 		errno = ENOMEM;
1352248Sraf 		goto out;
1362248Sraf 	}
1372248Sraf 	cr_flag |= ALLOC_MEM;
1382248Sraf 
1392248Sraf 	/* LINTED */
1402248Sraf 	sem = (sem_t *)mmap64(NULL, sizeof (sem_t), PROT_READ|PROT_WRITE,
141*6812Sraf 	    MAP_SHARED, fd, (off64_t)0);
1422248Sraf 	(void) __close_nc(fd);
1432248Sraf 	cr_flag &= ~DFILE_OPEN;
1442248Sraf 	if (sem == MAP_FAILED)
1452248Sraf 		goto out;
1462248Sraf 	cr_flag |= DFILE_MMAP;
1472248Sraf 
1482248Sraf 	/* if created, initialize */
1492248Sraf 	if (cr_flag & DFILE_CREATE) {
1502248Sraf 		error = sema_init((sema_t *)sem, value, USYNC_PROCESS, 0);
1512248Sraf 		if (error) {
1522248Sraf 			errno = error;
1532248Sraf 			goto out;
1542248Sraf 		}
1552248Sraf 	}
1562248Sraf 
1572248Sraf 	if (__pos4obj_unlock(path, SEM_LOCK_TYPE) == 0) {
1582248Sraf 		/* add to the list pointed by semheadp */
1592248Sraf 		lmutex_lock(&semlock);
1602248Sraf 		next->sad_next = semheadp;
1612248Sraf 		semheadp = next;
1622248Sraf 		next->sad_addr = sem;
1632248Sraf 		next->sad_inode = statbuf.st_ino;
1642248Sraf 		(void) strcpy(next->sad_name, path);
1652248Sraf 		lmutex_unlock(&semlock);
1662248Sraf 		return (sem);
1672248Sraf 	}
1682248Sraf 	/* fall into the error case */
1692248Sraf out:
1702248Sraf 	error = errno;
1712248Sraf 	if ((cr_flag & DFILE_OPEN) != 0)
1722248Sraf 		(void) __close_nc(fd);
1732248Sraf 	if ((cr_flag & DFILE_CREATE) != 0)
1742248Sraf 		(void) __pos4obj_unlink(path, SEM_DATA_TYPE);
1752248Sraf 	if ((cr_flag & ALLOC_MEM) != 0)
1762248Sraf 		free(next);
1772248Sraf 	if ((cr_flag & DFILE_MMAP) != 0)
1782248Sraf 		(void) munmap((caddr_t)sem, sizeof (sem_t));
1792248Sraf 	(void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
1802248Sraf 	errno = error;
1812248Sraf 	return (SEM_FAILED);
1822248Sraf }
1832248Sraf 
1842248Sraf int
sem_close(sem_t * sem)185*6812Sraf sem_close(sem_t *sem)
1862248Sraf {
1872248Sraf 	semaddr_t	**next;
1882248Sraf 	semaddr_t	*freeit;
1892248Sraf 
1902248Sraf 	lmutex_lock(&semlock);
1912248Sraf 	for (next = &semheadp; (freeit = *next) != NULL;
1922248Sraf 	    next = &(freeit->sad_next)) {
1932248Sraf 		if (freeit->sad_addr == sem) {
1942248Sraf 			*next = freeit->sad_next;
1952248Sraf 			lmutex_unlock(&semlock);
1962248Sraf 			free(freeit);
1972248Sraf 			return (munmap((caddr_t)sem, sizeof (sem_t)));
1982248Sraf 		}
1992248Sraf 	}
2002248Sraf 	lmutex_unlock(&semlock);
2012248Sraf 	errno = EINVAL;
2022248Sraf 	return (-1);
2032248Sraf }
2042248Sraf 
2052248Sraf int
sem_unlink(const char * path)206*6812Sraf sem_unlink(const char *path)
2072248Sraf {
2082248Sraf 	int	error;
2092248Sraf 	int	oerrno;
2102248Sraf 
2112248Sraf 	if (__pos4obj_check(path) < 0)
2122248Sraf 		return (-1);
2132248Sraf 
2142248Sraf 	if (__pos4obj_lock(path, SEM_LOCK_TYPE) < 0)
2152248Sraf 		return (-1);
2162248Sraf 
2172248Sraf 	error =  __pos4obj_unlink(path, SEM_DATA_TYPE);
2182248Sraf 
2192248Sraf 	oerrno = errno;
2202248Sraf 
2212248Sraf 	(void) __pos4obj_unlock(path, SEM_LOCK_TYPE);
2222248Sraf 
2232248Sraf 	errno = oerrno;
2242248Sraf 
2252248Sraf 	return (error);
2262248Sraf }
2272248Sraf 
2282248Sraf /*
2292248Sraf  * SUSV3 requires ("shall fail") an EINVAL failure for operations
2302248Sraf  * on invalid semaphores, including uninitialized unnamed semaphores.
2312248Sraf  * The best we can do is check that the magic number is correct.
2322248Sraf  * This is not perfect, but it allows the test suite to pass.
2332248Sraf  * (Standards bodies are filled with fools and idiots.)
2342248Sraf  */
2352248Sraf static int
sem_invalid(sem_t * sem)2362248Sraf sem_invalid(sem_t *sem)
2372248Sraf {
2382248Sraf 	if (sem->sem_magic != SEMA_MAGIC) {
2392248Sraf 		errno = EINVAL;
2402248Sraf 		return (-1);
2412248Sraf 	}
2422248Sraf 	return (0);
2432248Sraf }
2442248Sraf 
2452248Sraf int
sem_init(sem_t * sem,int pshared,uint_t value)246*6812Sraf sem_init(sem_t *sem, int pshared, uint_t value)
2472248Sraf {
2482248Sraf 	int	error;
2492248Sraf 
2502248Sraf 	if ((error = sema_init((sema_t *)sem, value,
2512248Sraf 	    pshared ? USYNC_PROCESS : USYNC_THREAD, NULL)) != 0) {
2522248Sraf 		errno = error;
2532248Sraf 		return (-1);
2542248Sraf 	}
2552248Sraf 	return (0);
2562248Sraf }
2572248Sraf 
2582248Sraf int
sem_destroy(sem_t * sem)259*6812Sraf sem_destroy(sem_t *sem)
2602248Sraf {
2612248Sraf 	int	error;
2622248Sraf 
2632248Sraf 	if (sem_invalid(sem))
2642248Sraf 		return (-1);
2652248Sraf 	if ((error = sema_destroy((sema_t *)sem)) != 0) {
2662248Sraf 		errno = error;
2672248Sraf 		return (-1);
2682248Sraf 	}
2692248Sraf 	return (0);
2702248Sraf }
2712248Sraf 
2722248Sraf int
sem_post(sem_t * sem)273*6812Sraf sem_post(sem_t *sem)
2742248Sraf {
2752248Sraf 	int	error;
2762248Sraf 
2772248Sraf 	if (sem_invalid(sem))
2782248Sraf 		return (-1);
2792248Sraf 	if ((error = sema_post((sema_t *)sem)) != 0) {
2802248Sraf 		errno = error;
2812248Sraf 		return (-1);
2822248Sraf 	}
2832248Sraf 	return (0);
2842248Sraf }
2852248Sraf 
2862248Sraf int
sem_wait(sem_t * sem)287*6812Sraf sem_wait(sem_t *sem)
2882248Sraf {
2892248Sraf 	int	error;
2902248Sraf 
2912248Sraf 	if (sem_invalid(sem))
2922248Sraf 		return (-1);
2932248Sraf 	if ((error = sema_wait((sema_t *)sem)) != 0) {
2942248Sraf 		errno = error;
2952248Sraf 		return (-1);
2962248Sraf 	}
2972248Sraf 	return (0);
2982248Sraf }
2992248Sraf 
3002248Sraf int
sem_timedwait(sem_t * sem,const timespec_t * abstime)301*6812Sraf sem_timedwait(sem_t *sem, const timespec_t *abstime)
3022248Sraf {
3032248Sraf 	int	error;
3042248Sraf 
3052248Sraf 	if (sem_invalid(sem))
3062248Sraf 		return (-1);
3072248Sraf 	if ((error = sema_timedwait((sema_t *)sem, abstime)) != 0) {
3082248Sraf 		if (error == ETIME)
3092248Sraf 			error = ETIMEDOUT;
3102248Sraf 		errno = error;
3112248Sraf 		return (-1);
3122248Sraf 	}
3132248Sraf 	return (0);
3142248Sraf }
3152248Sraf 
3162248Sraf int
sem_reltimedwait_np(sem_t * sem,const timespec_t * reltime)317*6812Sraf sem_reltimedwait_np(sem_t *sem, const timespec_t *reltime)
3182248Sraf {
3192248Sraf 	int	error;
3202248Sraf 
3212248Sraf 	if (sem_invalid(sem))
3222248Sraf 		return (-1);
3232248Sraf 	if ((error = sema_reltimedwait((sema_t *)sem, reltime)) != 0) {
3242248Sraf 		if (error == ETIME)
3252248Sraf 			error = ETIMEDOUT;
3262248Sraf 		errno = error;
3272248Sraf 		return (-1);
3282248Sraf 	}
3292248Sraf 	return (0);
3302248Sraf }
3312248Sraf 
3322248Sraf int
sem_trywait(sem_t * sem)333*6812Sraf sem_trywait(sem_t *sem)
3342248Sraf {
3352248Sraf 	int	error;
3362248Sraf 
3372248Sraf 	if (sem_invalid(sem))
3382248Sraf 		return (-1);
3392248Sraf 	if ((error = sema_trywait((sema_t *)sem)) != 0) {
3402248Sraf 		if (error == EBUSY)
3412248Sraf 			error = EAGAIN;
3422248Sraf 		errno = error;
3432248Sraf 		return (-1);
3442248Sraf 	}
3452248Sraf 	return (0);
3462248Sraf }
3472248Sraf 
3482248Sraf int
sem_getvalue(sem_t * sem,int * sval)349*6812Sraf sem_getvalue(sem_t *sem, int *sval)
3502248Sraf {
3512248Sraf 	if (sem_invalid(sem))
3522248Sraf 		return (-1);
3532248Sraf 	*sval = (int)sem->sem_count;
3542248Sraf 	return (0);
3552248Sraf }
356