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** rpclist.c 82** 83** FACILITY: 84** 85** Remote Procedure Call (RPC) 86** 87** ABSTRACT: 88** 89** This module contains routines to maintain lookaside list descriptors. 90** 91** 92*/ 93 94#include <commonp.h> 95 96GLOBAL rpc_lookaside_rcb_t rpc_g_lookaside_rcb = 97{ 98 RPC_C_LOOKASIDE_RES, 99 0, 100 RPC_C_LOOKASIDE_RES_MAX_WAIT, 101 RPC_C_LOOKASIDE_RES_WAIT, 102 RPC_MUTEX_INITIALIZER, 103 RPC_COND_INITIALIZER 104}; 105 106/* 107**++ 108** 109** ROUTINE NAME: rpc__list_desc_init 110** 111** SCOPE: PRIVATE - declared in rpclist.h 112** 113** DESCRIPTION: 114** 115** Initializes a lookaside list descriptor. The maximum size and element 116** size are set as part of this operation. 117** 118** INPUTS: 119** 120** list_desc List descriptor which is to be initialized. 121** 122** max_size The maximum length of the lookaside list. 123** 124** element_size The size of each list element. 125** 126** element_type The type of each list element (from rpcmem.h). 127** 128** alloc_rtn The element specific routine to be 129** called when allocating from heap. If this is 130** NULL no routine will be called. 131** 132** free_rtn The element specific alloc routine to be 133** called when freeing to heap. If this is NULL 134** no routine will be called. 135** 136** mutex The list specific mutex used to protect the 137** integrity of the list. If the NULL is 138** provided the global lookaside list mutex and 139** condition variable will be used.It is used when 140** blocking on or signalling condition 141** variables. Note that the neither 142** rpc__list_element_alloc or _free ever 143** explicitly acquires or releases this mutex. 144** This must be done by the caller. 145** 146** cond The list specific condition variable 147** associated with the above mutex. Valid iff 148** mutex is not NULL. 149** 150** INPUTS/OUTPUTS: none 151** 152** OUTPUTS: none 153** 154** IMPLICIT INPUTS: none 155** 156** IMPLICIT OUTPUTS: none 157** 158** FUNCTION VALUE: none 159** 160** SIDE EFFECTS: none 161** 162**-- 163**/ 164 165PRIVATE void rpc__list_desc_init 166( 167 rpc_list_desc_p_t list_desc, 168 unsigned32 max_size, 169 unsigned32 element_size, 170 unsigned32 element_type, 171 rpc_list_element_alloc_fn_t alloc_rtn, 172 rpc_list_element_free_fn_t free_rtn, 173 rpc_mutex_p_t mutex, 174 rpc_cond_p_t cond 175) 176{ 177 list_desc->max_size = max_size; 178 list_desc->cur_size = 0; 179 list_desc->element_size = element_size; 180 list_desc->element_type = element_type; 181 list_desc->alloc_rtn = alloc_rtn; 182 list_desc->free_rtn = free_rtn; 183 if (mutex == NULL) 184 { 185 list_desc->use_global_mutex = true; 186 } 187 else 188 { 189 list_desc->use_global_mutex = false; 190 list_desc->mutex = mutex; 191 list_desc->cond = cond; 192 } 193 RPC_LIST_INIT (list_desc->list_head); 194} 195 196/* 197**++ 198** 199** ROUTINE NAME: rpc__list_element_alloc 200** 201** SCOPE: PRIVATE - declared in rpclist.h 202** 203** DESCRIPTION: 204** 205** Remove the first element in the lookaside list and return a pointer 206** to it. If the lookaside list is empty, an element of the size 207** indicated in the lookaside list descriptor will be allocated from 208** the heap. 209** 210** INPUTS: none 211** 212** list_desc The lookaside list descriptor. 213** 214** block true if the alloc should block for heap to become free 215** false if it is not to block 216** 217** INPUTS/OUTPUTS: none 218** 219** OUTPUTS: none 220** 221** IMPLICIT INPUTS: none 222** 223** IMPLICIT OUTPUTS: none 224** 225** FUNCTION VALUE: 226** 227** return Pointer to the allocated list element. 228** 229** SIDE EFFECTS: none 230** 231**-- 232**/ 233 234PRIVATE dce_pointer_t rpc__list_element_alloc 235( 236 rpc_list_desc_p_t list_desc, 237 boolean32 block 238) 239{ 240 volatile dce_pointer_t element = NULL; 241 unsigned32 wait_cnt; 242 struct timespec delta; 243 struct timespec abstime; 244 245 RPC_LOG_LIST_ELT_ALLOC_NTR; 246 247 for (wait_cnt = 0; 248 wait_cnt < rpc_g_lookaside_rcb.max_wait_times; 249 wait_cnt++) 250 { 251 /* 252 * Acquire the global resource control lock for all lookaside 253 * lists if the caller doesn't have their own lock. 254 */ 255 if (list_desc->use_global_mutex) 256 { 257 RPC_MUTEX_LOCK (rpc_g_lookaside_rcb.res_lock); 258 } 259 260 /* 261 * Try allocating a structure off the lookaside list given. 262 */ 263 if (list_desc->cur_size > 0) 264 { 265#define DEBUG 1 266#ifdef DEBUG 267 if (list_desc->list_head.next == NULL) 268 { 269 /* 270 * rpc_m_lookaside_corrupt 271 * "(%s) Lookaside list is corrupted" 272 */ 273 rpc_dce_svc_printf ( 274 __FILE__, __LINE__, 275 "%s", 276 rpc_svc_general, 277 svc_c_sev_fatal | svc_c_action_abort, 278 rpc_m_lookaside_corrupt, 279 "rpc__list_element_alloc" ); 280 } 281#endif 282 list_desc->cur_size--; 283 RPC_LIST_REMOVE_HEAD (list_desc->list_head, element, dce_pointer_t); 284 285 /* 286 * Release the global resource control lock for all lookaside 287 * lists if the caller doesn't have their own lock. 288 */ 289 if (list_desc->use_global_mutex) 290 { 291 RPC_MUTEX_UNLOCK (rpc_g_lookaside_rcb.res_lock); 292 } 293 break; 294 } 295 else 296 { 297 /* 298 * Release the global resource control lock if the 299 * caller doesn't have their own lock for all lookaside lists 300 * since the structure was available on the lookaside list. 301 * 302 * We do it now because allocating an element from heap is a relatively 303 * time consuming operation. 304 */ 305 if (list_desc->use_global_mutex) 306 { 307 RPC_MUTEX_UNLOCK (rpc_g_lookaside_rcb.res_lock); 308 } 309 310 /* 311 * The lookaside list is empty. Try and allocate from 312 * heap. 313 */ 314 RPC_MEM_ALLOC (element, 315 dce_pointer_t, 316 list_desc->element_size, 317 list_desc->element_type, 318 RPC_C_MEM_NOWAIT); 319 320 if (element == NULL) 321 { 322 /* 323 * The heap allocate failed. If the caller indicated 324 * that we should not block return right now. 325 */ 326 if (block == false) 327 { 328 break; 329 } 330 331 delta.tv_sec = rpc_g_lookaside_rcb.wait_time; 332 delta.tv_nsec = 0; 333 dcethread_get_expiration (&delta, &abstime); 334 335 /* 336 * If we are using the global lookaside list lock 337 * then reaquire the global lookaside list lock and 338 * wait on the global lookaside list condition 339 * variable otherwise use the caller's mutex and 340 * condition variable. 341 */ 342 if (list_desc->use_global_mutex) 343 { 344 RPC_MUTEX_LOCK (rpc_g_lookaside_rcb.res_lock); 345 RPC_COND_TIMED_WAIT (rpc_g_lookaside_rcb.wait_flg, 346 rpc_g_lookaside_rcb.res_lock, 347 &abstime); 348 RPC_MUTEX_UNLOCK (rpc_g_lookaside_rcb.res_lock); 349 } 350 else 351 { 352 RPC_COND_TIMED_WAIT (*list_desc->cond, 353 *list_desc->mutex, 354 &abstime); 355 } 356 357 /* 358 * Try to allocate the structure again. 359 */ 360 continue; 361 } 362 else 363 { 364 /* 365 * The RPC_MEM_ALLOC succeeded. If an alloc routine 366 * was specified when the lookaside list was inited 367 * call it now. 368 */ 369 if (list_desc->alloc_rtn != NULL) 370 { 371 /* 372 * Catch any exceptions which may occur in the 373 * list-specific alloc routine. Any exceptions 374 * will be caught and the memory will be freed. 375 */ 376 DCETHREAD_TRY 377 { 378 (*list_desc->alloc_rtn) (element); 379 } 380 DCETHREAD_CATCH_ALL(THIS_CATCH) 381 { 382 RPC_MEM_FREE (element, list_desc->element_type); 383 element = NULL; 384 /* 385 * rpc_m_call_failed_no_status 386 * "%s failed" 387 */ 388 rpc_dce_svc_printf ( 389 __FILE__, __LINE__, 390 "%s", 391 rpc_svc_general, 392 svc_c_sev_fatal | svc_c_action_abort, 393 rpc_m_call_failed_no_status, 394 "rpc__list_element_alloc/(*list_desc->alloc_rtn)(element)" ); 395 } 396 DCETHREAD_ENDTRY 397 } 398 break; 399 } 400 } 401 } 402 if (element != NULL) { 403 ((rpc_list_p_t)element)->next = NULL; 404 ((rpc_list_p_t)element)->last = NULL; 405 } 406 RPC_LOG_LIST_ELT_ALLOC_XIT; 407 return (element); 408} 409 410 411/* 412**++ 413** 414** ROUTINE NAME: rpc__list_desc_free 415** 416** SCOPE: PRIVATE - declared in rpclist.h 417** 418** DESCRIPTION: 419** 420** Returns an element to the lookaside list. If this would result 421** in the current size of the lookaside list becoming greater than 422** the maximum size, the element will be returned to the heap instead. 423** 424** INPUTS: 425** 426** list_desc The list descriptor. 427** 428** list_element Pointer to the element to be freed. 429** 430** INPUTS/OUTPUTS: none 431** 432** OUTPUTS: none 433** 434** IMPLICIT INPUTS: none 435** 436** IMPLICIT OUTPUTS: none 437** 438** FUNCTION VALUE: none 439** 440** SIDE EFFECTS: none 441** 442**-- 443**/ 444 445PRIVATE void rpc__list_element_free 446( 447 rpc_list_desc_p_t list_desc, 448 dce_pointer_t list_element 449) 450{ 451 RPC_LOG_LIST_ELT_FREE_NTR; 452 453 assert(list_desc != NULL); 454 assert(list_element != NULL); 455 456 /* 457 * Acquire the global resource control lock for all lookaside 458 * lists if the caller doesn't have their own lock. 459 */ 460 if (list_desc->use_global_mutex) 461 { 462 RPC_MUTEX_LOCK (rpc_g_lookaside_rcb.res_lock); 463 } 464 465 if (list_desc->cur_size < list_desc->max_size) 466 { 467 list_desc->cur_size++; 468 469 RPC_LIST_ADD_TAIL (list_desc->list_head, list_element, dce_pointer_t); 470 471 /* 472 * Now check whether any other thread is waiting for a lookaside list 473 * structure. 474 */ 475 if (rpc_g_lookaside_rcb.waiter_cnt > 0) 476 { 477 /* 478 * There are waiters. Signal the global lookaside list 479 * condition variable if the caller doesn't have one. 480 * Otherwise signal the caller provided condition 481 * variable. 482 */ 483 if (list_desc->use_global_mutex) 484 { 485 RPC_COND_SIGNAL (rpc_g_lookaside_rcb.wait_flg, 486 rpc_g_lookaside_rcb.res_lock); 487 } 488 else 489 { 490 RPC_COND_SIGNAL (*list_desc->cond, 491 *list_desc->mutex); 492 } 493 } 494 495 /* 496 * Release the global resource control lock for all lookaside 497 * lists if the caller doesn't have their own lock 498 * since the structure has now been added to the list. 499 */ 500 if (list_desc->use_global_mutex) 501 { 502 RPC_MUTEX_UNLOCK (rpc_g_lookaside_rcb.res_lock); 503 } 504 } 505 else 506 { 507 /* 508 * If a free routine was specified when this lookaside list 509 * was inited call it now. 510 */ 511 if (list_desc->free_rtn != NULL) 512 { 513 (list_desc->free_rtn) (list_element); 514 } 515 516 /* 517 * Release the global resource control lock for all 518 * lookaside lists if the caller doesn't have their own lock. 519 * 520 * We do it now because freeing an element to the heap is a relatively 521 * time consuming operation. 522 */ 523 if (list_desc->use_global_mutex) 524 { 525 RPC_MUTEX_UNLOCK (rpc_g_lookaside_rcb.res_lock); 526 } 527 528 memset (list_element, 0, list_desc->element_size); 529 RPC_MEM_FREE (list_element, list_desc->element_type); 530 } 531 532 RPC_LOG_LIST_ELT_FREE_XIT; 533} 534 535/* 536**++ 537** 538** ROUTINE NAME: rpc__list_fork_handler 539** 540** SCOPE: PRIVATE - declared in rpclist.h 541** 542** DESCRIPTION: 543** 544** Perform fork-related processing, depending on what stage of the 545** fork we are currently in. 546** 547** INPUTS: 548** 549** stage The current stage of the fork process. 550** 551** INPUTS/OUTPUTS: none 552** 553** OUTPUTS: none 554** 555** IMPLICIT INPUTS: none 556** 557** IMPLICIT OUTPUTS: none 558** 559** FUNCTION VALUE: none 560** 561** SIDE EFFECTS: none 562** 563**-- 564**/ 565 566PRIVATE void rpc__list_fork_handler 567( 568 rpc_fork_stage_id_t stage 569) 570{ 571 switch ((int)stage) 572 { 573 case RPC_C_PREFORK: 574 break; 575 case RPC_C_POSTFORK_PARENT: 576 break; 577 case RPC_C_POSTFORK_CHILD: 578 /* 579 * Reset the lookaside waiter's count. 580 */ 581 rpc_g_lookaside_rcb.waiter_cnt = 0; 582 break; 583 } 584} 585