1 /* $NetBSD: sem.c,v 1.1 2003/01/24 01:52:44 thorpej 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 /* 69 * If an application is linked against both librt and libpthread, the 70 * libpthread versions must be used. Provide weak aliases to cause 71 * this behavior. 72 */ 73 #define sem_init _librt_sem_init 74 #define sem_destroy _librt_sem_destroy 75 #define sem_open _librt_sem_open 76 #define sem_close _librt_sem_close 77 #define sem_unlink _librt_sem_unlink 78 #define sem_wait _librt_sem_wait 79 #define sem_trywait _librt_sem_trywait 80 #define sem_post _librt_sem_post 81 #define sem_getvalue _librt_sem_getvalue 82 83 #define _LIBC /* XXX to get semid_t type */ 84 85 #include <sys/types.h> 86 #include <sys/ksem.h> 87 #include <sys/queue.h> 88 #include <stdlib.h> 89 #include <errno.h> 90 #include <fcntl.h> 91 #include <semaphore.h> 92 #include <stdarg.h> 93 94 struct _sem_st { 95 unsigned int ksem_magic; 96 #define KSEM_MAGIC 0x90af0421U 97 98 LIST_ENTRY(_sem_st) ksem_list; 99 semid_t ksem_semid; /* 0 -> user (non-shared) */ 100 sem_t *ksem_identity; 101 }; 102 103 static int sem_alloc(unsigned int value, semid_t semid, sem_t *semp); 104 static void sem_free(sem_t sem); 105 106 static LIST_HEAD(, _sem_st) named_sems = LIST_HEAD_INITIALIZER(&named_sems); 107 108 __weak_alias(sem_init,_librt_sem_init) 109 __weak_alias(sem_destroy,_librt_sem_destroy) 110 __weak_alias(sem_open,_librt_sem_open) 111 __weak_alias(sem_close,_librt_sem_close) 112 __weak_alias(sem_unlink,_librt_sem_unlink) 113 __weak_alias(sem_wait,_librt_sem_wait) 114 __weak_alias(sem_trywait,_librt_sem_trywait) 115 __weak_alias(sem_post,_librt_sem_post) 116 __weak_alias(sem_getvalue,_librt_sem_getvalue) 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, semid_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 semid_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 167 #ifdef ERRORCHECK 168 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 169 errno = EINVAL; 170 return (-1); 171 } 172 #endif 173 174 if (_ksem_destroy((*sem)->ksem_semid) == -1) 175 return (-1); 176 177 sem_free(*sem); 178 179 return (0); 180 } 181 182 sem_t * 183 sem_open(const char *name, int oflag, ...) 184 { 185 sem_t *sem, s; 186 semid_t semid; 187 mode_t mode; 188 unsigned int value; 189 int error; 190 va_list ap; 191 192 mode = 0; 193 value = 0; 194 195 if (oflag & O_CREAT) { 196 va_start(ap, oflag); 197 mode = va_arg(ap, int); 198 value = va_arg(ap, unsigned int); 199 va_end(ap); 200 } 201 202 /* 203 * We can be lazy and let the kernel handle the oflag, 204 * we'll just merge duplicate IDs into our list. 205 */ 206 if (_ksem_open(name, oflag, mode, value, &semid) == -1) 207 return (SEM_FAILED); 208 209 /* 210 * Search for a duplicate ID, we must return the same sem_t * 211 * if we locate one. 212 */ 213 LIST_FOREACH(s, &named_sems, ksem_list) { 214 if (s->ksem_semid == semid) 215 return (s->ksem_identity); 216 } 217 218 if ((sem = malloc(sizeof(*sem))) == NULL) { 219 error = ENOSPC; 220 goto bad; 221 } 222 if ((error = sem_alloc(value, semid, sem)) != 0) 223 goto bad; 224 225 LIST_INSERT_HEAD(&named_sems, *sem, ksem_list); 226 (*sem)->ksem_identity = sem; 227 228 return (sem); 229 230 bad: 231 _ksem_close(semid); 232 if (sem != NULL) { 233 if (*sem != NULL) 234 sem_free(*sem); 235 free(sem); 236 } 237 errno = error; 238 return (SEM_FAILED); 239 } 240 241 int 242 sem_close(sem_t *sem) 243 { 244 245 #ifdef ERRORCHECK 246 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 247 errno = EINVAL; 248 return (-1); 249 } 250 #endif 251 252 if (_ksem_close((*sem)->ksem_semid) == -1) 253 return (-1); 254 255 LIST_REMOVE((*sem), ksem_list); 256 sem_free(*sem); 257 free(sem); 258 return (0); 259 } 260 261 int 262 sem_unlink(const char *name) 263 { 264 265 return (_ksem_unlink(name)); 266 } 267 268 int 269 sem_wait(sem_t *sem) 270 { 271 272 #ifdef ERRORCHECK 273 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 274 errno = EINVAL; 275 return (-1); 276 } 277 #endif 278 279 return (_ksem_wait((*sem)->ksem_semid)); 280 } 281 282 int 283 sem_trywait(sem_t *sem) 284 { 285 286 #ifdef ERRORCHECK 287 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 288 errno = EINVAL; 289 return (-1); 290 } 291 #endif 292 293 return (_ksem_trywait((*sem)->ksem_semid)); 294 } 295 296 int 297 sem_post(sem_t *sem) 298 { 299 300 #ifdef ERRORCHECK 301 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 302 errno = EINVAL; 303 return (-1); 304 } 305 #endif 306 307 return (_ksem_post((*sem)->ksem_semid)); 308 } 309 310 int 311 sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 312 { 313 314 #ifdef ERRORCHECK 315 if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) { 316 errno = EINVAL; 317 return (-1); 318 } 319 #endif 320 return (_ksem_getvalue((*sem)->ksem_semid, sval)); 321 } 322