1 /* $NetBSD: sem.c,v 1.7 2012/03/10 19:59:21 joerg 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.7 2012/03/10 19:59:21 joerg 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_timedwait _librt_sem_timedwait 76 #define sem_trywait _librt_sem_trywait 77 #define sem_post _librt_sem_post 78 #define sem_getvalue _librt_sem_getvalue 79 80 #define _LIBC 81 82 #include <sys/types.h> 83 #include <sys/ksem.h> 84 #include <sys/queue.h> 85 #include <stdlib.h> 86 #include <errno.h> 87 #include <fcntl.h> 88 #include <semaphore.h> 89 #include <stdarg.h> 90 91 struct _sem_st { 92 unsigned int ksem_magic; 93 #define KSEM_MAGIC 0x90af0421U 94 95 LIST_ENTRY(_sem_st) ksem_list; 96 intptr_t ksem_semid; /* 0 -> user (non-shared) */ 97 sem_t *ksem_identity; 98 }; 99 100 static int sem_alloc(unsigned int value, intptr_t semid, sem_t *semp); 101 static void sem_free(sem_t sem); 102 103 static LIST_HEAD(, _sem_st) named_sems = LIST_HEAD_INITIALIZER(&named_sems); 104 105 #ifdef __weak_alias 106 __weak_alias(sem_init,_librt_sem_init) 107 __weak_alias(sem_destroy,_librt_sem_destroy) 108 __weak_alias(sem_open,_librt_sem_open) 109 __weak_alias(sem_close,_librt_sem_close) 110 __weak_alias(sem_unlink,_librt_sem_unlink) 111 __weak_alias(sem_wait,_librt_sem_wait) 112 __weak_alias(sem_timedwait,_librt_sem_timedwait) 113 __weak_alias(sem_trywait,_librt_sem_trywait) 114 __weak_alias(sem_post,_librt_sem_post) 115 __weak_alias(sem_getvalue,_librt_sem_getvalue) 116 #endif 117 118 static void 119 sem_free(sem_t sem) 120 { 121 122 sem->ksem_magic = 0; 123 free(sem); 124 } 125 126 static int 127 sem_alloc(unsigned int value, intptr_t semid, sem_t *semp) 128 { 129 sem_t sem; 130 131 if (value > SEM_VALUE_MAX) 132 return (EINVAL); 133 134 if ((sem = malloc(sizeof(struct _sem_st))) == NULL) 135 return (ENOSPC); 136 137 sem->ksem_magic = KSEM_MAGIC; 138 sem->ksem_semid = semid; 139 140 *semp = sem; 141 return (0); 142 } 143 144 /* ARGSUSED */ 145 int 146 sem_init(sem_t *sem, int pshared, unsigned int value) 147 { 148 intptr_t semid; 149 int error; 150 151 if (_ksem_init(value, &semid) == -1) 152 return (-1); 153 154 if ((error = sem_alloc(value, semid, sem)) != 0) { 155 _ksem_destroy(semid); 156 errno = error; 157 return (-1); 158 } 159 160 return (0); 161 } 162 163 int 164 sem_destroy(sem_t *sem) 165 { 166 int error, save_errno; 167 168 #ifdef ERRORCHECK 169 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 170 errno = EINVAL; 171 return (-1); 172 } 173 #endif 174 175 error = _ksem_destroy((*sem)->ksem_semid); 176 save_errno = errno; 177 sem_free(*sem); 178 errno = save_errno; 179 180 return error; 181 } 182 183 sem_t * 184 sem_open(const char *name, int oflag, ...) 185 { 186 sem_t *sem, s; 187 intptr_t semid; 188 mode_t mode; 189 unsigned int value; 190 int error; 191 va_list ap; 192 193 mode = 0; 194 value = 0; 195 196 if (oflag & O_CREAT) { 197 va_start(ap, oflag); 198 mode = va_arg(ap, int); 199 value = va_arg(ap, unsigned int); 200 va_end(ap); 201 } 202 203 /* 204 * We can be lazy and let the kernel handle the oflag, 205 * we'll just merge duplicate IDs into our list. 206 */ 207 if (_ksem_open(name, oflag, mode, value, &semid) == -1) 208 return (SEM_FAILED); 209 210 /* 211 * Search for a duplicate ID, we must return the same sem_t * 212 * if we locate one. 213 */ 214 LIST_FOREACH(s, &named_sems, ksem_list) { 215 if (s->ksem_semid == semid) 216 return (s->ksem_identity); 217 } 218 219 if ((sem = malloc(sizeof(*sem))) == NULL) { 220 error = ENOSPC; 221 goto bad; 222 } 223 if ((error = sem_alloc(value, semid, sem)) != 0) 224 goto bad; 225 226 LIST_INSERT_HEAD(&named_sems, *sem, ksem_list); 227 (*sem)->ksem_identity = sem; 228 229 return (sem); 230 231 bad: 232 _ksem_close(semid); 233 if (sem != NULL) { 234 if (*sem != NULL) 235 sem_free(*sem); 236 free(sem); 237 } 238 errno = error; 239 return (SEM_FAILED); 240 } 241 242 int 243 sem_close(sem_t *sem) 244 { 245 int error, save_errno; 246 247 #ifdef ERRORCHECK 248 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 249 errno = EINVAL; 250 return (-1); 251 } 252 #endif 253 254 error = _ksem_close((*sem)->ksem_semid); 255 256 LIST_REMOVE((*sem), ksem_list); 257 save_errno = errno; 258 sem_free(*sem); 259 free(sem); 260 errno = save_errno; 261 return error; 262 } 263 264 int 265 sem_unlink(const char *name) 266 { 267 268 return (_ksem_unlink(name)); 269 } 270 271 int 272 sem_wait(sem_t *sem) 273 { 274 275 #ifdef ERRORCHECK 276 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 277 errno = EINVAL; 278 return (-1); 279 } 280 #endif 281 282 return (_ksem_wait((*sem)->ksem_semid)); 283 } 284 285 int 286 sem_timedwait(sem_t *sem, const struct timespec * __restrict abstime) 287 { 288 289 #ifdef ERRORCHECK 290 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 291 errno = EINVAL; 292 return (-1); 293 } 294 #endif 295 296 return (_ksem_timedwait((*sem)->ksem_semid, abstime)); 297 } 298 299 int 300 sem_trywait(sem_t *sem) 301 { 302 303 #ifdef ERRORCHECK 304 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 305 errno = EINVAL; 306 return (-1); 307 } 308 #endif 309 310 return (_ksem_trywait((*sem)->ksem_semid)); 311 } 312 313 int 314 sem_post(sem_t *sem) 315 { 316 317 #ifdef ERRORCHECK 318 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 319 errno = EINVAL; 320 return (-1); 321 } 322 #endif 323 324 return (_ksem_post((*sem)->ksem_semid)); 325 } 326 327 int 328 sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 329 { 330 331 #ifdef ERRORCHECK 332 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 333 errno = EINVAL; 334 return (-1); 335 } 336 #endif 337 return (_ksem_getvalue((*sem)->ksem_semid, sval)); 338 } 339