1 /* $NetBSD: pthread_mutex.c,v 1.2 2003/01/18 10:34:16 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2003 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, and by Jason R. Thorpe. 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 #include <assert.h> 41 #include <errno.h> 42 #include <limits.h> 43 #include <stdlib.h> 44 45 #include "pthread.h" 46 #include "pthread_int.h" 47 48 static int pthread_mutex_lock_slow(pthread_mutex_t *); 49 50 __strong_alias(__libc_mutex_init,pthread_mutex_init) 51 __strong_alias(__libc_mutex_lock,pthread_mutex_lock) 52 __strong_alias(__libc_mutex_trylock,pthread_mutex_trylock) 53 __strong_alias(__libc_mutex_unlock,pthread_mutex_unlock) 54 __strong_alias(__libc_mutex_destroy,pthread_mutex_destroy) 55 56 __strong_alias(__libc_thr_once,pthread_once) 57 58 struct mutex_private { 59 int type; 60 int recursecount; 61 }; 62 63 static const struct mutex_private mutex_private_default = { 64 PTHREAD_MUTEX_DEFAULT, 65 0, 66 }; 67 68 struct mutexattr_private { 69 int type; 70 }; 71 72 static const struct mutexattr_private mutexattr_private_default = { 73 PTHREAD_MUTEX_DEFAULT, 74 }; 75 76 /* 77 * If the mutex does not already have private data (i.e. was statically 78 * initialized), then give it the default. 79 */ 80 #define GET_MUTEX_PRIVATE(mutex, mp) \ 81 do { \ 82 if (__predict_false((mp = (mutex)->ptm_private) == NULL)) { \ 83 /* LINTED cast away const */ \ 84 mp = ((mutex)->ptm_private = \ 85 (void *)&mutex_private_default); \ 86 } \ 87 } while (/*CONSTCOND*/0) 88 89 int 90 pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) 91 { 92 struct mutexattr_private *map; 93 struct mutex_private *mp; 94 95 #ifdef ERRORCHECK 96 if ((mutex == NULL) || 97 (attr && (attr->ptma_magic != _PT_MUTEXATTR_MAGIC))) 98 return EINVAL; 99 #endif 100 101 if (attr != NULL && (map = attr->ptma_private) != NULL && 102 memcmp(map, &mutexattr_private_default, sizeof(*map)) != 0) { 103 mp = malloc(sizeof(*mp)); 104 if (mp == NULL) 105 return ENOMEM; 106 107 mp->type = map->type; 108 mp->recursecount = 0; 109 } else { 110 /* LINTED cast away const */ 111 mp = (struct mutex_private *) &mutex_private_default; 112 } 113 114 mutex->ptm_magic = _PT_MUTEX_MAGIC; 115 mutex->ptm_owner = NULL; 116 pthread_lockinit(&mutex->ptm_lock); 117 pthread_lockinit(&mutex->ptm_interlock); 118 PTQ_INIT(&mutex->ptm_blocked); 119 mutex->ptm_private = mp; 120 121 return 0; 122 } 123 124 125 int 126 pthread_mutex_destroy(pthread_mutex_t *mutex) 127 { 128 129 #ifdef ERRORCHECK 130 if ((mutex == NULL) || 131 (mutex->ptm_magic != _PT_MUTEX_MAGIC) || 132 (mutex->ptm_lock != __SIMPLELOCK_UNLOCKED)) 133 return EINVAL; 134 #endif 135 136 mutex->ptm_magic = _PT_MUTEX_DEAD; 137 if (mutex->ptm_private != NULL && 138 mutex->ptm_private != (void *)&mutex_private_default) 139 free(mutex->ptm_private); 140 141 return 0; 142 } 143 144 145 /* 146 * Note regarding memory visibility: Pthreads has rules about memory 147 * visibility and mutexes. Very roughly: Memory a thread can see when 148 * it unlocks a mutex can be seen by another thread that locks the 149 * same mutex. 150 * 151 * A memory barrier after a lock and before an unlock will provide 152 * this behavior. This code relies on pthread__simple_lock_try() to issue 153 * a barrier after obtaining a lock, and on pthread__simple_unlock() to 154 * issue a barrier before releasing a lock. 155 */ 156 157 int 158 pthread_mutex_lock(pthread_mutex_t *mutex) 159 { 160 int error; 161 162 #ifdef ERRORCHECK 163 if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC)) 164 return EINVAL; 165 #endif 166 167 /* 168 * Note that if we get the lock, we don't have to deal with any 169 * non-default lock type handling. 170 */ 171 if (__predict_false(pthread__simple_lock_try(&mutex->ptm_lock) == 0)) { 172 error = pthread_mutex_lock_slow(mutex); 173 if (error) 174 return error; 175 } 176 177 /* We have the lock! */ 178 mutex->ptm_owner = pthread__self(); 179 180 return 0; 181 } 182 183 184 static int 185 pthread_mutex_lock_slow(pthread_mutex_t *mutex) 186 { 187 pthread_t self; 188 189 self = pthread__self(); 190 191 while (/*CONSTCOND*/1) { 192 if (pthread__simple_lock_try(&mutex->ptm_lock)) 193 break; /* got it! */ 194 195 /* Okay, didn't look free. Get the interlock... */ 196 pthread_spinlock(self, &mutex->ptm_interlock); 197 /* 198 * The mutex_unlock routine will get the interlock 199 * before looking at the list of sleepers, so if the 200 * lock is held we can safely put ourselves on the 201 * sleep queue. If it's not held, we can try taking it 202 * again. 203 */ 204 if (mutex->ptm_lock == __SIMPLELOCK_LOCKED) { 205 struct mutex_private *mp; 206 207 GET_MUTEX_PRIVATE(mutex, mp); 208 209 if (mutex->ptm_owner == self) { 210 switch (mp->type) { 211 case PTHREAD_MUTEX_ERRORCHECK: 212 pthread_spinunlock(self, 213 &mutex->ptm_interlock); 214 return EDEADLK; 215 216 case PTHREAD_MUTEX_RECURSIVE: 217 /* 218 * It's safe to do this without 219 * holding the interlock, because 220 * we only modify it if we know we 221 * own the mutex. 222 */ 223 pthread_spinunlock(self, 224 &mutex->ptm_interlock); 225 if (mp->recursecount == INT_MAX) 226 return EAGAIN; 227 mp->recursecount++; 228 return 0; 229 } 230 } 231 232 PTQ_INSERT_TAIL(&mutex->ptm_blocked, self, pt_sleep); 233 /* 234 * Locking a mutex is not a cancellation 235 * point, so we don't need to do the 236 * test-cancellation dance. We may get woken 237 * up spuriously by pthread_cancel, though, 238 * but it's okay since we're just going to 239 * retry. 240 */ 241 pthread_spinlock(self, &self->pt_statelock); 242 self->pt_state = PT_STATE_BLOCKED_QUEUE; 243 self->pt_sleepobj = mutex; 244 self->pt_sleepq = &mutex->ptm_blocked; 245 self->pt_sleeplock = &mutex->ptm_interlock; 246 pthread_spinunlock(self, &self->pt_statelock); 247 248 pthread__block(self, &mutex->ptm_interlock); 249 /* interlock is not held when we return */ 250 } else { 251 pthread_spinunlock(self, &mutex->ptm_interlock); 252 } 253 /* Go around for another try. */ 254 } 255 256 return 0; 257 } 258 259 260 int 261 pthread_mutex_trylock(pthread_mutex_t *mutex) 262 { 263 pthread_t self = pthread__self(); 264 265 #ifdef ERRORCHECK 266 if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC)) 267 return EINVAL; 268 #endif 269 270 if (pthread__simple_lock_try(&mutex->ptm_lock) == 0) { 271 struct mutex_private *mp; 272 273 GET_MUTEX_PRIVATE(mutex, mp); 274 275 /* 276 * These tests can be performed without holding the 277 * interlock because these fields are only modified 278 * if we know we own the mutex. 279 */ 280 if (mutex->ptm_owner == self) { 281 switch (mp->type) { 282 case PTHREAD_MUTEX_ERRORCHECK: 283 return EDEADLK; 284 285 case PTHREAD_MUTEX_RECURSIVE: 286 if (mp->recursecount == INT_MAX) 287 return EAGAIN; 288 mp->recursecount++; 289 return 0; 290 } 291 } 292 293 return EBUSY; 294 } 295 296 mutex->ptm_owner = self; 297 298 return 0; 299 } 300 301 302 int 303 pthread_mutex_unlock(pthread_mutex_t *mutex) 304 { 305 struct mutex_private *mp; 306 pthread_t self, blocked; 307 308 self = pthread__self(); 309 310 #ifdef ERRORCHECK 311 if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC)) 312 return EINVAL; 313 314 if (mutex->ptm_lock != __SIMPLELOCK_LOCKED) 315 return EPERM; /* Not exactly the right error. */ 316 #endif 317 318 GET_MUTEX_PRIVATE(mutex, mp); 319 320 /* 321 * These tests can be performed without holding the 322 * interlock because these fields are only modified 323 * if we know we own the mutex. 324 */ 325 switch (mp->type) { 326 case PTHREAD_MUTEX_ERRORCHECK: 327 if (mutex->ptm_owner != self) 328 return EPERM; 329 break; 330 331 case PTHREAD_MUTEX_RECURSIVE: 332 if (mutex->ptm_owner != self) 333 return EPERM; 334 if (mp->recursecount != 0) { 335 mp->recursecount--; 336 return 0; 337 } 338 break; 339 } 340 341 pthread_spinlock(self, &mutex->ptm_interlock); 342 blocked = PTQ_FIRST(&mutex->ptm_blocked); 343 if (blocked) 344 PTQ_REMOVE(&mutex->ptm_blocked, blocked, pt_sleep); 345 mutex->ptm_owner = NULL; 346 pthread__simple_unlock(&mutex->ptm_lock); 347 pthread_spinunlock(self, &mutex->ptm_interlock); 348 349 /* Give the head of the blocked queue another try. */ 350 if (blocked) 351 pthread__sched(self, blocked); 352 353 return 0; 354 } 355 356 int 357 pthread_mutexattr_init(pthread_mutexattr_t *attr) 358 { 359 struct mutexattr_private *map; 360 361 #ifdef ERRORCHECK 362 if (attr == NULL) 363 return EINVAL; 364 #endif 365 366 map = malloc(sizeof(*map)); 367 if (map == NULL) 368 return ENOMEM; 369 370 *map = mutexattr_private_default; 371 372 attr->ptma_magic = _PT_MUTEXATTR_MAGIC; 373 attr->ptma_private = map; 374 375 return 0; 376 } 377 378 379 int 380 pthread_mutexattr_destroy(pthread_mutexattr_t *attr) 381 { 382 383 #ifdef ERRORCHECK 384 if ((attr == NULL) || 385 (attr->ptma_magic != _PT_MUTEXATTR_MAGIC)) 386 return EINVAL; 387 #endif 388 389 attr->ptma_magic = _PT_MUTEXATTR_DEAD; 390 if (attr->ptma_private != NULL) 391 free(attr->ptma_private); 392 393 return 0; 394 } 395 396 397 int 398 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep) 399 { 400 struct mutexattr_private *map; 401 402 #ifdef ERRORCHECK 403 if ((attr == NULL) || 404 (attr->ptma_magic != _PT_MUTEXATTR_MAGIC) || 405 (typep == NULL)) 406 return EINVAL; 407 #endif 408 409 map = attr->ptma_private; 410 411 *typep = map->type; 412 413 return 0; 414 } 415 416 417 int 418 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) 419 { 420 struct mutexattr_private *map; 421 422 #ifdef ERRORCHECK 423 if ((attr == NULL) || 424 (attr->ptma_magic != _PT_MUTEXATTR_MAGIC)) 425 return EINVAL; 426 #endif 427 map = attr->ptma_private; 428 429 switch (type) { 430 case PTHREAD_MUTEX_NORMAL: 431 case PTHREAD_MUTEX_ERRORCHECK: 432 case PTHREAD_MUTEX_RECURSIVE: 433 map->type = type; 434 break; 435 436 default: 437 return EINVAL; 438 } 439 440 return 0; 441 } 442 443 444 int 445 pthread_once(pthread_once_t *once_control, void (*routine)(void)) 446 { 447 448 if (once_control->pto_done == 0) { 449 pthread_mutex_lock(&once_control->pto_mutex); 450 if (once_control->pto_done == 0) { 451 routine(); 452 once_control->pto_done = 1; 453 } 454 pthread_mutex_unlock(&once_control->pto_mutex); 455 } 456 457 return 0; 458 } 459