1bf4dc877SAlfred Perlstein /* 2bf4dc877SAlfred Perlstein * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. 3bf4dc877SAlfred Perlstein * All rights reserved. 4bf4dc877SAlfred Perlstein * 5bf4dc877SAlfred Perlstein * Redistribution and use in source and binary forms, with or without 6bf4dc877SAlfred Perlstein * modification, are permitted provided that the following conditions 7bf4dc877SAlfred Perlstein * are met: 8bf4dc877SAlfred Perlstein * 1. Redistributions of source code must retain the above copyright 9bf4dc877SAlfred Perlstein * notice(s), this list of conditions and the following disclaimer as 10bf4dc877SAlfred Perlstein * the first lines of this file unmodified other than the possible 11bf4dc877SAlfred Perlstein * addition of one or more copyright notices. 12bf4dc877SAlfred Perlstein * 2. Redistributions in binary form must reproduce the above copyright 13bf4dc877SAlfred Perlstein * notice(s), this list of conditions and the following disclaimer in 14bf4dc877SAlfred Perlstein * the documentation and/or other materials provided with the 15bf4dc877SAlfred Perlstein * distribution. 16bf4dc877SAlfred Perlstein * 17bf4dc877SAlfred Perlstein * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 18bf4dc877SAlfred Perlstein * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19bf4dc877SAlfred Perlstein * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20bf4dc877SAlfred Perlstein * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 21bf4dc877SAlfred Perlstein * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22bf4dc877SAlfred Perlstein * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23bf4dc877SAlfred Perlstein * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24bf4dc877SAlfred Perlstein * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25bf4dc877SAlfred Perlstein * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26bf4dc877SAlfred Perlstein * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27bf4dc877SAlfred Perlstein * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28bf4dc877SAlfred Perlstein * 29bf4dc877SAlfred Perlstein * $FreeBSD$ 30bf4dc877SAlfred Perlstein */ 31bf4dc877SAlfred Perlstein 32e0554a53SJacques Vidrine #include "namespace.h" 33bf4dc877SAlfred Perlstein #include <stdlib.h> 34bf4dc877SAlfred Perlstein #include <errno.h> 35bf4dc877SAlfred Perlstein #include <fcntl.h> 36bf4dc877SAlfred Perlstein #include <semaphore.h> 37bf4dc877SAlfred Perlstein #include <stdarg.h> 38bf4dc877SAlfred Perlstein #include <pthread.h> 39bf4dc877SAlfred Perlstein #include <sys/queue.h> 40bf4dc877SAlfred Perlstein #include <_semaphore.h> 41e0554a53SJacques Vidrine #include "un-namespace.h" 42bf4dc877SAlfred Perlstein 43bf4dc877SAlfred Perlstein #define _SEM_CHECK_VALIDITY(sem) \ 44bf4dc877SAlfred Perlstein if ((*(sem))->magic != SEM_MAGIC) { \ 45bf4dc877SAlfred Perlstein errno = EINVAL; \ 46bf4dc877SAlfred Perlstein retval = -1; \ 47bf4dc877SAlfred Perlstein goto RETURN; \ 48bf4dc877SAlfred Perlstein } 49bf4dc877SAlfred Perlstein 50bf4dc877SAlfred Perlstein static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); 51bf4dc877SAlfred Perlstein static void sem_free(sem_t sem); 52bf4dc877SAlfred Perlstein 53bf4dc877SAlfred Perlstein static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); 54bf4dc877SAlfred Perlstein static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; 55bf4dc877SAlfred Perlstein 56bf4dc877SAlfred Perlstein static void 57bf4dc877SAlfred Perlstein sem_free(sem_t sem) 58bf4dc877SAlfred Perlstein { 59bf4dc877SAlfred Perlstein 60bf4dc877SAlfred Perlstein _pthread_mutex_destroy(&sem->lock); 61bf4dc877SAlfred Perlstein _pthread_cond_destroy(&sem->gtzero); 62bf4dc877SAlfred Perlstein sem->magic = 0; 63bf4dc877SAlfred Perlstein free(sem); 64bf4dc877SAlfred Perlstein } 65bf4dc877SAlfred Perlstein 66bf4dc877SAlfred Perlstein static sem_t 67bf4dc877SAlfred Perlstein sem_alloc(unsigned int value, semid_t semid, int system_sem) 68bf4dc877SAlfred Perlstein { 69bf4dc877SAlfred Perlstein sem_t sem; 70bf4dc877SAlfred Perlstein 71bf4dc877SAlfred Perlstein if (value > SEM_VALUE_MAX) { 72bf4dc877SAlfred Perlstein errno = EINVAL; 73bf4dc877SAlfred Perlstein return (NULL); 74bf4dc877SAlfred Perlstein } 75bf4dc877SAlfred Perlstein 76bf4dc877SAlfred Perlstein sem = (sem_t)malloc(sizeof(struct sem)); 77bf4dc877SAlfred Perlstein if (sem == NULL) { 78bf4dc877SAlfred Perlstein errno = ENOSPC; 79bf4dc877SAlfred Perlstein return (NULL); 80bf4dc877SAlfred Perlstein } 81bf4dc877SAlfred Perlstein 82bf4dc877SAlfred Perlstein /* 83bf4dc877SAlfred Perlstein * Initialize the semaphore. 84bf4dc877SAlfred Perlstein */ 85bf4dc877SAlfred Perlstein if (_pthread_mutex_init(&sem->lock, NULL) != 0) { 86bf4dc877SAlfred Perlstein free(sem); 87bf4dc877SAlfred Perlstein errno = ENOSPC; 88bf4dc877SAlfred Perlstein return (NULL); 89bf4dc877SAlfred Perlstein } 90bf4dc877SAlfred Perlstein 91bf4dc877SAlfred Perlstein if (_pthread_cond_init(&sem->gtzero, NULL) != 0) { 92bf4dc877SAlfred Perlstein _pthread_mutex_destroy(&sem->lock); 93bf4dc877SAlfred Perlstein free(sem); 94bf4dc877SAlfred Perlstein errno = ENOSPC; 95bf4dc877SAlfred Perlstein return (NULL); 96bf4dc877SAlfred Perlstein } 97bf4dc877SAlfred Perlstein 98bf4dc877SAlfred Perlstein sem->count = (u_int32_t)value; 99bf4dc877SAlfred Perlstein sem->nwaiters = 0; 100bf4dc877SAlfred Perlstein sem->magic = SEM_MAGIC; 101bf4dc877SAlfred Perlstein sem->semid = semid; 102bf4dc877SAlfred Perlstein sem->syssem = system_sem; 103bf4dc877SAlfred Perlstein return (sem); 104bf4dc877SAlfred Perlstein } 105bf4dc877SAlfred Perlstein 106bf4dc877SAlfred Perlstein int 107bf4dc877SAlfred Perlstein sem_init(sem_t *sem, int pshared, unsigned int value) 108bf4dc877SAlfred Perlstein { 109bf4dc877SAlfred Perlstein int retval, got_system_sem; 110bf4dc877SAlfred Perlstein semid_t semid; 111bf4dc877SAlfred Perlstein 112bf4dc877SAlfred Perlstein got_system_sem = 0; 113bf4dc877SAlfred Perlstein semid = SEM_USER; 114bf4dc877SAlfred Perlstein /* 115bf4dc877SAlfred Perlstein * Range check the arguments. 116bf4dc877SAlfred Perlstein */ 117bf4dc877SAlfred Perlstein if (pshared != 0) { 118bf4dc877SAlfred Perlstein retval = ksem_init(&semid, value); 119bf4dc877SAlfred Perlstein if (retval == -1) 120bf4dc877SAlfred Perlstein goto RETURN; 121bf4dc877SAlfred Perlstein got_system_sem = 1; 122bf4dc877SAlfred Perlstein } 123bf4dc877SAlfred Perlstein 124bf4dc877SAlfred Perlstein (*sem) = sem_alloc(value, semid, got_system_sem); 125bf4dc877SAlfred Perlstein if ((*sem) == NULL) 126bf4dc877SAlfred Perlstein retval = -1; 127bf4dc877SAlfred Perlstein else 128bf4dc877SAlfred Perlstein retval = 0; 129bf4dc877SAlfred Perlstein RETURN: 130bf4dc877SAlfred Perlstein if (retval != 0 && got_system_sem) 131bf4dc877SAlfred Perlstein ksem_destroy(semid); 132bf4dc877SAlfred Perlstein return retval; 133bf4dc877SAlfred Perlstein } 134bf4dc877SAlfred Perlstein 135bf4dc877SAlfred Perlstein int 136bf4dc877SAlfred Perlstein sem_destroy(sem_t *sem) 137bf4dc877SAlfred Perlstein { 138bf4dc877SAlfred Perlstein int retval; 139bf4dc877SAlfred Perlstein 140bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 141bf4dc877SAlfred Perlstein 142bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 143bf4dc877SAlfred Perlstein /* 144bf4dc877SAlfred Perlstein * If this is a system semaphore let the kernel track it otherwise 145bf4dc877SAlfred Perlstein * make sure there are no waiters. 146bf4dc877SAlfred Perlstein */ 147bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 148bf4dc877SAlfred Perlstein retval = ksem_destroy((*sem)->semid); 149bf4dc877SAlfred Perlstein if (retval == -1) { 150bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 151bf4dc877SAlfred Perlstein goto RETURN; 152bf4dc877SAlfred Perlstein } 153bf4dc877SAlfred Perlstein } else if ((*sem)->nwaiters > 0) { 154bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 155bf4dc877SAlfred Perlstein errno = EBUSY; 156bf4dc877SAlfred Perlstein retval = -1; 157bf4dc877SAlfred Perlstein goto RETURN; 158bf4dc877SAlfred Perlstein } 159bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 160bf4dc877SAlfred Perlstein 161bf4dc877SAlfred Perlstein sem_free(*sem); 162bf4dc877SAlfred Perlstein 163bf4dc877SAlfred Perlstein retval = 0; 164bf4dc877SAlfred Perlstein RETURN: 165bf4dc877SAlfred Perlstein return retval; 166bf4dc877SAlfred Perlstein } 167bf4dc877SAlfred Perlstein 168bf4dc877SAlfred Perlstein sem_t * 169bf4dc877SAlfred Perlstein sem_open(const char *name, int oflag, ...) 170bf4dc877SAlfred Perlstein { 171bf4dc877SAlfred Perlstein sem_t *sem; 172bf4dc877SAlfred Perlstein sem_t s; 173bf4dc877SAlfred Perlstein semid_t semid; 174bf4dc877SAlfred Perlstein mode_t mode; 175bf4dc877SAlfred Perlstein unsigned int value; 176bf4dc877SAlfred Perlstein 177bf4dc877SAlfred Perlstein mode = 0; 178bf4dc877SAlfred Perlstein value = 0; 179bf4dc877SAlfred Perlstein 180bf4dc877SAlfred Perlstein if ((oflag & O_CREAT) != 0) { 181bf4dc877SAlfred Perlstein va_list ap; 182bf4dc877SAlfred Perlstein 183bf4dc877SAlfred Perlstein va_start(ap, oflag); 184bf4dc877SAlfred Perlstein mode = va_arg(ap, int); 185bf4dc877SAlfred Perlstein value = va_arg(ap, unsigned int); 186bf4dc877SAlfred Perlstein va_end(ap); 187bf4dc877SAlfred Perlstein } 188bf4dc877SAlfred Perlstein /* 189bf4dc877SAlfred Perlstein * we can be lazy and let the kernel handle the "oflag", 190bf4dc877SAlfred Perlstein * we'll just merge duplicate IDs into our list. 191bf4dc877SAlfred Perlstein */ 192bf4dc877SAlfred Perlstein if (ksem_open(&semid, name, oflag, mode, value) == -1) 193bf4dc877SAlfred Perlstein return (SEM_FAILED); 194bf4dc877SAlfred Perlstein /* 195bf4dc877SAlfred Perlstein * search for a duplicate ID, we must return the same sem_t * 196bf4dc877SAlfred Perlstein * if we locate one. 197bf4dc877SAlfred Perlstein */ 198bf4dc877SAlfred Perlstein _pthread_mutex_lock(&named_sems_mtx); 199bf4dc877SAlfred Perlstein LIST_FOREACH(s, &named_sems, entry) { 200bf4dc877SAlfred Perlstein if (s->semid == semid) { 201bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 202bf4dc877SAlfred Perlstein return (s->backpointer); 203bf4dc877SAlfred Perlstein } 204bf4dc877SAlfred Perlstein } 205bf4dc877SAlfred Perlstein sem = (sem_t *)malloc(sizeof(*sem)); 206bf4dc877SAlfred Perlstein if (sem == NULL) 207bf4dc877SAlfred Perlstein goto err; 208bf4dc877SAlfred Perlstein *sem = sem_alloc(value, semid, 1); 209bf4dc877SAlfred Perlstein if ((*sem) == NULL) 210bf4dc877SAlfred Perlstein goto err; 211a91b25dcSTim J. Robbins LIST_INSERT_HEAD(&named_sems, *sem, entry); 212bf4dc877SAlfred Perlstein (*sem)->backpointer = sem; 213a91b25dcSTim J. Robbins _pthread_mutex_unlock(&named_sems_mtx); 214bf4dc877SAlfred Perlstein return (sem); 215bf4dc877SAlfred Perlstein err: 216bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 217bf4dc877SAlfred Perlstein ksem_close(semid); 218bf4dc877SAlfred Perlstein if (sem != NULL) { 219bf4dc877SAlfred Perlstein if (*sem != NULL) 220bf4dc877SAlfred Perlstein sem_free(*sem); 221bf4dc877SAlfred Perlstein else 222bf4dc877SAlfred Perlstein errno = ENOSPC; 223bf4dc877SAlfred Perlstein free(sem); 224bf4dc877SAlfred Perlstein } else { 225bf4dc877SAlfred Perlstein errno = ENOSPC; 226bf4dc877SAlfred Perlstein } 227bf4dc877SAlfred Perlstein return (SEM_FAILED); 228bf4dc877SAlfred Perlstein } 229bf4dc877SAlfred Perlstein 230bf4dc877SAlfred Perlstein int 231bf4dc877SAlfred Perlstein sem_close(sem_t *sem) 232bf4dc877SAlfred Perlstein { 233bf4dc877SAlfred Perlstein 234bf4dc877SAlfred Perlstein if ((*sem)->syssem == 0) { 235bf4dc877SAlfred Perlstein errno = EINVAL; 236bf4dc877SAlfred Perlstein return (-1); 237bf4dc877SAlfred Perlstein } 238bf4dc877SAlfred Perlstein _pthread_mutex_lock(&named_sems_mtx); 239bf4dc877SAlfred Perlstein if (ksem_close((*sem)->semid) == -1) { 240bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 241bf4dc877SAlfred Perlstein return (-1); 242bf4dc877SAlfred Perlstein } 243bf4dc877SAlfred Perlstein LIST_REMOVE((*sem), entry); 244bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 245bf4dc877SAlfred Perlstein sem_free(*sem); 246bf4dc877SAlfred Perlstein free(sem); 247bf4dc877SAlfred Perlstein return (0); 248bf4dc877SAlfred Perlstein } 249bf4dc877SAlfred Perlstein 250bf4dc877SAlfred Perlstein int 251bf4dc877SAlfred Perlstein sem_unlink(const char *name) 252bf4dc877SAlfred Perlstein { 253bf4dc877SAlfred Perlstein 254bf4dc877SAlfred Perlstein return (ksem_unlink(name)); 255bf4dc877SAlfred Perlstein } 256bf4dc877SAlfred Perlstein 257b6897522SDavid Xu int 258bf4dc877SAlfred Perlstein sem_wait(sem_t *sem) 259bf4dc877SAlfred Perlstein { 260bf4dc877SAlfred Perlstein int retval; 261bf4dc877SAlfred Perlstein 262bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 263bf4dc877SAlfred Perlstein 264bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 265bf4dc877SAlfred Perlstein retval = ksem_wait((*sem)->semid); 266bf4dc877SAlfred Perlstein goto RETURN; 267bf4dc877SAlfred Perlstein } 268bf4dc877SAlfred Perlstein 269bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 270bf4dc877SAlfred Perlstein 271bf4dc877SAlfred Perlstein while ((*sem)->count == 0) { 272bf4dc877SAlfred Perlstein (*sem)->nwaiters++; 273b6897522SDavid Xu _pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); 274bf4dc877SAlfred Perlstein (*sem)->nwaiters--; 275bf4dc877SAlfred Perlstein } 276bf4dc877SAlfred Perlstein (*sem)->count--; 277bf4dc877SAlfred Perlstein 278bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 279bf4dc877SAlfred Perlstein 280bf4dc877SAlfred Perlstein retval = 0; 281bf4dc877SAlfred Perlstein RETURN: 282bf4dc877SAlfred Perlstein return retval; 283bf4dc877SAlfred Perlstein } 284bf4dc877SAlfred Perlstein 285bf4dc877SAlfred Perlstein int 286bf4dc877SAlfred Perlstein sem_trywait(sem_t *sem) 287bf4dc877SAlfred Perlstein { 288bf4dc877SAlfred Perlstein int retval; 289bf4dc877SAlfred Perlstein 290bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 291bf4dc877SAlfred Perlstein 292bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 293bf4dc877SAlfred Perlstein retval = ksem_trywait((*sem)->semid); 294bf4dc877SAlfred Perlstein goto RETURN; 295bf4dc877SAlfred Perlstein } 296bf4dc877SAlfred Perlstein 297bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 298bf4dc877SAlfred Perlstein 299bf4dc877SAlfred Perlstein if ((*sem)->count > 0) { 300bf4dc877SAlfred Perlstein (*sem)->count--; 301bf4dc877SAlfred Perlstein retval = 0; 302bf4dc877SAlfred Perlstein } else { 303bf4dc877SAlfred Perlstein errno = EAGAIN; 304bf4dc877SAlfred Perlstein retval = -1; 305bf4dc877SAlfred Perlstein } 306bf4dc877SAlfred Perlstein 307bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 308bf4dc877SAlfred Perlstein 309bf4dc877SAlfred Perlstein RETURN: 310bf4dc877SAlfred Perlstein return retval; 311bf4dc877SAlfred Perlstein } 312bf4dc877SAlfred Perlstein 313bf4dc877SAlfred Perlstein int 314bf4dc877SAlfred Perlstein sem_post(sem_t *sem) 315bf4dc877SAlfred Perlstein { 316bf4dc877SAlfred Perlstein int retval; 317bf4dc877SAlfred Perlstein 318bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 319bf4dc877SAlfred Perlstein 320bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 321bf4dc877SAlfred Perlstein retval = ksem_post((*sem)->semid); 322bf4dc877SAlfred Perlstein goto RETURN; 323bf4dc877SAlfred Perlstein } 324bf4dc877SAlfred Perlstein 325bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 326bf4dc877SAlfred Perlstein 327bf4dc877SAlfred Perlstein (*sem)->count++; 328bf4dc877SAlfred Perlstein if ((*sem)->nwaiters > 0) 329bf4dc877SAlfred Perlstein _pthread_cond_signal(&(*sem)->gtzero); 330bf4dc877SAlfred Perlstein 331bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 332bf4dc877SAlfred Perlstein 333bf4dc877SAlfred Perlstein retval = 0; 334bf4dc877SAlfred Perlstein RETURN: 335bf4dc877SAlfred Perlstein return retval; 336bf4dc877SAlfred Perlstein } 337bf4dc877SAlfred Perlstein 338bf4dc877SAlfred Perlstein int 339ddb4fb5bSMike Barcroft sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 340bf4dc877SAlfred Perlstein { 341bf4dc877SAlfred Perlstein int retval; 342bf4dc877SAlfred Perlstein 343bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 344bf4dc877SAlfred Perlstein 345bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 346bf4dc877SAlfred Perlstein retval = ksem_getvalue((*sem)->semid, sval); 347bf4dc877SAlfred Perlstein goto RETURN; 348bf4dc877SAlfred Perlstein } 349bf4dc877SAlfred Perlstein 350bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 351bf4dc877SAlfred Perlstein *sval = (int)(*sem)->count; 352bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 353bf4dc877SAlfred Perlstein 354bf4dc877SAlfred Perlstein retval = 0; 355bf4dc877SAlfred Perlstein RETURN: 356bf4dc877SAlfred Perlstein return retval; 357bf4dc877SAlfred Perlstein } 358