1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** rpcmutex.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** The support routines for rpcmutex.h abstraction. These should NOT 90** be called directly; use the macros in rpcmutex.h . 91** 92** 93*/ 94 95#include <commonp.h> 96 97#if defined(RPC_MUTEX_DEBUG) || defined(RPC_MUTEX_STATS) 98 99/* 100 * All of the routines return true on success, false on failure. 101 * 102 * There are races present on the modifications of the package wide 103 * statistics as well as the per lock "busy", "try_lock" and "*_assert" 104 * statistics, but we don't really care. We don't want to burden these 105 * "informative" statistics with some other mutex. We're only providing 106 * these stats so we can track gross trends. 107 */ 108 109/* 110 * !!! Since CMA pthreads doesn't provide a "null" handle, create our own. 111 */ 112PRIVATE dcethread* rpc_g_null_thread_handle; 113#define NULL_THREAD rpc_g_null_thread_handle 114 115#define IS_MY_THREAD(t) dcethread_equal((t), my_thread) 116 117/* 118 * Some package wide statistics. 119 */ 120 121INTERNAL rpc_mutex_stats_t mutex_stats = {0}; 122INTERNAL rpc_cond_stats_t cond_stats = {0}; 123 124/* 125 * R P C _ _ M U T E X _ I N I T 126 */ 127 128PRIVATE boolean rpc__mutex_init 129( 130 rpc_mutex_p_t mp 131) 132{ 133 mp->stats.busy = 0; 134 mp->stats.lock = 0; 135 mp->stats.try_lock = 0; 136 mp->stats.unlock = 0; 137 mp->stats.init = 1; 138 mp->stats.deletes = 0; 139 mp->stats.lock_assert = 0; 140 mp->stats.unlock_assert = 0; 141 mp->is_locked = false; 142 mp->owner = NULL_THREAD; 143 mp->locker_file = "never_locked"; 144 mp->locker_line = 0; 145 if (dcethread_mutex_init(&mp->m, NULL) != 0) { 146 return (false); 147 } 148 mutex_stats.init++; 149 return(true); 150} 151 152/* 153 * R P C _ _ M U T E X _ D E L E T E 154 */ 155 156PRIVATE boolean rpc__mutex_delete 157( 158 rpc_mutex_p_t mp 159) 160{ 161 mp->stats.deletes++; 162 mutex_stats.deletes++; 163 dcethread_mutex_destroy(&mp->m); 164 return(true); 165} 166 167/* 168 * R P C _ _ M U T E X _ L O C K 169 */ 170 171PRIVATE boolean rpc__mutex_lock 172( 173 rpc_mutex_p_t mp, 174 char *file, 175 int line 176) 177{ 178 dcethread* my_thread = NULL_THREAD; 179 boolean is_locked = mp->is_locked; 180 boolean dbg; 181 182 dbg = RPC_DBG(rpc_es_dbg_mutex, 5); 183 if (dbg) 184 { 185 my_thread = dcethread_self(); 186 if (is_locked && IS_MY_THREAD(mp->owner)) 187 { 188 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 189 ("(rpc__mutex_lock) deadlock with self at %s/%d (previous lock at %s/%d)\n", 190 file, line, mp->locker_file, mp->locker_line)); 191 return(false); 192 } 193 } 194 dcethread_mutex_lock(&mp->m); 195 mp->is_locked = true; 196 if (dbg) 197 { 198 mp->owner = my_thread; 199 mp->locker_file = file; 200 mp->locker_line = line; 201 } 202 if (is_locked) 203 { 204 mp->stats.busy++; 205 mutex_stats.busy++; 206 } 207 mp->stats.lock++; 208 mutex_stats.lock++; 209 return(true); 210} 211 212/* 213 * R P C _ _ M U T E X _ T R Y _ L O C K 214 */ 215 216PRIVATE boolean rpc__mutex_try_lock 217( 218 rpc_mutex_p_t mp, 219 boolean *bp, 220 char *file, 221 int line 222) 223{ 224 dcethread* my_thread = NULL_THREAD; 225 boolean is_locked = mp->is_locked; 226 boolean dbg; 227 228 dbg = RPC_DBG(rpc_es_dbg_mutex, 5); 229 if (dbg) 230 { 231 my_thread = dcethread_self(); 232 if (is_locked && IS_MY_THREAD(mp->owner)) 233 { 234 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 235 ("(rpc__mutex_try_lock) deadlock with self at %s/%d (previous lock at %s/%d)\n", 236 file, line, mp->locker_file, mp->locker_line)); 237 return(false); 238 } 239 } 240 *bp = dcethread_mutex_trylock(&mp->m); 241 if (*bp) 242 { 243 mp->is_locked = true; 244 if (dbg) 245 { 246 mp->owner = my_thread; 247 mp->locker_file = file; 248 mp->locker_line = line; 249 } 250 } 251 else 252 { 253 mp->stats.busy++; 254 mutex_stats.busy++; 255 } 256 mp->stats.try_lock++; 257 mutex_stats.try_lock++; 258 return(true); 259} 260 261/* 262 * R P C _ _ M U T E X _ U N L O C K 263 */ 264 265PRIVATE boolean rpc__mutex_unlock 266( 267 rpc_mutex_p_t mp 268) 269{ 270 dcethread* my_thread; 271 boolean is_locked = mp->is_locked; 272 boolean dbg; 273 274 dbg = RPC_DBG(rpc_es_dbg_mutex, 5); 275 if (dbg) 276 { 277 if (! is_locked) 278 { 279 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 280 ("(rpc__mutex_unlock) not locked\n")); 281 return(false); 282 } 283 my_thread = dcethread_self(); 284 if (!IS_MY_THREAD(mp->owner)) 285 { 286 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 287 ("(rpc__mutex_unlock) not owner (owner at %s/%d)\n", 288 mp->locker_file, mp->locker_line)); 289 return(false); 290 } 291 mp->owner = NULL_THREAD; 292 } 293 mp->stats.unlock++; 294 mutex_stats.unlock++; 295 mp->is_locked = false; 296 dcethread_mutex_unlock(&mp->m); 297 return(true); 298} 299 300/* 301 * R P C _ _ M U T E X _ L O C K _ A S S E R T 302 * 303 * assert that we are the owner of the lock. 304 */ 305 306PRIVATE boolean rpc__mutex_lock_assert 307( 308 rpc_mutex_p_t mp 309) 310{ 311 dcethread* my_thread; 312 boolean is_locked = mp->is_locked; 313 boolean dbg; 314 315 dbg = RPC_DBG(rpc_es_dbg_mutex, 5); 316 mp->stats.lock_assert++; 317 mutex_stats.lock_assert++; 318 if (dbg) 319 { 320 if (! is_locked) 321 { 322 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 323 ("(rpc__mutex_lock_assert) not locked\n")); 324 return(false); 325 } 326 my_thread = dcethread_self(); 327 if (!IS_MY_THREAD(mp->owner)) 328 { 329 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 330 ("(rpc__mutex_lock_assert) not owner\n")); 331 return(false); 332 } 333 } 334 return(true); 335} 336 337/* 338 * R P C _ _ M U T E X _ U N L O C K _ A S S E R T 339 * 340 * assert that we are not the owner of the lock. 341 */ 342 343PRIVATE boolean rpc__mutex_unlock_assert 344( 345 rpc_mutex_p_t mp 346) 347{ 348 dcethread* my_thread; 349 boolean is_locked = mp->is_locked; 350 boolean dbg; 351 352 dbg = RPC_DBG(rpc_es_dbg_mutex, 5); 353 mp->stats.unlock_assert++; 354 mutex_stats.unlock_assert++; 355 if (dbg) 356 { 357 if (! is_locked) 358 return(true); 359 my_thread = dcethread_self(); 360 if (IS_MY_THREAD(mp->owner)) 361 { 362 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 363 ("(rpc__mutex_unlock_assert) owner\n")); 364 return(false); 365 } 366 } 367 return(true); 368} 369 370/* 371 * R P C _ _ C O N D _ I N I T 372 * 373 * The "mp" is the mutex that is associated with the cv. 374 */ 375 376boolean rpc__cond_init 377( 378 rpc_cond_p_t cp, 379 rpc_mutex_p_t mp 380) 381{ 382 cp->stats.init = 1; 383 cp->stats.deletes = 0; 384 cp->stats.wait = 0; 385 cp->stats.signals = 0; 386 cp->mp = mp; 387 dcethread_cond_init(&cp->c, NULL); 388 cond_stats.init++; 389 return(true); 390} 391 392/* 393 * R P C _ _ C O N D _ D E L E T E 394 */ 395 396boolean rpc__cond_delete 397( 398 rpc_cond_p_t cp, 399 rpc_mutex_p_t mp ATTRIBUTE_UNUSED 400) 401{ 402 cp->stats.deletes++; 403 cond_stats.deletes++; 404 dcethread_cond_destroy(&cp->c); 405 return(true); 406} 407 408/* 409 * R P C _ _ C O N D _ W A I T 410 * 411 * The mutex is automatically released and reacquired by the wait. 412 */ 413 414boolean rpc__cond_wait 415( 416 rpc_cond_p_t cp, 417 rpc_mutex_p_t mp, 418 char *file, 419 int line 420) 421{ 422 dcethread* my_thread; 423 volatile boolean dbg; 424 425 DO_NOT_CLOBBER(my_thread); 426 427 cp->stats.wait++; 428 cond_stats.wait++; 429 dbg = RPC_DBG(rpc_es_dbg_mutex, 5); 430 if (dbg) 431 { 432 if (! rpc__mutex_lock_assert(mp)) 433 { 434 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 435 ("(rpc__cond_wait) mutex usage error\n")); 436 return(false); 437 } 438 if (cp->mp != mp) 439 { 440 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 441 ("(rpc__cond_wait) incorrect mutex\n")); 442 return(false); 443 } 444 my_thread = dcethread_self(); 445 mp->owner = NULL_THREAD; 446 } 447 mp->is_locked = false; 448 TRY 449 dcethread_cond_wait_throw(&cp->c, &mp->m); 450 CATCH_ALL 451 mp->is_locked = true; 452 if (dbg) 453 { 454 mp->owner = my_thread; 455 mp->locker_file = file; 456 mp->locker_line = line; 457 } 458 RERAISE; 459 ENDTRY 460 mp->is_locked = true; 461 if (dbg) 462 { 463 mp->owner = my_thread; 464 mp->locker_file = file; 465 mp->locker_line = line; 466 } 467 return(true); 468} 469 470/* 471 * R P C _ _ C O N D _ T I M E D _ W A I T 472 * 473 * The mutex is automatically released and reacquired by the wait. 474 */ 475 476boolean rpc__cond_timed_wait 477( 478 rpc_cond_p_t cp, 479 rpc_mutex_p_t mp, 480 struct timespec *wtime, 481 char *file, 482 int line 483) 484{ 485 dcethread* my_thread; 486 volatile boolean dbg; 487 488 DO_NOT_CLOBBER(my_thread); 489 490 cp->stats.wait++; 491 cond_stats.wait++; 492 dbg = RPC_DBG(rpc_es_dbg_mutex, 5); 493 if (dbg) 494 { 495 if (! rpc__mutex_lock_assert(mp)) 496 { 497 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 498 ("(rpc__cond_wait) mutex usage error\n")); 499 return(false); 500 } 501 if (cp->mp != mp) 502 { 503 RPC_DBG_PRINTF(rpc_e_dbg_mutex, 1, 504 ("(rpc__cond_wait) incorrect mutex\n")); 505 return(false); 506 } 507 my_thread = dcethread_self(); 508 mp->owner = NULL_THREAD; 509 } 510 mp->is_locked = false; 511 TRY { 512 dcethread_cond_timedwait_throw(&cp->c, &mp->m, wtime); 513 } 514 CATCH_ALL 515 mp->is_locked = true; 516 if (dbg) 517 { 518 mp->owner = my_thread; 519 mp->locker_file = file; 520 mp->locker_line = line; 521 } 522 RERAISE; 523 ENDTRY 524 mp->is_locked = true; 525 if (dbg) 526 { 527 mp->owner = my_thread; 528 mp->locker_file = file; 529 mp->locker_line = line; 530 } 531 return(true); 532} 533 534/* 535 * R P C _ _ C O N D _ S I G N A L 536 * 537 * It's not clear if it's legal to signal w/o holding the lock 538 * (in the runtime's context); CMA clearly doesn't require it. 539 */ 540 541boolean rpc__cond_signal 542( 543 rpc_cond_p_t cp, 544 rpc_mutex_p_t mp ATTRIBUTE_UNUSED 545) 546{ 547 cp->stats.signals++; 548 cond_stats.signals++; 549 dcethread_cond_signal(&cp->c); 550 return(true); 551} 552 553/* 554 * R P C _ _ C O N D _ B R O A D C A S T 555 * 556 * It's not clear if it's legal to broadcast w/o holding the lock 557 * (in the runtime's context); CMA clearly doesn't require it. 558 */ 559 560boolean rpc__cond_broadcast 561( 562 rpc_cond_p_t cp, 563 rpc_mutex_p_t mp ATTRIBUTE_UNUSED 564) 565{ 566 cp->stats.signals++; 567 cond_stats.signals++; 568 dcethread_cond_broadcast(&cp->c); 569 return(true); 570} 571 572#else 573#ifdef MIREK_NOT_DEFINED 574INTERNAL void rpc__mutex_none (void) 575{ 576} 577#endif 578#endif /* defined(RPC_MUTEX_DEBUG) || defined(RPC_MUTEX_STATS) */ 579