thr_sem.c revision 125408
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 * 29 * $FreeBSD: head/lib/libthr/thread/thr_sem.c 125408 2004-02-03 22:30:01Z deischen $ 30 */ 31 32#include <stdlib.h> 33#include <errno.h> 34#include <semaphore.h> 35#include <pthread.h> 36#include "thr_private.h" 37 38#define _SEM_CHECK_VALIDITY(sem) \ 39 if ((*(sem))->magic != SEM_MAGIC) { \ 40 errno = EINVAL; \ 41 retval = -1; \ 42 goto RETURN; \ 43 } 44 45__weak_reference(_sem_init, sem_init); 46__weak_reference(_sem_destroy, sem_destroy); 47__weak_reference(_sem_open, sem_open); 48__weak_reference(_sem_close, sem_close); 49__weak_reference(_sem_unlink, sem_unlink); 50__weak_reference(_sem_wait, sem_wait); 51__weak_reference(_sem_trywait, sem_trywait); 52__weak_reference(_sem_post, sem_post); 53__weak_reference(_sem_getvalue, sem_getvalue); 54 55 56int 57_sem_init(sem_t *sem, int pshared, unsigned int value) 58{ 59 int retval; 60 61 /* 62 * Range check the arguments. 63 */ 64 if (pshared != 0) { 65 /* 66 * The user wants a semaphore that can be shared among 67 * processes, which this implementation can't do. Sounds like a 68 * permissions problem to me (yeah right). 69 */ 70 errno = EPERM; 71 retval = -1; 72 goto RETURN; 73 } 74 75 if (value > SEM_VALUE_MAX) { 76 errno = EINVAL; 77 retval = -1; 78 goto RETURN; 79 } 80 81 *sem = (sem_t)malloc(sizeof(struct sem)); 82 if (*sem == NULL) { 83 errno = ENOSPC; 84 retval = -1; 85 goto RETURN; 86 } 87 88 /* 89 * Initialize the semaphore. 90 */ 91 if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) { 92 free(*sem); 93 errno = ENOSPC; 94 retval = -1; 95 goto RETURN; 96 } 97 98 if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) { 99 pthread_mutex_destroy(&(*sem)->lock); 100 free(*sem); 101 errno = ENOSPC; 102 retval = -1; 103 goto RETURN; 104 } 105 106 (*sem)->count = (u_int32_t)value; 107 (*sem)->nwaiters = 0; 108 (*sem)->magic = SEM_MAGIC; 109 110 retval = 0; 111 RETURN: 112 return retval; 113} 114 115int 116_sem_destroy(sem_t *sem) 117{ 118 int retval; 119 120 _SEM_CHECK_VALIDITY(sem); 121 122 /* Make sure there are no waiters. */ 123 pthread_mutex_lock(&(*sem)->lock); 124 if ((*sem)->nwaiters > 0) { 125 pthread_mutex_unlock(&(*sem)->lock); 126 errno = EBUSY; 127 retval = -1; 128 goto RETURN; 129 } 130 pthread_mutex_unlock(&(*sem)->lock); 131 132 pthread_mutex_destroy(&(*sem)->lock); 133 pthread_cond_destroy(&(*sem)->gtzero); 134 (*sem)->magic = 0; 135 136 free(*sem); 137 138 retval = 0; 139 RETURN: 140 return retval; 141} 142 143sem_t * 144_sem_open(const char *name, int oflag, ...) 145{ 146 errno = ENOSYS; 147 return SEM_FAILED; 148} 149 150int 151_sem_close(sem_t *sem) 152{ 153 errno = ENOSYS; 154 return -1; 155} 156 157int 158_sem_unlink(const char *name) 159{ 160 errno = ENOSYS; 161 return -1; 162} 163 164int 165_sem_wait(sem_t *sem) 166{ 167 int retval; 168 169 _thread_enter_cancellation_point(); 170 171 _SEM_CHECK_VALIDITY(sem); 172 173 pthread_mutex_lock(&(*sem)->lock); 174 175 while ((*sem)->count == 0) { 176 (*sem)->nwaiters++; 177 pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); 178 (*sem)->nwaiters--; 179 } 180 (*sem)->count--; 181 182 pthread_mutex_unlock(&(*sem)->lock); 183 184 retval = 0; 185 RETURN: 186 _thread_leave_cancellation_point(); 187 return retval; 188} 189 190int 191_sem_trywait(sem_t *sem) 192{ 193 int retval; 194 195 _SEM_CHECK_VALIDITY(sem); 196 197 pthread_mutex_lock(&(*sem)->lock); 198 199 if ((*sem)->count > 0) { 200 (*sem)->count--; 201 retval = 0; 202 } else { 203 errno = EAGAIN; 204 retval = -1; 205 } 206 207 pthread_mutex_unlock(&(*sem)->lock); 208 209 RETURN: 210 return retval; 211} 212 213int 214_sem_post(sem_t *sem) 215{ 216 int retval; 217 218 _SEM_CHECK_VALIDITY(sem); 219 220 /* 221 * sem_post() is required to be safe to call from within signal 222 * handlers. Thus, we must defer signals. 223 */ 224 pthread_mutex_lock(&(*sem)->lock); 225 226 /* GIANT_LOCK(curthread); */ 227 228 (*sem)->count++; 229 if ((*sem)->nwaiters > 0) 230 pthread_cond_signal(&(*sem)->gtzero); 231 232 /* GIANT_UNLOCK(curthread); */ 233 234 pthread_mutex_unlock(&(*sem)->lock); 235 236 retval = 0; 237 RETURN: 238 return retval; 239} 240 241int 242_sem_getvalue(sem_t *sem, int *sval) 243{ 244 int retval; 245 246 _SEM_CHECK_VALIDITY(sem); 247 248 pthread_mutex_lock(&(*sem)->lock); 249 *sval = (int)(*sem)->count; 250 pthread_mutex_unlock(&(*sem)->lock); 251 252 retval = 0; 253 RETURN: 254 return retval; 255} 256