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$ 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 56 int 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 115 int 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 143 sem_t * 144 _sem_open(const char *name, int oflag, ...) 145 { 146 errno = ENOSYS; 147 return SEM_FAILED; 148 } 149 150 int 151 _sem_close(sem_t *sem) 152 { 153 errno = ENOSYS; 154 return -1; 155 } 156 157 int 158 _sem_unlink(const char *name) 159 { 160 errno = ENOSYS; 161 return -1; 162 } 163 164 int 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 190 int 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 213 int 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 241 int 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