thr_mutex.c revision 35027
1/* 2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 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, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33#include <stdlib.h> 34#include <errno.h> 35#ifdef _THREAD_SAFE 36#include <pthread.h> 37#include "pthread_private.h" 38 39int 40pthread_mutex_init(pthread_mutex_t * mutex, 41 const pthread_mutexattr_t * mutex_attr) 42{ 43 enum pthread_mutextype type; 44 pthread_mutex_t pmutex; 45 int ret = 0; 46 int status; 47 48 if (mutex == NULL) { 49 ret = EINVAL; 50 } else { 51 /* Check if default mutex attributes: */ 52 if (mutex_attr == NULL || *mutex_attr == NULL) { 53 /* Default to a fast mutex: */ 54 type = MUTEX_TYPE_FAST; 55 } else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX) { 56 /* Return an invalid argument error: */ 57 ret = EINVAL; 58 } else { 59 /* Use the requested mutex type: */ 60 type = (*mutex_attr)->m_type; 61 } 62 63 /* Check no errors so far: */ 64 if (ret == 0) { 65 if ((pmutex = (pthread_mutex_t) malloc(sizeof(struct pthread_mutex))) == NULL) { 66 ret = ENOMEM; 67 } else { 68 /* Reset the mutex flags: */ 69 pmutex->m_flags = 0; 70 71 /* Block signals: */ 72 _thread_kern_sig_block(&status); 73 74 /* Process according to mutex type: */ 75 switch (type) { 76 /* Fast mutex: */ 77 case MUTEX_TYPE_FAST: 78 /* Nothing to do here. */ 79 break; 80 81 /* Counting mutex: */ 82 case MUTEX_TYPE_COUNTING_FAST: 83 /* Reset the mutex count: */ 84 pmutex->m_data.m_count = 0; 85 break; 86 87 /* Trap invalid mutex types: */ 88 default: 89 /* Return an invalid argument error: */ 90 ret = EINVAL; 91 break; 92 } 93 if (ret == 0) { 94 /* Initialise the rest of the mutex: */ 95 _thread_queue_init(&pmutex->m_queue); 96 pmutex->m_flags |= MUTEX_FLAGS_INITED; 97 pmutex->m_owner = NULL; 98 pmutex->m_type = type; 99 *mutex = pmutex; 100 } else { 101 free(pmutex); 102 *mutex = NULL; 103 } 104 105 /* Unblock signals: */ 106 _thread_kern_sig_unblock(status); 107 } 108 } 109 } 110 /* Return the completion status: */ 111 return (ret); 112} 113 114int 115pthread_mutex_destroy(pthread_mutex_t * mutex) 116{ 117 int ret = 0; 118 int status; 119 120 if (mutex == NULL || *mutex == NULL) { 121 ret = EINVAL; 122 } else { 123 /* Block signals: */ 124 _thread_kern_sig_block(&status); 125 126 /* Process according to mutex type: */ 127 switch ((*mutex)->m_type) { 128 /* Fast mutex: */ 129 case MUTEX_TYPE_FAST: 130 /* Nothing to do here. */ 131 break; 132 133 /* Counting mutex: */ 134 case MUTEX_TYPE_COUNTING_FAST: 135 /* Reset the mutex count: */ 136 (*mutex)->m_data.m_count = 0; 137 break; 138 139 /* Trap undefined mutex types: */ 140 default: 141 /* Return an invalid argument error: */ 142 ret = EINVAL; 143 break; 144 } 145 146 /* Clean up the mutex in case that others want to use it: */ 147 _thread_queue_init(&(*mutex)->m_queue); 148 (*mutex)->m_owner = NULL; 149 (*mutex)->m_flags = 0; 150 151 /* Unblock signals: */ 152 _thread_kern_sig_unblock(status); 153 } 154 155 /* Return the completion status: */ 156 return (ret); 157} 158 159int 160pthread_mutex_trylock(pthread_mutex_t * mutex) 161{ 162 int ret = 0; 163 int status; 164 165 if (mutex == NULL) 166 ret = EINVAL; 167 168 /* 169 * If the mutex is statically initialized, perform the dynamic 170 * initialization: 171 */ 172 else if (*mutex != NULL || 173 (ret = pthread_mutex_init(mutex,NULL)) == 0) { 174 /* Block signals: */ 175 _thread_kern_sig_block(&status); 176 177 /* Process according to mutex type: */ 178 switch ((*mutex)->m_type) { 179 /* Fast mutex: */ 180 case MUTEX_TYPE_FAST: 181 /* Check if this mutex is not locked: */ 182 if ((*mutex)->m_owner == NULL) { 183 /* Lock the mutex for the running thread: */ 184 (*mutex)->m_owner = _thread_run; 185 } else { 186 /* Return a busy error: */ 187 ret = EBUSY; 188 } 189 break; 190 191 /* Counting mutex: */ 192 case MUTEX_TYPE_COUNTING_FAST: 193 /* Check if this mutex is locked: */ 194 if ((*mutex)->m_owner != NULL) { 195 /* 196 * Check if the mutex is locked by the running 197 * thread: 198 */ 199 if ((*mutex)->m_owner == _thread_run) { 200 /* Increment the lock count: */ 201 (*mutex)->m_data.m_count++; 202 } else { 203 /* Return a busy error: */ 204 ret = EBUSY; 205 } 206 } else { 207 /* Lock the mutex for the running thread: */ 208 (*mutex)->m_owner = _thread_run; 209 } 210 break; 211 212 /* Trap invalid mutex types: */ 213 default: 214 /* Return an invalid argument error: */ 215 ret = EINVAL; 216 break; 217 } 218 219 /* Unblock signals: */ 220 _thread_kern_sig_unblock(status); 221 } 222 223 /* Return the completion status: */ 224 return (ret); 225} 226 227int 228pthread_mutex_lock(pthread_mutex_t * mutex) 229{ 230 int ret = 0; 231 int status; 232 233 if (mutex == NULL) 234 ret = EINVAL; 235 236 /* 237 * If the mutex is statically initialized, perform the dynamic 238 * initialization: 239 */ 240 else if (*mutex != NULL || 241 (ret = pthread_mutex_init(mutex,NULL)) == 0) { 242 /* Block signals: */ 243 _thread_kern_sig_block(&status); 244 245 /* Process according to mutex type: */ 246 switch ((*mutex)->m_type) { 247 /* Fast mutexes do not check for any error conditions: */ 248 case MUTEX_TYPE_FAST: 249 /* 250 * Enter a loop to wait for the mutex to be locked by the 251 * current thread: 252 */ 253 while ((*mutex)->m_owner != _thread_run) { 254 /* Check if the mutex is not locked: */ 255 if ((*mutex)->m_owner == NULL) { 256 /* Lock the mutex for this thread: */ 257 (*mutex)->m_owner = _thread_run; 258 } else { 259 /* 260 * Join the queue of threads waiting to lock 261 * the mutex: 262 */ 263 _thread_queue_enq(&(*mutex)->m_queue, _thread_run); 264 265 /* Block signals: */ 266 _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); 267 268 /* Block signals: */ 269 _thread_kern_sig_block(NULL); 270 } 271 } 272 break; 273 274 /* Counting mutex: */ 275 case MUTEX_TYPE_COUNTING_FAST: 276 /* 277 * Enter a loop to wait for the mutex to be locked by the 278 * current thread: 279 */ 280 while ((*mutex)->m_owner != _thread_run) { 281 /* Check if the mutex is not locked: */ 282 if ((*mutex)->m_owner == NULL) { 283 /* Lock the mutex for this thread: */ 284 (*mutex)->m_owner = _thread_run; 285 286 /* Reset the lock count for this mutex: */ 287 (*mutex)->m_data.m_count = 0; 288 } else { 289 /* 290 * Join the queue of threads waiting to lock 291 * the mutex: 292 */ 293 _thread_queue_enq(&(*mutex)->m_queue, _thread_run); 294 295 /* Block signals: */ 296 _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); 297 298 /* Block signals: */ 299 _thread_kern_sig_block(NULL); 300 } 301 } 302 303 /* Increment the lock count for this mutex: */ 304 (*mutex)->m_data.m_count++; 305 break; 306 307 /* Trap invalid mutex types: */ 308 default: 309 /* Return an invalid argument error: */ 310 ret = EINVAL; 311 break; 312 } 313 314 /* Unblock signals: */ 315 _thread_kern_sig_unblock(status); 316 } 317 318 /* Return the completion status: */ 319 return (ret); 320} 321 322int 323pthread_mutex_unlock(pthread_mutex_t * mutex) 324{ 325 int ret = 0; 326 int status; 327 328 if (mutex == NULL || *mutex == NULL) { 329 ret = EINVAL; 330 } else { 331 /* Block signals: */ 332 _thread_kern_sig_block(&status); 333 334 /* Process according to mutex type: */ 335 switch ((*mutex)->m_type) { 336 /* Fast mutexes do not check for any error conditions: */ 337 case MUTEX_TYPE_FAST: 338 /* Check if the running thread is not the owner of the mutex: */ 339 if ((*mutex)->m_owner != _thread_run) { 340 /* Return an invalid argument error: */ 341 ret = EINVAL; 342 } 343 /* 344 * Get the next thread from the queue of threads waiting on 345 * the mutex: 346 */ 347 else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { 348 /* Allow the new owner of the mutex to run: */ 349 PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING); 350 } 351 break; 352 353 /* Counting mutex: */ 354 case MUTEX_TYPE_COUNTING_FAST: 355 /* Check if the running thread is not the owner of the mutex: */ 356 if ((*mutex)->m_owner != _thread_run) { 357 /* Return an invalid argument error: */ 358 ret = EINVAL; 359 } 360 /* Check if there are still counts: */ 361 else if ((*mutex)->m_data.m_count) { 362 /* Decrement the count: */ 363 (*mutex)->m_data.m_count--; 364 } 365 /* 366 * Get the next thread from the queue of threads waiting on 367 * the mutex: 368 */ 369 else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { 370 /* Allow the new owner of the mutex to run: */ 371 PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING); 372 } 373 break; 374 375 /* Trap invalid mutex types: */ 376 default: 377 /* Return an invalid argument error: */ 378 ret = EINVAL; 379 break; 380 } 381 382 /* Unblock signals: */ 383 _thread_kern_sig_unblock(status); 384 } 385 386 /* Return the completion status: */ 387 return (ret); 388} 389#endif 390