pthread_mutex.c revision 1.28
1/* $NetBSD: pthread_mutex.c,v 1.28 2007/03/24 18:52:00 ad Exp $ */ 2 3/*- 4 * Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nathan J. Williams, by Jason R. Thorpe, and by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/cdefs.h> 40__RCSID("$NetBSD: pthread_mutex.c,v 1.28 2007/03/24 18:52:00 ad Exp $"); 41 42#include <errno.h> 43#include <limits.h> 44#include <stdlib.h> 45#include <string.h> 46 47#include "pthread.h" 48#include "pthread_int.h" 49 50static int pthread_mutex_lock_slow(pthread_t, pthread_mutex_t *); 51 52__strong_alias(__libc_mutex_init,pthread_mutex_init) 53__strong_alias(__libc_mutex_lock,pthread_mutex_lock) 54__strong_alias(__libc_mutex_trylock,pthread_mutex_trylock) 55__strong_alias(__libc_mutex_unlock,pthread_mutex_unlock) 56__strong_alias(__libc_mutex_destroy,pthread_mutex_destroy) 57 58__strong_alias(__libc_mutexattr_init,pthread_mutexattr_init) 59__strong_alias(__libc_mutexattr_destroy,pthread_mutexattr_destroy) 60__strong_alias(__libc_mutexattr_settype,pthread_mutexattr_settype) 61 62__strong_alias(__libc_thr_once,pthread_once) 63 64struct mutex_private { 65 int type; 66 int recursecount; 67}; 68 69static const struct mutex_private mutex_private_default = { 70 PTHREAD_MUTEX_DEFAULT, 71 0, 72}; 73 74struct mutexattr_private { 75 int type; 76}; 77 78static const struct mutexattr_private mutexattr_private_default = { 79 PTHREAD_MUTEX_DEFAULT, 80}; 81 82/* 83 * If the mutex does not already have private data (i.e. was statically 84 * initialized), then give it the default. 85 */ 86#define GET_MUTEX_PRIVATE(mutex, mp) \ 87do { \ 88 if (__predict_false((mp = (mutex)->ptm_private) == NULL)) { \ 89 /* LINTED cast away const */ \ 90 mp = ((mutex)->ptm_private = \ 91 (void *)&mutex_private_default); \ 92 } \ 93} while (/*CONSTCOND*/0) 94 95int 96pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) 97{ 98 struct mutexattr_private *map; 99 struct mutex_private *mp; 100 101 pthread__error(EINVAL, "Invalid mutex attribute", 102 (attr == NULL) || (attr->ptma_magic == _PT_MUTEXATTR_MAGIC)); 103 104 if (attr != NULL && (map = attr->ptma_private) != NULL && 105 memcmp(map, &mutexattr_private_default, sizeof(*map)) != 0) { 106 mp = malloc(sizeof(*mp)); 107 if (mp == NULL) 108 return ENOMEM; 109 110 mp->type = map->type; 111 mp->recursecount = 0; 112 } else { 113 /* LINTED cast away const */ 114 mp = (struct mutex_private *) &mutex_private_default; 115 } 116 117 mutex->ptm_magic = _PT_MUTEX_MAGIC; 118 mutex->ptm_owner = NULL; 119 pthread_lockinit(&mutex->ptm_lock); 120 pthread_lockinit(&mutex->ptm_interlock); 121 PTQ_INIT(&mutex->ptm_blocked); 122 mutex->ptm_private = mp; 123 124 return 0; 125} 126 127 128int 129pthread_mutex_destroy(pthread_mutex_t *mutex) 130{ 131 132 pthread__error(EINVAL, "Invalid mutex", 133 mutex->ptm_magic == _PT_MUTEX_MAGIC); 134 pthread__error(EBUSY, "Destroying locked mutex", 135 mutex->ptm_lock == __SIMPLELOCK_UNLOCKED); 136 137 mutex->ptm_magic = _PT_MUTEX_DEAD; 138 if (mutex->ptm_private != NULL && 139 mutex->ptm_private != (const void *)&mutex_private_default) 140 free(mutex->ptm_private); 141 142 return 0; 143} 144 145 146/* 147 * Note regarding memory visibility: Pthreads has rules about memory 148 * visibility and mutexes. Very roughly: Memory a thread can see when 149 * it unlocks a mutex can be seen by another thread that locks the 150 * same mutex. 151 * 152 * A memory barrier after a lock and before an unlock will provide 153 * this behavior. This code relies on pthread__simple_lock_try() to issue 154 * a barrier after obtaining a lock, and on pthread__simple_unlock() to 155 * issue a barrier before releasing a lock. 156 */ 157 158int 159pthread_mutex_lock(pthread_mutex_t *mutex) 160{ 161 pthread_t self; 162 int error; 163 164 self = pthread__self(); 165 166 PTHREADD_ADD(PTHREADD_MUTEX_LOCK); 167 168 /* 169 * Note that if we get the lock, we don't have to deal with any 170 * non-default lock type handling. 171 */ 172 if (__predict_false(pthread__simple_lock_try(&mutex->ptm_lock) == 0)) { 173 error = pthread_mutex_lock_slow(self, mutex); 174 if (error) 175 return error; 176 } 177 178 /* 179 * We have the lock! 180 */ 181 self->pt_mutexhint = mutex; 182 mutex->ptm_owner = self; 183 184 return 0; 185} 186 187 188static int 189pthread_mutex_lock_slow(pthread_t self, pthread_mutex_t *mutex) 190{ 191 extern int pthread__started; 192 193 pthread__error(EINVAL, "Invalid mutex", 194 mutex->ptm_magic == _PT_MUTEX_MAGIC); 195 196 PTHREADD_ADD(PTHREADD_MUTEX_LOCK_SLOW); 197 while (/*CONSTCOND*/1) { 198 if (pthread__simple_lock_try(&mutex->ptm_lock)) 199 break; /* got it! */ 200 201 /* Okay, didn't look free. Get the interlock... */ 202 pthread_spinlock(self, &mutex->ptm_interlock); 203 204 /* 205 * The mutex_unlock routine will get the interlock 206 * before looking at the list of sleepers, so if the 207 * lock is held we can safely put ourselves on the 208 * sleep queue. If it's not held, we can try taking it 209 * again. 210 */ 211 PTQ_INSERT_HEAD(&mutex->ptm_blocked, self, pt_sleep); 212 if (mutex->ptm_lock == __SIMPLELOCK_LOCKED) { 213 struct mutex_private *mp; 214 215 GET_MUTEX_PRIVATE(mutex, mp); 216 217 if (mutex->ptm_owner == self) { 218 switch (mp->type) { 219 case PTHREAD_MUTEX_ERRORCHECK: 220 PTQ_REMOVE(&mutex->ptm_blocked, self, 221 pt_sleep); 222 pthread_spinunlock(self, 223 &mutex->ptm_interlock); 224 return EDEADLK; 225 226 case PTHREAD_MUTEX_RECURSIVE: 227 /* 228 * It's safe to do this without 229 * holding the interlock, because 230 * we only modify it if we know we 231 * own the mutex. 232 */ 233 PTQ_REMOVE(&mutex->ptm_blocked, self, 234 pt_sleep); 235 pthread_spinunlock(self, 236 &mutex->ptm_interlock); 237 if (mp->recursecount == INT_MAX) 238 return EAGAIN; 239 mp->recursecount++; 240 return 0; 241 } 242 } 243 244 if (pthread__started == 0) { 245 sigset_t ss; 246 247 /* 248 * The spec says we must deadlock, so... 249 */ 250 pthread__assert(mp->type == 251 PTHREAD_MUTEX_NORMAL); 252 (void) sigprocmask(SIG_SETMASK, NULL, &ss); 253 for (;;) { 254 sigsuspend(&ss); 255 } 256 /*NOTREACHED*/ 257 } 258 259 /* 260 * Locking a mutex is not a cancellation 261 * point, so we don't need to do the 262 * test-cancellation dance. We may get woken 263 * up spuriously by pthread_cancel or signals, 264 * but it's okay since we're just going to 265 * retry. 266 */ 267 self->pt_sleeponq = 1; 268 self->pt_sleepobj = &mutex->ptm_blocked; 269 (void)pthread__park(self, &mutex->ptm_interlock, 270 &mutex->ptm_blocked, NULL, 0, &mutex->ptm_blocked); 271 pthread_spinunlock(self, &mutex->ptm_interlock); 272 } else { 273 PTQ_REMOVE(&mutex->ptm_blocked, self, pt_sleep); 274 pthread_spinunlock(self, &mutex->ptm_interlock); 275 } 276 /* Go around for another try. */ 277 } 278 279 return 0; 280} 281 282 283int 284pthread_mutex_trylock(pthread_mutex_t *mutex) 285{ 286 struct mutex_private *mp; 287 pthread_t self; 288 289 pthread__error(EINVAL, "Invalid mutex", 290 mutex->ptm_magic == _PT_MUTEX_MAGIC); 291 292 self = pthread__self(); 293 294 PTHREADD_ADD(PTHREADD_MUTEX_TRYLOCK); 295 if (pthread__simple_lock_try(&mutex->ptm_lock) == 0) { 296 /* 297 * These tests can be performed without holding the 298 * interlock because these fields are only modified 299 * if we know we own the mutex. 300 */ 301 GET_MUTEX_PRIVATE(mutex, mp); 302 if (mp->type == PTHREAD_MUTEX_RECURSIVE && 303 mutex->ptm_owner == self) { 304 if (mp->recursecount == INT_MAX) 305 return EAGAIN; 306 mp->recursecount++; 307 return 0; 308 } 309 310 return EBUSY; 311 } 312 313 mutex->ptm_owner = self; 314 self->pt_mutexhint = mutex; 315 316 return 0; 317} 318 319 320int 321pthread_mutex_unlock(pthread_mutex_t *mutex) 322{ 323 struct mutex_private *mp; 324 pthread_t self; 325 int weown; 326 327 pthread__error(EINVAL, "Invalid mutex", 328 mutex->ptm_magic == _PT_MUTEX_MAGIC); 329 330 PTHREADD_ADD(PTHREADD_MUTEX_UNLOCK); 331 332 GET_MUTEX_PRIVATE(mutex, mp); 333 334 self = pthread_self(); 335 /* 336 * These tests can be performed without holding the 337 * interlock because these fields are only modified 338 * if we know we own the mutex. 339 */ 340 weown = (mutex->ptm_owner == self); 341 switch (mp->type) { 342 case PTHREAD_MUTEX_RECURSIVE: 343 if (!weown) 344 return EPERM; 345 if (mp->recursecount != 0) { 346 mp->recursecount--; 347 return 0; 348 } 349 break; 350 case PTHREAD_MUTEX_ERRORCHECK: 351 if (!weown) 352 return EPERM; 353 /*FALLTHROUGH*/ 354 default: 355 if (__predict_false(!weown)) { 356 pthread__error(EPERM, "Unlocking unlocked mutex", 357 (mutex->ptm_owner != 0)); 358 pthread__error(EPERM, 359 "Unlocking mutex owned by another thread", weown); 360 } 361 break; 362 } 363 364 mutex->ptm_owner = NULL; 365 pthread__simple_unlock(&mutex->ptm_lock); 366 367 /* 368 * Do a double-checked locking dance to see if there are any 369 * waiters. If we don't see any waiters, we can exit, because 370 * we've already released the lock. If we do see waiters, they 371 * were probably waiting on us... there's a slight chance that 372 * they are waiting on a different thread's ownership of the 373 * lock that happened between the unlock above and this 374 * examination of the queue; if so, no harm is done, as the 375 * waiter will loop and see that the mutex is still locked. 376 * 377 * Note that waiters may have been transferred here from a 378 * condition variable. 379 */ 380 if (self->pt_mutexhint == mutex) 381 self->pt_mutexhint = NULL; 382 383 pthread_spinlock(self, &mutex->ptm_interlock); 384 pthread__unpark_all(self, &mutex->ptm_interlock, &mutex->ptm_blocked); 385 386 return 0; 387} 388 389int 390pthread_mutexattr_init(pthread_mutexattr_t *attr) 391{ 392 struct mutexattr_private *map; 393 394 map = malloc(sizeof(*map)); 395 if (map == NULL) 396 return ENOMEM; 397 398 *map = mutexattr_private_default; 399 400 attr->ptma_magic = _PT_MUTEXATTR_MAGIC; 401 attr->ptma_private = map; 402 403 return 0; 404} 405 406 407int 408pthread_mutexattr_destroy(pthread_mutexattr_t *attr) 409{ 410 411 pthread__error(EINVAL, "Invalid mutex attribute", 412 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 413 414 attr->ptma_magic = _PT_MUTEXATTR_DEAD; 415 if (attr->ptma_private != NULL) 416 free(attr->ptma_private); 417 418 return 0; 419} 420 421 422int 423pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep) 424{ 425 struct mutexattr_private *map; 426 427 pthread__error(EINVAL, "Invalid mutex attribute", 428 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 429 430 map = attr->ptma_private; 431 432 *typep = map->type; 433 434 return 0; 435} 436 437 438int 439pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) 440{ 441 struct mutexattr_private *map; 442 443 pthread__error(EINVAL, "Invalid mutex attribute", 444 attr->ptma_magic == _PT_MUTEXATTR_MAGIC); 445 446 map = attr->ptma_private; 447 448 switch (type) { 449 case PTHREAD_MUTEX_NORMAL: 450 case PTHREAD_MUTEX_ERRORCHECK: 451 case PTHREAD_MUTEX_RECURSIVE: 452 map->type = type; 453 break; 454 455 default: 456 return EINVAL; 457 } 458 459 return 0; 460} 461 462 463static void 464once_cleanup(void *closure) 465{ 466 467 pthread_mutex_unlock((pthread_mutex_t *)closure); 468} 469 470 471int 472pthread_once(pthread_once_t *once_control, void (*routine)(void)) 473{ 474 475 if (once_control->pto_done == 0) { 476 pthread_mutex_lock(&once_control->pto_mutex); 477 pthread_cleanup_push(&once_cleanup, &once_control->pto_mutex); 478 if (once_control->pto_done == 0) { 479 routine(); 480 once_control->pto_done = 1; 481 } 482 pthread_cleanup_pop(1); 483 } 484 485 return 0; 486} 487