thr_sem.c revision 125394
1228690Sdes/* 2228690Sdes * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. 3228690Sdes * All rights reserved. 4228690Sdes * 5228690Sdes * Redistribution and use in source and binary forms, with or without 6228690Sdes * modification, are permitted provided that the following conditions 7228690Sdes * are met: 8228690Sdes * 1. Redistributions of source code must retain the above copyright 9255376Sdes * notice(s), this list of conditions and the following disclaimer as 10228690Sdes * the first lines of this file unmodified other than the possible 11228690Sdes * addition of one or more copyright notices. 12228690Sdes * 2. Redistributions in binary form must reproduce the above copyright 13236099Sdes * notice(s), this list of conditions and the following disclaimer in 14236099Sdes * the documentation and/or other materials provided with the 15236099Sdes * distribution. 16228690Sdes * 17228690Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 18228690Sdes * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19228690Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20228690Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 21228690Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22228690Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23228690Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24228690Sdes * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25228690Sdes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26228690Sdes * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27228690Sdes * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28228690Sdes * 29255376Sdes * $FreeBSD: head/lib/libthr/thread/thr_sem.c 125394 2004-02-03 15:55:30Z deischen $ 30228690Sdes */ 31228690Sdes 32236099Sdes#include <stdlib.h> 33236099Sdes#include <errno.h> 34228690Sdes#include <time.h> 35228690Sdes#include <semaphore.h> 36228690Sdes#include <pthread.h> 37228690Sdes#include "thr_private.h" 38228690Sdes 39228690Sdes#define _SEM_CHECK_VALIDITY(sem) \ 40228690Sdes if ((*(sem))->magic != SEM_MAGIC) { \ 41228690Sdes errno = EINVAL; \ 42255376Sdes retval = -1; \ 43255376Sdes goto RETURN; \ 44255376Sdes } 45228690Sdes 46__weak_reference(_sem_init, sem_init); 47__weak_reference(_sem_destroy, sem_destroy); 48__weak_reference(_sem_open, sem_open); 49__weak_reference(_sem_close, sem_close); 50__weak_reference(_sem_unlink, sem_unlink); 51__weak_reference(_sem_wait, sem_wait); 52__weak_reference(_sem_trywait, sem_trywait); 53__weak_reference(_sem_post, sem_post); 54__weak_reference(_sem_getvalue, sem_getvalue); 55 56 57int 58_sem_init(sem_t *sem, int pshared, unsigned int value) 59{ 60 int retval; 61 62 /* 63 * Range check the arguments. 64 */ 65 if (pshared != 0) { 66 /* 67 * The user wants a semaphore that can be shared among 68 * processes, which this implementation can't do. Sounds like a 69 * permissions problem to me (yeah right). 70 */ 71 errno = EPERM; 72 retval = -1; 73 goto RETURN; 74 } 75 76 if (value > SEM_VALUE_MAX) { 77 errno = EINVAL; 78 retval = -1; 79 goto RETURN; 80 } 81 82 *sem = (sem_t)malloc(sizeof(struct sem)); 83 if (*sem == NULL) { 84 errno = ENOSPC; 85 retval = -1; 86 goto RETURN; 87 } 88 89 /* 90 * Initialize the semaphore. 91 */ 92 if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) { 93 free(*sem); 94 errno = ENOSPC; 95 retval = -1; 96 goto RETURN; 97 } 98 99 if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) { 100 pthread_mutex_destroy(&(*sem)->lock); 101 free(*sem); 102 errno = ENOSPC; 103 retval = -1; 104 goto RETURN; 105 } 106 107 (*sem)->count = (u_int32_t)value; 108 (*sem)->nwaiters = 0; 109 (*sem)->magic = SEM_MAGIC; 110 111 retval = 0; 112 RETURN: 113 return retval; 114} 115 116int 117_sem_destroy(sem_t *sem) 118{ 119 int retval; 120 121 _SEM_CHECK_VALIDITY(sem); 122 123 /* Make sure there are no waiters. */ 124 pthread_mutex_lock(&(*sem)->lock); 125 if ((*sem)->nwaiters > 0) { 126 pthread_mutex_unlock(&(*sem)->lock); 127 errno = EBUSY; 128 retval = -1; 129 goto RETURN; 130 } 131 pthread_mutex_unlock(&(*sem)->lock); 132 133 pthread_mutex_destroy(&(*sem)->lock); 134 pthread_cond_destroy(&(*sem)->gtzero); 135 (*sem)->magic = 0; 136 137 free(*sem); 138 139 retval = 0; 140 RETURN: 141 return retval; 142} 143 144sem_t * 145_sem_open(const char *name, int oflag, ...) 146{ 147 errno = ENOSYS; 148 return SEM_FAILED; 149} 150 151int 152_sem_close(sem_t *sem) 153{ 154 errno = ENOSYS; 155 return -1; 156} 157 158int 159_sem_unlink(const char *name) 160{ 161 errno = ENOSYS; 162 return -1; 163} 164 165int 166_sem_wait(sem_t *sem) 167{ 168 int retval; 169 170 _thread_enter_cancellation_point(); 171 172 _SEM_CHECK_VALIDITY(sem); 173 174 pthread_mutex_lock(&(*sem)->lock); 175 176 while ((*sem)->count == 0) { 177 (*sem)->nwaiters++; 178 pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); 179 (*sem)->nwaiters--; 180 } 181 (*sem)->count--; 182 183 pthread_mutex_unlock(&(*sem)->lock); 184 185 retval = 0; 186 RETURN: 187 _thread_leave_cancellation_point(); 188 return retval; 189} 190 191int 192_sem_trywait(sem_t *sem) 193{ 194 int retval; 195 196 _SEM_CHECK_VALIDITY(sem); 197 198 pthread_mutex_lock(&(*sem)->lock); 199 200 if ((*sem)->count > 0) { 201 (*sem)->count--; 202 retval = 0; 203 } else { 204 errno = EAGAIN; 205 retval = -1; 206 } 207 208 pthread_mutex_unlock(&(*sem)->lock); 209 210 RETURN: 211 return retval; 212} 213 214int 215_sem_post(sem_t *sem) 216{ 217 int retval; 218 219 _SEM_CHECK_VALIDITY(sem); 220 221 /* 222 * sem_post() is required to be safe to call from within signal 223 * handlers. Thus, we must defer signals. 224 */ 225 pthread_mutex_lock(&(*sem)->lock); 226 227 /* GIANT_LOCK(curthread); */ 228 229 (*sem)->count++; 230 if ((*sem)->nwaiters > 0) 231 pthread_cond_signal(&(*sem)->gtzero); 232 233 /* GIANT_UNLOCK(curthread); */ 234 235 pthread_mutex_unlock(&(*sem)->lock); 236 237 retval = 0; 238 RETURN: 239 return retval; 240} 241 242int 243_sem_getvalue(sem_t *sem, int *sval) 244{ 245 int retval; 246 247 _SEM_CHECK_VALIDITY(sem); 248 249 pthread_mutex_lock(&(*sem)->lock); 250 *sval = (int)(*sem)->count; 251 pthread_mutex_unlock(&(*sem)->lock); 252 253 retval = 0; 254 RETURN: 255 return retval; 256} 257