thr_sem.c revision 112918
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 112918 2003-04-01 03:46:29Z jeff $ 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 pthread_t curthread; 217 int retval; 218 219 _SEM_CHECK_VALIDITY(sem); 220 221 curthread = _get_curthread(); 222 /* 223 * sem_post() is required to be safe to call from within signal 224 * handlers. Thus, we must defer signals. 225 */ 226 pthread_mutex_lock(&(*sem)->lock); 227 228 /* GIANT_LOCK(curthread); */ 229 230 (*sem)->count++; 231 if ((*sem)->nwaiters > 0) 232 pthread_cond_signal(&(*sem)->gtzero); 233 234 /* GIANT_UNLOCK(curthread); */ 235 236 pthread_mutex_unlock(&(*sem)->lock); 237 238 retval = 0; 239 RETURN: 240 return retval; 241} 242 243int 244_sem_getvalue(sem_t *sem, int *sval) 245{ 246 int retval; 247 248 _SEM_CHECK_VALIDITY(sem); 249 250 pthread_mutex_lock(&(*sem)->lock); 251 *sval = (int)(*sem)->count; 252 pthread_mutex_unlock(&(*sem)->lock); 253 254 retval = 0; 255 RETURN: 256 return retval; 257} 258