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