thr_mutex.c revision 31402
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 || *mutex == NULL) { 166 ret = EINVAL; 167 } else { 168 /* Block signals: */ 169 _thread_kern_sig_block(&status); 170 171 /* Process according to mutex type: */ 172 switch ((*mutex)->m_type) { 173 /* Fast mutex: */ 174 case MUTEX_TYPE_FAST: 175 /* Check if this mutex is not locked: */ 176 if ((*mutex)->m_owner == NULL) { 177 /* Lock the mutex for the running thread: */ 178 (*mutex)->m_owner = _thread_run; 179 } else { 180 /* Return a busy error: */ 181 ret = EBUSY; 182 } 183 break; 184 185 /* Counting mutex: */ 186 case MUTEX_TYPE_COUNTING_FAST: 187 /* Check if this mutex is locked: */ 188 if ((*mutex)->m_owner != NULL) { 189 /* 190 * Check if the mutex is locked by the running 191 * thread: 192 */ 193 if ((*mutex)->m_owner == _thread_run) { 194 /* Increment the lock count: */ 195 (*mutex)->m_data.m_count++; 196 } else { 197 /* Return a busy error: */ 198 ret = EBUSY; 199 } 200 } else { 201 /* Lock the mutex for the running thread: */ 202 (*mutex)->m_owner = _thread_run; 203 } 204 break; 205 206 /* Trap invalid mutex types: */ 207 default: 208 /* Return an invalid argument error: */ 209 ret = EINVAL; 210 break; 211 } 212 213 /* Unblock signals: */ 214 _thread_kern_sig_unblock(status); 215 } 216 217 /* Return the completion status: */ 218 return (ret); 219} 220 221int 222pthread_mutex_lock(pthread_mutex_t * mutex) 223{ 224 int ret = 0; 225 int status; 226 227 if (mutex == NULL || *mutex == NULL) { 228 ret = EINVAL; 229 } else { 230 /* Block signals: */ 231 _thread_kern_sig_block(&status); 232 233 /* Process according to mutex type: */ 234 switch ((*mutex)->m_type) { 235 /* Fast mutexes do not check for any error conditions: */ 236 case MUTEX_TYPE_FAST: 237 /* 238 * Enter a loop to wait for the mutex to be locked by the 239 * current thread: 240 */ 241 while ((*mutex)->m_owner != _thread_run) { 242 /* Check if the mutex is not locked: */ 243 if ((*mutex)->m_owner == NULL) { 244 /* Lock the mutex for this thread: */ 245 (*mutex)->m_owner = _thread_run; 246 } else { 247 /* 248 * Join the queue of threads waiting to lock 249 * the mutex: 250 */ 251 _thread_queue_enq(&(*mutex)->m_queue, _thread_run); 252 253 /* Block signals: */ 254 _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); 255 256 /* Block signals: */ 257 _thread_kern_sig_block(NULL); 258 } 259 } 260 break; 261 262 /* Counting mutex: */ 263 case MUTEX_TYPE_COUNTING_FAST: 264 /* 265 * Enter a loop to wait for the mutex to be locked by the 266 * current thread: 267 */ 268 while ((*mutex)->m_owner != _thread_run) { 269 /* Check if the mutex is not locked: */ 270 if ((*mutex)->m_owner == NULL) { 271 /* Lock the mutex for this thread: */ 272 (*mutex)->m_owner = _thread_run; 273 274 /* Reset the lock count for this mutex: */ 275 (*mutex)->m_data.m_count = 0; 276 } else { 277 /* 278 * Join the queue of threads waiting to lock 279 * the mutex: 280 */ 281 _thread_queue_enq(&(*mutex)->m_queue, _thread_run); 282 283 /* Block signals: */ 284 _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__); 285 286 /* Block signals: */ 287 _thread_kern_sig_block(NULL); 288 } 289 } 290 291 /* Increment the lock count for this mutex: */ 292 (*mutex)->m_data.m_count++; 293 break; 294 295 /* Trap invalid mutex types: */ 296 default: 297 /* Return an invalid argument error: */ 298 ret = EINVAL; 299 break; 300 } 301 302 /* Unblock signals: */ 303 _thread_kern_sig_unblock(status); 304 } 305 306 /* Return the completion status: */ 307 return (ret); 308} 309 310int 311pthread_mutex_unlock(pthread_mutex_t * mutex) 312{ 313 int ret = 0; 314 int status; 315 316 if (mutex == NULL || *mutex == NULL) { 317 ret = EINVAL; 318 } else { 319 /* Block signals: */ 320 _thread_kern_sig_block(&status); 321 322 /* Process according to mutex type: */ 323 switch ((*mutex)->m_type) { 324 /* Fast mutexes do not check for any error conditions: */ 325 case MUTEX_TYPE_FAST: 326 /* Check if the running thread is not the owner of the mutex: */ 327 if ((*mutex)->m_owner != _thread_run) { 328 /* Return an invalid argument error: */ 329 ret = EINVAL; 330 } 331 /* 332 * Get the next thread from the queue of threads waiting on 333 * the mutex: 334 */ 335 else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { 336 /* Allow the new owner of the mutex to run: */ 337 PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING); 338 } 339 break; 340 341 /* Counting mutex: */ 342 case MUTEX_TYPE_COUNTING_FAST: 343 /* Check if the running thread is not the owner of the mutex: */ 344 if ((*mutex)->m_owner != _thread_run) { 345 /* Return an invalid argument error: */ 346 ret = EINVAL; 347 } 348 /* Check if there are still counts: */ 349 else if ((*mutex)->m_data.m_count) { 350 /* Decrement the count: */ 351 (*mutex)->m_data.m_count--; 352 } 353 /* 354 * Get the next thread from the queue of threads waiting on 355 * the mutex: 356 */ 357 else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) { 358 /* Allow the new owner of the mutex to run: */ 359 PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING); 360 } 361 break; 362 363 /* Trap invalid mutex types: */ 364 default: 365 /* Return an invalid argument error: */ 366 ret = EINVAL; 367 break; 368 } 369 370 /* Unblock signals: */ 371 _thread_kern_sig_unblock(status); 372 } 373 374 /* Return the completion status: */ 375 return (ret); 376} 377#endif 378