1/* $NetBSD: sem.c,v 1.4 2008/04/28 20:23:02 martin Exp $ */ 2 3/*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice(s), this list of conditions and the following disclaimer as 41 * the first lines of this file unmodified other than the possible 42 * addition of one or more copyright notices. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice(s), this list of conditions and the following disclaimer in 45 * the documentation and/or other materials provided with the 46 * distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 49 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 52 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 55 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 56 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 57 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 58 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 */ 60 61#include <sys/cdefs.h> 62__RCSID("$NetBSD: sem.c,v 1.4 2008/04/28 20:23:02 martin Exp $"); 63 64/* 65 * If an application is linked against both librt and libpthread, the 66 * libpthread versions must be used. Provide weak aliases to cause 67 * this behavior. 68 */ 69#define sem_init _librt_sem_init 70#define sem_destroy _librt_sem_destroy 71#define sem_open _librt_sem_open 72#define sem_close _librt_sem_close 73#define sem_unlink _librt_sem_unlink 74#define sem_wait _librt_sem_wait 75#define sem_trywait _librt_sem_trywait 76#define sem_post _librt_sem_post 77#define sem_getvalue _librt_sem_getvalue 78 79#define _LIBC 80 81#include <sys/types.h> 82#include <sys/ksem.h> 83#include <sys/queue.h> 84#include <stdlib.h> 85#include <errno.h> 86#include <fcntl.h> 87#include <semaphore.h> 88#include <stdarg.h> 89 90struct _sem_st { 91 unsigned int ksem_magic; 92#define KSEM_MAGIC 0x90af0421U 93 94 LIST_ENTRY(_sem_st) ksem_list; 95 intptr_t ksem_semid; /* 0 -> user (non-shared) */ 96 sem_t *ksem_identity; 97}; 98 99static int sem_alloc(unsigned int value, intptr_t semid, sem_t *semp); 100static void sem_free(sem_t sem); 101 102static LIST_HEAD(, _sem_st) named_sems = LIST_HEAD_INITIALIZER(&named_sems); 103 104#ifdef __weak_alias 105__weak_alias(sem_init,_librt_sem_init) 106__weak_alias(sem_destroy,_librt_sem_destroy) 107__weak_alias(sem_open,_librt_sem_open) 108__weak_alias(sem_close,_librt_sem_close) 109__weak_alias(sem_unlink,_librt_sem_unlink) 110__weak_alias(sem_wait,_librt_sem_wait) 111__weak_alias(sem_trywait,_librt_sem_trywait) 112__weak_alias(sem_post,_librt_sem_post) 113__weak_alias(sem_getvalue,_librt_sem_getvalue) 114#endif 115 116static void 117sem_free(sem_t sem) 118{ 119 120 sem->ksem_magic = 0; 121 free(sem); 122} 123 124static int 125sem_alloc(unsigned int value, intptr_t semid, sem_t *semp) 126{ 127 sem_t sem; 128 129 if (value > SEM_VALUE_MAX) 130 return (EINVAL); 131 132 if ((sem = malloc(sizeof(struct _sem_st))) == NULL) 133 return (ENOSPC); 134 135 sem->ksem_magic = KSEM_MAGIC; 136 sem->ksem_semid = semid; 137 138 *semp = sem; 139 return (0); 140} 141 142/* ARGSUSED */ 143int 144sem_init(sem_t *sem, int pshared, unsigned int value) 145{ 146 intptr_t semid; 147 int error; 148 149 if (_ksem_init(value, &semid) == -1) 150 return (-1); 151 152 if ((error = sem_alloc(value, semid, sem)) != 0) { 153 _ksem_destroy(semid); 154 errno = error; 155 return (-1); 156 } 157 158 return (0); 159} 160 161int 162sem_destroy(sem_t *sem) 163{ 164 165#ifdef ERRORCHECK 166 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 167 errno = EINVAL; 168 return (-1); 169 } 170#endif 171 172 if (_ksem_destroy((*sem)->ksem_semid) == -1) 173 return (-1); 174 175 sem_free(*sem); 176 177 return (0); 178} 179 180sem_t * 181sem_open(const char *name, int oflag, ...) 182{ 183 sem_t *sem, s; 184 intptr_t semid; 185 mode_t mode; 186 unsigned int value; 187 int error; 188 va_list ap; 189 190 mode = 0; 191 value = 0; 192 193 if (oflag & O_CREAT) { 194 va_start(ap, oflag); 195 mode = va_arg(ap, int); 196 value = va_arg(ap, unsigned int); 197 va_end(ap); 198 } 199 200 /* 201 * We can be lazy and let the kernel handle the oflag, 202 * we'll just merge duplicate IDs into our list. 203 */ 204 if (_ksem_open(name, oflag, mode, value, &semid) == -1) 205 return (SEM_FAILED); 206 207 /* 208 * Search for a duplicate ID, we must return the same sem_t * 209 * if we locate one. 210 */ 211 LIST_FOREACH(s, &named_sems, ksem_list) { 212 if (s->ksem_semid == semid) 213 return (s->ksem_identity); 214 } 215 216 if ((sem = malloc(sizeof(*sem))) == NULL) { 217 error = ENOSPC; 218 goto bad; 219 } 220 if ((error = sem_alloc(value, semid, sem)) != 0) 221 goto bad; 222 223 LIST_INSERT_HEAD(&named_sems, *sem, ksem_list); 224 (*sem)->ksem_identity = sem; 225 226 return (sem); 227 228 bad: 229 _ksem_close(semid); 230 if (sem != NULL) { 231 if (*sem != NULL) 232 sem_free(*sem); 233 free(sem); 234 } 235 errno = error; 236 return (SEM_FAILED); 237} 238 239int 240sem_close(sem_t *sem) 241{ 242 243#ifdef ERRORCHECK 244 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 245 errno = EINVAL; 246 return (-1); 247 } 248#endif 249 250 if (_ksem_close((*sem)->ksem_semid) == -1) 251 return (-1); 252 253 LIST_REMOVE((*sem), ksem_list); 254 sem_free(*sem); 255 free(sem); 256 return (0); 257} 258 259int 260sem_unlink(const char *name) 261{ 262 263 return (_ksem_unlink(name)); 264} 265 266int 267sem_wait(sem_t *sem) 268{ 269 270#ifdef ERRORCHECK 271 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 272 errno = EINVAL; 273 return (-1); 274 } 275#endif 276 277 return (_ksem_wait((*sem)->ksem_semid)); 278} 279 280int 281sem_trywait(sem_t *sem) 282{ 283 284#ifdef ERRORCHECK 285 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 286 errno = EINVAL; 287 return (-1); 288 } 289#endif 290 291 return (_ksem_trywait((*sem)->ksem_semid)); 292} 293 294int 295sem_post(sem_t *sem) 296{ 297 298#ifdef ERRORCHECK 299 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 300 errno = EINVAL; 301 return (-1); 302 } 303#endif 304 305 return (_ksem_post((*sem)->ksem_semid)); 306} 307 308int 309sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 310{ 311 312#ifdef ERRORCHECK 313 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 314 errno = EINVAL; 315 return (-1); 316 } 317#endif 318 return (_ksem_getvalue((*sem)->ksem_semid, sval)); 319} 320