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