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