1/* 2 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice(s), this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified other than the possible 11 * addition of one or more copyright notices. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice(s), this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 *
| 1/* 2 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice(s), this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified other than the possible 11 * addition of one or more copyright notices. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice(s), this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 *
|
60#include <sys/queue.h> 61#include <errno.h> 62#include <fcntl.h> 63#include <pthread.h> 64#include <semaphore.h> 65#include <stdarg.h> 66#include <stdlib.h> 67#include <time.h> 68#include <_semaphore.h> 69#include "un-namespace.h" 70#include "libc_private.h" 71 72static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); 73static void sem_free(sem_t sem); 74 75static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); 76static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; 77 78__weak_reference(__sem_init, sem_init); 79__weak_reference(__sem_destroy, sem_destroy); 80__weak_reference(__sem_open, sem_open); 81__weak_reference(__sem_close, sem_close); 82__weak_reference(__sem_unlink, sem_unlink); 83__weak_reference(__sem_wait, sem_wait); 84__weak_reference(__sem_trywait, sem_trywait); 85__weak_reference(__sem_timedwait, sem_timedwait); 86__weak_reference(__sem_post, sem_post); 87__weak_reference(__sem_getvalue, sem_getvalue); 88 89 90static inline int 91sem_check_validity(sem_t *sem) 92{ 93 94 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) 95 return (0); 96 else { 97 errno = EINVAL; 98 return (-1); 99 } 100} 101 102static void 103sem_free(sem_t sem) 104{ 105 106 _pthread_mutex_destroy(&sem->lock); 107 _pthread_cond_destroy(&sem->gtzero); 108 sem->magic = 0; 109 free(sem); 110} 111 112static sem_t 113sem_alloc(unsigned int value, semid_t semid, int system_sem) 114{ 115 sem_t sem; 116 117 if (value > SEM_VALUE_MAX) { 118 errno = EINVAL; 119 return (NULL); 120 } 121 122 sem = (sem_t)malloc(sizeof(struct sem)); 123 if (sem == NULL) { 124 errno = ENOSPC; 125 return (NULL); 126 } 127 128 sem->count = (u_int32_t)value; 129 sem->nwaiters = 0; 130 sem->magic = SEM_MAGIC; 131 sem->semid = semid; 132 sem->syssem = system_sem; 133 sem->lock = PTHREAD_MUTEX_INITIALIZER; 134 sem->gtzero = PTHREAD_COND_INITIALIZER; 135 return (sem); 136} 137 138int 139__sem_init(sem_t *sem, int pshared, unsigned int value) 140{ 141 semid_t semid; 142 143 /* 144 * We always have to create the kernel semaphore if the 145 * threads library isn't present since libc's version of 146 * pthread_cond_wait() is just a stub that doesn't really 147 * wait. 148 */ 149 if (ksem_init(&semid, value) != 0) 150 return (-1); 151 152 (*sem) = sem_alloc(value, semid, 1); 153 if ((*sem) == NULL) { 154 ksem_destroy(semid); 155 return (-1); 156 } 157 return (0); 158} 159 160int 161__sem_destroy(sem_t *sem) 162{ 163 int retval; 164 165 if (sem_check_validity(sem) != 0) 166 return (-1); 167 168 _pthread_mutex_lock(&(*sem)->lock); 169 /* 170 * If this is a system semaphore let the kernel track it otherwise 171 * make sure there are no waiters. 172 */ 173 if ((*sem)->syssem != 0) 174 retval = ksem_destroy((*sem)->semid); 175 else if ((*sem)->nwaiters > 0) { 176 errno = EBUSY; 177 retval = -1; 178 } 179 else { 180 retval = 0; 181 (*sem)->magic = 0; 182 } 183 _pthread_mutex_unlock(&(*sem)->lock); 184 185 if (retval == 0) { 186 _pthread_mutex_destroy(&(*sem)->lock); 187 _pthread_cond_destroy(&(*sem)->gtzero); 188 sem_free(*sem); 189 } 190 return (retval); 191} 192 193sem_t * 194__sem_open(const char *name, int oflag, ...) 195{ 196 sem_t *sem; 197 sem_t s; 198 semid_t semid; 199 mode_t mode; 200 unsigned int value; 201 202 mode = 0; 203 value = 0; 204 205 if ((oflag & O_CREAT) != 0) { 206 va_list ap; 207 208 va_start(ap, oflag); 209 mode = va_arg(ap, int); 210 value = va_arg(ap, unsigned int); 211 va_end(ap); 212 } 213 /* 214 * we can be lazy and let the kernel handle the "oflag", 215 * we'll just merge duplicate IDs into our list. 216 */ 217 if (ksem_open(&semid, name, oflag, mode, value) == -1) 218 return (SEM_FAILED); 219 /* 220 * search for a duplicate ID, we must return the same sem_t * 221 * if we locate one. 222 */ 223 _pthread_mutex_lock(&named_sems_mtx); 224 LIST_FOREACH(s, &named_sems, entry) { 225 if (s->semid == semid) { 226 sem = s->backpointer; 227 _pthread_mutex_unlock(&named_sems_mtx); 228 return (sem); 229 } 230 } 231 sem = (sem_t *)malloc(sizeof(*sem)); 232 if (sem == NULL) 233 goto err; 234 *sem = sem_alloc(value, semid, 1); 235 if ((*sem) == NULL) 236 goto err; 237 LIST_INSERT_HEAD(&named_sems, *sem, entry); 238 (*sem)->backpointer = sem; 239 _pthread_mutex_unlock(&named_sems_mtx); 240 return (sem); 241err: 242 _pthread_mutex_unlock(&named_sems_mtx); 243 ksem_close(semid); 244 if (sem != NULL) { 245 if (*sem != NULL) 246 sem_free(*sem); 247 else 248 errno = ENOSPC; 249 free(sem); 250 } else { 251 errno = ENOSPC; 252 } 253 return (SEM_FAILED); 254} 255 256int 257__sem_close(sem_t *sem) 258{ 259 260 if (sem_check_validity(sem) != 0) 261 return (-1); 262 263 if ((*sem)->syssem == 0) { 264 errno = EINVAL; 265 return (-1); 266 } 267 268 _pthread_mutex_lock(&named_sems_mtx); 269 if (ksem_close((*sem)->semid) != 0) { 270 _pthread_mutex_unlock(&named_sems_mtx); 271 return (-1); 272 } 273 LIST_REMOVE((*sem), entry); 274 _pthread_mutex_unlock(&named_sems_mtx); 275 sem_free(*sem); 276 *sem = NULL; 277 free(sem); 278 return (0); 279} 280 281int 282__sem_unlink(const char *name) 283{ 284 285 return (ksem_unlink(name)); 286} 287 288int 289__sem_wait(sem_t *sem) 290{ 291 292 if (sem_check_validity(sem) != 0) 293 return (-1); 294 295 return (ksem_wait((*sem)->semid)); 296} 297 298int 299__sem_trywait(sem_t *sem) 300{ 301 int retval; 302 303 if (sem_check_validity(sem) != 0) 304 return (-1); 305 306 if ((*sem)->syssem != 0) 307 retval = ksem_trywait((*sem)->semid); 308 else { 309 _pthread_mutex_lock(&(*sem)->lock); 310 if ((*sem)->count > 0) { 311 (*sem)->count--; 312 retval = 0; 313 } else { 314 errno = EAGAIN; 315 retval = -1; 316 } 317 _pthread_mutex_unlock(&(*sem)->lock); 318 } 319 return (retval); 320} 321 322int 323__sem_timedwait(sem_t * __restrict sem, 324 struct timespec * __restrict abs_timeout) 325{ 326 if (sem_check_validity(sem) != 0) 327 return (-1); 328 329 return (ksem_timedwait((*sem)->semid, abs_timeout)); 330} 331 332int 333__sem_post(sem_t *sem) 334{ 335 336 if (sem_check_validity(sem) != 0) 337 return (-1); 338 339 return (ksem_post((*sem)->semid)); 340} 341 342int 343__sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 344{ 345 int retval; 346 347 if (sem_check_validity(sem) != 0) 348 return (-1); 349 350 if ((*sem)->syssem != 0) 351 retval = ksem_getvalue((*sem)->semid, sval); 352 else { 353 _pthread_mutex_lock(&(*sem)->lock); 354 *sval = (int)(*sem)->count; 355 _pthread_mutex_unlock(&(*sem)->lock); 356 357 retval = 0; 358 } 359 return (retval); 360}
| 61#include <sys/queue.h> 62#include <errno.h> 63#include <fcntl.h> 64#include <pthread.h> 65#include <semaphore.h> 66#include <stdarg.h> 67#include <stdlib.h> 68#include <time.h> 69#include <_semaphore.h> 70#include "un-namespace.h" 71#include "libc_private.h" 72 73static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); 74static void sem_free(sem_t sem); 75 76static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); 77static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; 78 79__weak_reference(__sem_init, sem_init); 80__weak_reference(__sem_destroy, sem_destroy); 81__weak_reference(__sem_open, sem_open); 82__weak_reference(__sem_close, sem_close); 83__weak_reference(__sem_unlink, sem_unlink); 84__weak_reference(__sem_wait, sem_wait); 85__weak_reference(__sem_trywait, sem_trywait); 86__weak_reference(__sem_timedwait, sem_timedwait); 87__weak_reference(__sem_post, sem_post); 88__weak_reference(__sem_getvalue, sem_getvalue); 89 90 91static inline int 92sem_check_validity(sem_t *sem) 93{ 94 95 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) 96 return (0); 97 else { 98 errno = EINVAL; 99 return (-1); 100 } 101} 102 103static void 104sem_free(sem_t sem) 105{ 106 107 _pthread_mutex_destroy(&sem->lock); 108 _pthread_cond_destroy(&sem->gtzero); 109 sem->magic = 0; 110 free(sem); 111} 112 113static sem_t 114sem_alloc(unsigned int value, semid_t semid, int system_sem) 115{ 116 sem_t sem; 117 118 if (value > SEM_VALUE_MAX) { 119 errno = EINVAL; 120 return (NULL); 121 } 122 123 sem = (sem_t)malloc(sizeof(struct sem)); 124 if (sem == NULL) { 125 errno = ENOSPC; 126 return (NULL); 127 } 128 129 sem->count = (u_int32_t)value; 130 sem->nwaiters = 0; 131 sem->magic = SEM_MAGIC; 132 sem->semid = semid; 133 sem->syssem = system_sem; 134 sem->lock = PTHREAD_MUTEX_INITIALIZER; 135 sem->gtzero = PTHREAD_COND_INITIALIZER; 136 return (sem); 137} 138 139int 140__sem_init(sem_t *sem, int pshared, unsigned int value) 141{ 142 semid_t semid; 143 144 /* 145 * We always have to create the kernel semaphore if the 146 * threads library isn't present since libc's version of 147 * pthread_cond_wait() is just a stub that doesn't really 148 * wait. 149 */ 150 if (ksem_init(&semid, value) != 0) 151 return (-1); 152 153 (*sem) = sem_alloc(value, semid, 1); 154 if ((*sem) == NULL) { 155 ksem_destroy(semid); 156 return (-1); 157 } 158 return (0); 159} 160 161int 162__sem_destroy(sem_t *sem) 163{ 164 int retval; 165 166 if (sem_check_validity(sem) != 0) 167 return (-1); 168 169 _pthread_mutex_lock(&(*sem)->lock); 170 /* 171 * If this is a system semaphore let the kernel track it otherwise 172 * make sure there are no waiters. 173 */ 174 if ((*sem)->syssem != 0) 175 retval = ksem_destroy((*sem)->semid); 176 else if ((*sem)->nwaiters > 0) { 177 errno = EBUSY; 178 retval = -1; 179 } 180 else { 181 retval = 0; 182 (*sem)->magic = 0; 183 } 184 _pthread_mutex_unlock(&(*sem)->lock); 185 186 if (retval == 0) { 187 _pthread_mutex_destroy(&(*sem)->lock); 188 _pthread_cond_destroy(&(*sem)->gtzero); 189 sem_free(*sem); 190 } 191 return (retval); 192} 193 194sem_t * 195__sem_open(const char *name, int oflag, ...) 196{ 197 sem_t *sem; 198 sem_t s; 199 semid_t semid; 200 mode_t mode; 201 unsigned int value; 202 203 mode = 0; 204 value = 0; 205 206 if ((oflag & O_CREAT) != 0) { 207 va_list ap; 208 209 va_start(ap, oflag); 210 mode = va_arg(ap, int); 211 value = va_arg(ap, unsigned int); 212 va_end(ap); 213 } 214 /* 215 * we can be lazy and let the kernel handle the "oflag", 216 * we'll just merge duplicate IDs into our list. 217 */ 218 if (ksem_open(&semid, name, oflag, mode, value) == -1) 219 return (SEM_FAILED); 220 /* 221 * search for a duplicate ID, we must return the same sem_t * 222 * if we locate one. 223 */ 224 _pthread_mutex_lock(&named_sems_mtx); 225 LIST_FOREACH(s, &named_sems, entry) { 226 if (s->semid == semid) { 227 sem = s->backpointer; 228 _pthread_mutex_unlock(&named_sems_mtx); 229 return (sem); 230 } 231 } 232 sem = (sem_t *)malloc(sizeof(*sem)); 233 if (sem == NULL) 234 goto err; 235 *sem = sem_alloc(value, semid, 1); 236 if ((*sem) == NULL) 237 goto err; 238 LIST_INSERT_HEAD(&named_sems, *sem, entry); 239 (*sem)->backpointer = sem; 240 _pthread_mutex_unlock(&named_sems_mtx); 241 return (sem); 242err: 243 _pthread_mutex_unlock(&named_sems_mtx); 244 ksem_close(semid); 245 if (sem != NULL) { 246 if (*sem != NULL) 247 sem_free(*sem); 248 else 249 errno = ENOSPC; 250 free(sem); 251 } else { 252 errno = ENOSPC; 253 } 254 return (SEM_FAILED); 255} 256 257int 258__sem_close(sem_t *sem) 259{ 260 261 if (sem_check_validity(sem) != 0) 262 return (-1); 263 264 if ((*sem)->syssem == 0) { 265 errno = EINVAL; 266 return (-1); 267 } 268 269 _pthread_mutex_lock(&named_sems_mtx); 270 if (ksem_close((*sem)->semid) != 0) { 271 _pthread_mutex_unlock(&named_sems_mtx); 272 return (-1); 273 } 274 LIST_REMOVE((*sem), entry); 275 _pthread_mutex_unlock(&named_sems_mtx); 276 sem_free(*sem); 277 *sem = NULL; 278 free(sem); 279 return (0); 280} 281 282int 283__sem_unlink(const char *name) 284{ 285 286 return (ksem_unlink(name)); 287} 288 289int 290__sem_wait(sem_t *sem) 291{ 292 293 if (sem_check_validity(sem) != 0) 294 return (-1); 295 296 return (ksem_wait((*sem)->semid)); 297} 298 299int 300__sem_trywait(sem_t *sem) 301{ 302 int retval; 303 304 if (sem_check_validity(sem) != 0) 305 return (-1); 306 307 if ((*sem)->syssem != 0) 308 retval = ksem_trywait((*sem)->semid); 309 else { 310 _pthread_mutex_lock(&(*sem)->lock); 311 if ((*sem)->count > 0) { 312 (*sem)->count--; 313 retval = 0; 314 } else { 315 errno = EAGAIN; 316 retval = -1; 317 } 318 _pthread_mutex_unlock(&(*sem)->lock); 319 } 320 return (retval); 321} 322 323int 324__sem_timedwait(sem_t * __restrict sem, 325 struct timespec * __restrict abs_timeout) 326{ 327 if (sem_check_validity(sem) != 0) 328 return (-1); 329 330 return (ksem_timedwait((*sem)->semid, abs_timeout)); 331} 332 333int 334__sem_post(sem_t *sem) 335{ 336 337 if (sem_check_validity(sem) != 0) 338 return (-1); 339 340 return (ksem_post((*sem)->semid)); 341} 342 343int 344__sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 345{ 346 int retval; 347 348 if (sem_check_validity(sem) != 0) 349 return (-1); 350 351 if ((*sem)->syssem != 0) 352 retval = ksem_getvalue((*sem)->semid, sval); 353 else { 354 _pthread_mutex_lock(&(*sem)->lock); 355 *sval = (int)(*sem)->count; 356 _pthread_mutex_unlock(&(*sem)->lock); 357 358 retval = 0; 359 } 360 return (retval); 361}
|