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 32bf4dc877SAlfred Perlstein #include <stdlib.h> 33bf4dc877SAlfred Perlstein #include <errno.h> 34bf4dc877SAlfred Perlstein #include <fcntl.h> 35bf4dc877SAlfred Perlstein #include <semaphore.h> 36bf4dc877SAlfred Perlstein #include <stdarg.h> 37bf4dc877SAlfred Perlstein #include <pthread.h> 38bf4dc877SAlfred Perlstein #include <sys/queue.h> 39bf4dc877SAlfred Perlstein #include <_semaphore.h> 40bf4dc877SAlfred Perlstein 41bf4dc877SAlfred Perlstein #define _SEM_CHECK_VALIDITY(sem) \ 42bf4dc877SAlfred Perlstein if ((*(sem))->magic != SEM_MAGIC) { \ 43bf4dc877SAlfred Perlstein errno = EINVAL; \ 44bf4dc877SAlfred Perlstein retval = -1; \ 45bf4dc877SAlfred Perlstein goto RETURN; \ 46bf4dc877SAlfred Perlstein } 47bf4dc877SAlfred Perlstein 48bf4dc877SAlfred Perlstein static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); 49bf4dc877SAlfred Perlstein static void sem_free(sem_t sem); 50bf4dc877SAlfred Perlstein 51bf4dc877SAlfred Perlstein static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); 52bf4dc877SAlfred Perlstein static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; 53bf4dc877SAlfred Perlstein 54bf4dc877SAlfred Perlstein static void 55bf4dc877SAlfred Perlstein sem_free(sem_t sem) 56bf4dc877SAlfred Perlstein { 57bf4dc877SAlfred Perlstein 58bf4dc877SAlfred Perlstein _pthread_mutex_destroy(&sem->lock); 59bf4dc877SAlfred Perlstein _pthread_cond_destroy(&sem->gtzero); 60bf4dc877SAlfred Perlstein sem->magic = 0; 61bf4dc877SAlfred Perlstein free(sem); 62bf4dc877SAlfred Perlstein } 63bf4dc877SAlfred Perlstein 64bf4dc877SAlfred Perlstein static sem_t 65bf4dc877SAlfred Perlstein sem_alloc(unsigned int value, semid_t semid, int system_sem) 66bf4dc877SAlfred Perlstein { 67bf4dc877SAlfred Perlstein sem_t sem; 68bf4dc877SAlfred Perlstein 69bf4dc877SAlfred Perlstein if (value > SEM_VALUE_MAX) { 70bf4dc877SAlfred Perlstein errno = EINVAL; 71bf4dc877SAlfred Perlstein return (NULL); 72bf4dc877SAlfred Perlstein } 73bf4dc877SAlfred Perlstein 74bf4dc877SAlfred Perlstein sem = (sem_t)malloc(sizeof(struct sem)); 75bf4dc877SAlfred Perlstein if (sem == NULL) { 76bf4dc877SAlfred Perlstein errno = ENOSPC; 77bf4dc877SAlfred Perlstein return (NULL); 78bf4dc877SAlfred Perlstein } 79bf4dc877SAlfred Perlstein 80bf4dc877SAlfred Perlstein /* 81bf4dc877SAlfred Perlstein * Initialize the semaphore. 82bf4dc877SAlfred Perlstein */ 83bf4dc877SAlfred Perlstein if (_pthread_mutex_init(&sem->lock, NULL) != 0) { 84bf4dc877SAlfred Perlstein free(sem); 85bf4dc877SAlfred Perlstein errno = ENOSPC; 86bf4dc877SAlfred Perlstein return (NULL); 87bf4dc877SAlfred Perlstein } 88bf4dc877SAlfred Perlstein 89bf4dc877SAlfred Perlstein if (_pthread_cond_init(&sem->gtzero, NULL) != 0) { 90bf4dc877SAlfred Perlstein _pthread_mutex_destroy(&sem->lock); 91bf4dc877SAlfred Perlstein free(sem); 92bf4dc877SAlfred Perlstein errno = ENOSPC; 93bf4dc877SAlfred Perlstein return (NULL); 94bf4dc877SAlfred Perlstein } 95bf4dc877SAlfred Perlstein 96bf4dc877SAlfred Perlstein sem->count = (u_int32_t)value; 97bf4dc877SAlfred Perlstein sem->nwaiters = 0; 98bf4dc877SAlfred Perlstein sem->magic = SEM_MAGIC; 99bf4dc877SAlfred Perlstein sem->semid = semid; 100bf4dc877SAlfred Perlstein sem->syssem = system_sem; 101bf4dc877SAlfred Perlstein return (sem); 102bf4dc877SAlfred Perlstein } 103bf4dc877SAlfred Perlstein 104bf4dc877SAlfred Perlstein int 105bf4dc877SAlfred Perlstein sem_init(sem_t *sem, int pshared, unsigned int value) 106bf4dc877SAlfred Perlstein { 107bf4dc877SAlfred Perlstein int retval, got_system_sem; 108bf4dc877SAlfred Perlstein semid_t semid; 109bf4dc877SAlfred Perlstein 110bf4dc877SAlfred Perlstein got_system_sem = 0; 111bf4dc877SAlfred Perlstein semid = SEM_USER; 112bf4dc877SAlfred Perlstein /* 113bf4dc877SAlfred Perlstein * Range check the arguments. 114bf4dc877SAlfred Perlstein */ 115bf4dc877SAlfred Perlstein if (pshared != 0) { 116bf4dc877SAlfred Perlstein retval = ksem_init(&semid, value); 117bf4dc877SAlfred Perlstein if (retval == -1) 118bf4dc877SAlfred Perlstein goto RETURN; 119bf4dc877SAlfred Perlstein got_system_sem = 1; 120bf4dc877SAlfred Perlstein } 121bf4dc877SAlfred Perlstein 122bf4dc877SAlfred Perlstein (*sem) = sem_alloc(value, semid, got_system_sem); 123bf4dc877SAlfred Perlstein if ((*sem) == NULL) 124bf4dc877SAlfred Perlstein retval = -1; 125bf4dc877SAlfred Perlstein else 126bf4dc877SAlfred Perlstein retval = 0; 127bf4dc877SAlfred Perlstein RETURN: 128bf4dc877SAlfred Perlstein if (retval != 0 && got_system_sem) 129bf4dc877SAlfred Perlstein ksem_destroy(semid); 130bf4dc877SAlfred Perlstein return retval; 131bf4dc877SAlfred Perlstein } 132bf4dc877SAlfred Perlstein 133bf4dc877SAlfred Perlstein int 134bf4dc877SAlfred Perlstein sem_destroy(sem_t *sem) 135bf4dc877SAlfred Perlstein { 136bf4dc877SAlfred Perlstein int retval; 137bf4dc877SAlfred Perlstein 138bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 139bf4dc877SAlfred Perlstein 140bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 141bf4dc877SAlfred Perlstein /* 142bf4dc877SAlfred Perlstein * If this is a system semaphore let the kernel track it otherwise 143bf4dc877SAlfred Perlstein * make sure there are no waiters. 144bf4dc877SAlfred Perlstein */ 145bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 146bf4dc877SAlfred Perlstein retval = ksem_destroy((*sem)->semid); 147bf4dc877SAlfred Perlstein if (retval == -1) { 148bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 149bf4dc877SAlfred Perlstein goto RETURN; 150bf4dc877SAlfred Perlstein } 151bf4dc877SAlfred Perlstein } else if ((*sem)->nwaiters > 0) { 152bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 153bf4dc877SAlfred Perlstein errno = EBUSY; 154bf4dc877SAlfred Perlstein retval = -1; 155bf4dc877SAlfred Perlstein goto RETURN; 156bf4dc877SAlfred Perlstein } 157bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 158bf4dc877SAlfred Perlstein 159bf4dc877SAlfred Perlstein sem_free(*sem); 160bf4dc877SAlfred Perlstein 161bf4dc877SAlfred Perlstein retval = 0; 162bf4dc877SAlfred Perlstein RETURN: 163bf4dc877SAlfred Perlstein return retval; 164bf4dc877SAlfred Perlstein } 165bf4dc877SAlfred Perlstein 166bf4dc877SAlfred Perlstein sem_t * 167bf4dc877SAlfred Perlstein sem_open(const char *name, int oflag, ...) 168bf4dc877SAlfred Perlstein { 169bf4dc877SAlfred Perlstein sem_t *sem; 170bf4dc877SAlfred Perlstein sem_t s; 171bf4dc877SAlfred Perlstein semid_t semid; 172bf4dc877SAlfred Perlstein mode_t mode; 173bf4dc877SAlfred Perlstein unsigned int value; 174bf4dc877SAlfred Perlstein 175bf4dc877SAlfred Perlstein mode = 0; 176bf4dc877SAlfred Perlstein value = 0; 177bf4dc877SAlfred Perlstein 178bf4dc877SAlfred Perlstein if ((oflag & O_CREAT) != 0) { 179bf4dc877SAlfred Perlstein va_list ap; 180bf4dc877SAlfred Perlstein 181bf4dc877SAlfred Perlstein va_start(ap, oflag); 182bf4dc877SAlfred Perlstein mode = va_arg(ap, int); 183bf4dc877SAlfred Perlstein value = va_arg(ap, unsigned int); 184bf4dc877SAlfred Perlstein va_end(ap); 185bf4dc877SAlfred Perlstein } 186bf4dc877SAlfred Perlstein /* 187bf4dc877SAlfred Perlstein * we can be lazy and let the kernel handle the "oflag", 188bf4dc877SAlfred Perlstein * we'll just merge duplicate IDs into our list. 189bf4dc877SAlfred Perlstein */ 190bf4dc877SAlfred Perlstein if (ksem_open(&semid, name, oflag, mode, value) == -1) 191bf4dc877SAlfred Perlstein return (SEM_FAILED); 192bf4dc877SAlfred Perlstein /* 193bf4dc877SAlfred Perlstein * search for a duplicate ID, we must return the same sem_t * 194bf4dc877SAlfred Perlstein * if we locate one. 195bf4dc877SAlfred Perlstein */ 196bf4dc877SAlfred Perlstein _pthread_mutex_lock(&named_sems_mtx); 197bf4dc877SAlfred Perlstein LIST_FOREACH(s, &named_sems, entry) { 198bf4dc877SAlfred Perlstein if (s->semid == semid) { 199bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 200bf4dc877SAlfred Perlstein return (s->backpointer); 201bf4dc877SAlfred Perlstein } 202bf4dc877SAlfred Perlstein } 203bf4dc877SAlfred Perlstein sem = (sem_t *)malloc(sizeof(*sem)); 204bf4dc877SAlfred Perlstein if (sem == NULL) 205bf4dc877SAlfred Perlstein goto err; 206bf4dc877SAlfred Perlstein *sem = sem_alloc(value, semid, 1); 207bf4dc877SAlfred Perlstein if ((*sem) == NULL) 208bf4dc877SAlfred Perlstein goto err; 209bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 210bf4dc877SAlfred Perlstein (*sem)->backpointer = sem; 211bf4dc877SAlfred Perlstein return (sem); 212bf4dc877SAlfred Perlstein err: 213bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 214bf4dc877SAlfred Perlstein ksem_close(semid); 215bf4dc877SAlfred Perlstein if (sem != NULL) { 216bf4dc877SAlfred Perlstein if (*sem != NULL) 217bf4dc877SAlfred Perlstein sem_free(*sem); 218bf4dc877SAlfred Perlstein else 219bf4dc877SAlfred Perlstein errno = ENOSPC; 220bf4dc877SAlfred Perlstein free(sem); 221bf4dc877SAlfred Perlstein } else { 222bf4dc877SAlfred Perlstein errno = ENOSPC; 223bf4dc877SAlfred Perlstein } 224bf4dc877SAlfred Perlstein return (SEM_FAILED); 225bf4dc877SAlfred Perlstein } 226bf4dc877SAlfred Perlstein 227bf4dc877SAlfred Perlstein int 228bf4dc877SAlfred Perlstein sem_close(sem_t *sem) 229bf4dc877SAlfred Perlstein { 230bf4dc877SAlfred Perlstein 231bf4dc877SAlfred Perlstein if ((*sem)->syssem == 0) { 232bf4dc877SAlfred Perlstein errno = EINVAL; 233bf4dc877SAlfred Perlstein return (-1); 234bf4dc877SAlfred Perlstein } 235bf4dc877SAlfred Perlstein _pthread_mutex_lock(&named_sems_mtx); 236bf4dc877SAlfred Perlstein if (ksem_close((*sem)->semid) == -1) { 237bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 238bf4dc877SAlfred Perlstein return (-1); 239bf4dc877SAlfred Perlstein } 240bf4dc877SAlfred Perlstein LIST_REMOVE((*sem), entry); 241bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 242bf4dc877SAlfred Perlstein sem_free(*sem); 243bf4dc877SAlfred Perlstein free(sem); 244bf4dc877SAlfred Perlstein return (0); 245bf4dc877SAlfred Perlstein } 246bf4dc877SAlfred Perlstein 247bf4dc877SAlfred Perlstein int 248bf4dc877SAlfred Perlstein sem_unlink(const char *name) 249bf4dc877SAlfred Perlstein { 250bf4dc877SAlfred Perlstein 251bf4dc877SAlfred Perlstein return (ksem_unlink(name)); 252bf4dc877SAlfred Perlstein } 253bf4dc877SAlfred Perlstein 254bf4dc877SAlfred Perlstein int 255bf4dc877SAlfred Perlstein sem_wait(sem_t *sem) 256bf4dc877SAlfred Perlstein { 257bf4dc877SAlfred Perlstein int retval; 258bf4dc877SAlfred Perlstein 259bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 260bf4dc877SAlfred Perlstein 261bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 262bf4dc877SAlfred Perlstein retval = ksem_wait((*sem)->semid); 263bf4dc877SAlfred Perlstein goto RETURN; 264bf4dc877SAlfred Perlstein } 265bf4dc877SAlfred Perlstein 266bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 267bf4dc877SAlfred Perlstein 268bf4dc877SAlfred Perlstein while ((*sem)->count == 0) { 269bf4dc877SAlfred Perlstein (*sem)->nwaiters++; 270bf4dc877SAlfred Perlstein _pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); 271bf4dc877SAlfred Perlstein (*sem)->nwaiters--; 272bf4dc877SAlfred Perlstein } 273bf4dc877SAlfred Perlstein (*sem)->count--; 274bf4dc877SAlfred Perlstein 275bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 276bf4dc877SAlfred Perlstein 277bf4dc877SAlfred Perlstein retval = 0; 278bf4dc877SAlfred Perlstein RETURN: 279bf4dc877SAlfred Perlstein return retval; 280bf4dc877SAlfred Perlstein } 281bf4dc877SAlfred Perlstein 282bf4dc877SAlfred Perlstein int 283bf4dc877SAlfred Perlstein sem_trywait(sem_t *sem) 284bf4dc877SAlfred Perlstein { 285bf4dc877SAlfred Perlstein int retval; 286bf4dc877SAlfred Perlstein 287bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 288bf4dc877SAlfred Perlstein 289bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 290bf4dc877SAlfred Perlstein retval = ksem_trywait((*sem)->semid); 291bf4dc877SAlfred Perlstein goto RETURN; 292bf4dc877SAlfred Perlstein } 293bf4dc877SAlfred Perlstein 294bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 295bf4dc877SAlfred Perlstein 296bf4dc877SAlfred Perlstein if ((*sem)->count > 0) { 297bf4dc877SAlfred Perlstein (*sem)->count--; 298bf4dc877SAlfred Perlstein retval = 0; 299bf4dc877SAlfred Perlstein } else { 300bf4dc877SAlfred Perlstein errno = EAGAIN; 301bf4dc877SAlfred Perlstein retval = -1; 302bf4dc877SAlfred Perlstein } 303bf4dc877SAlfred Perlstein 304bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 305bf4dc877SAlfred Perlstein 306bf4dc877SAlfred Perlstein RETURN: 307bf4dc877SAlfred Perlstein return retval; 308bf4dc877SAlfred Perlstein } 309bf4dc877SAlfred Perlstein 310bf4dc877SAlfred Perlstein int 311bf4dc877SAlfred Perlstein sem_post(sem_t *sem) 312bf4dc877SAlfred Perlstein { 313bf4dc877SAlfred Perlstein int retval; 314bf4dc877SAlfred Perlstein 315bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 316bf4dc877SAlfred Perlstein 317bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 318bf4dc877SAlfred Perlstein retval = ksem_post((*sem)->semid); 319bf4dc877SAlfred Perlstein goto RETURN; 320bf4dc877SAlfred Perlstein } 321bf4dc877SAlfred Perlstein 322bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 323bf4dc877SAlfred Perlstein 324bf4dc877SAlfred Perlstein (*sem)->count++; 325bf4dc877SAlfred Perlstein if ((*sem)->nwaiters > 0) 326bf4dc877SAlfred Perlstein _pthread_cond_signal(&(*sem)->gtzero); 327bf4dc877SAlfred Perlstein 328bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 329bf4dc877SAlfred Perlstein 330bf4dc877SAlfred Perlstein retval = 0; 331bf4dc877SAlfred Perlstein RETURN: 332bf4dc877SAlfred Perlstein return retval; 333bf4dc877SAlfred Perlstein } 334bf4dc877SAlfred Perlstein 335bf4dc877SAlfred Perlstein int 336ddb4fb5bSMike Barcroft sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 337bf4dc877SAlfred Perlstein { 338bf4dc877SAlfred Perlstein int retval; 339bf4dc877SAlfred Perlstein 340bf4dc877SAlfred Perlstein _SEM_CHECK_VALIDITY(sem); 341bf4dc877SAlfred Perlstein 342bf4dc877SAlfred Perlstein if ((*sem)->syssem != 0) { 343bf4dc877SAlfred Perlstein retval = ksem_getvalue((*sem)->semid, sval); 344bf4dc877SAlfred Perlstein goto RETURN; 345bf4dc877SAlfred Perlstein } 346bf4dc877SAlfred Perlstein 347bf4dc877SAlfred Perlstein _pthread_mutex_lock(&(*sem)->lock); 348bf4dc877SAlfred Perlstein *sval = (int)(*sem)->count; 349bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&(*sem)->lock); 350bf4dc877SAlfred Perlstein 351bf4dc877SAlfred Perlstein retval = 0; 352bf4dc877SAlfred Perlstein RETURN: 353bf4dc877SAlfred Perlstein return retval; 354bf4dc877SAlfred Perlstein } 355