1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "alloc_cache.h" 29 #include "alloc_impl.h" 30 #include "alloc_arena.h" 31 #include "internal/once.h" 32 #include "sal/macros.h" 33 #include "osl/diagnose.h" 34 35 #ifndef INCLUDED_STRING_H 36 #include <string.h> 37 #endif 38 39 #ifndef INCLUDED_STDIO_H 40 #include <stdio.h> 41 #endif 42 43 #ifdef OS2 44 #undef OSL_TRACE 45 #define OSL_TRACE 1 ? ((void)0) : _OSL_GLOBAL osl_trace 46 #endif 47 48 /* ================================================================= * 49 * 50 * cache internals. 51 * 52 * ================================================================= */ 53 54 /** g_cache_list 55 * @internal 56 */ 57 struct rtl_cache_list_st 58 { 59 rtl_memory_lock_type m_lock; 60 rtl_cache_type m_cache_head; 61 62 #if defined(SAL_UNX) || defined(SAL_OS2) 63 pthread_t m_update_thread; 64 pthread_cond_t m_update_cond; 65 #elif defined(SAL_W32) 66 HANDLE m_update_thread; 67 HANDLE m_update_cond; 68 #endif /* SAL_UNX || SAL_W32 */ 69 int m_update_done; 70 }; 71 72 static struct rtl_cache_list_st g_cache_list; 73 74 75 /** gp_cache_arena 76 * provided for cache_type allocations, and hash_table resizing. 77 * 78 * @internal 79 */ 80 static rtl_arena_type * gp_cache_arena = 0; 81 82 83 /** gp_cache_magazine_cache 84 * @internal 85 */ 86 static rtl_cache_type * gp_cache_magazine_cache = 0; 87 88 89 /** gp_cache_slab_cache 90 * @internal 91 */ 92 static rtl_cache_type * gp_cache_slab_cache = 0; 93 94 95 /** gp_cache_bufctl_cache 96 * @internal 97 */ 98 static rtl_cache_type * gp_cache_bufctl_cache = 0; 99 100 101 /** rtl_cache_init() 102 * @internal 103 */ 104 static int 105 rtl_cache_init (void); 106 107 108 /* ================================================================= */ 109 110 /** RTL_CACHE_HASH_INDEX() 111 */ 112 #define RTL_CACHE_HASH_INDEX_IMPL(a, s, q, m) \ 113 ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m)) 114 115 #define RTL_CACHE_HASH_INDEX(cache, addr) \ 116 RTL_CACHE_HASH_INDEX_IMPL((addr), (cache)->m_hash_shift, (cache)->m_type_shift, ((cache)->m_hash_size - 1)) 117 118 119 /** rtl_cache_hash_rescale() 120 */ 121 static void 122 rtl_cache_hash_rescale ( 123 rtl_cache_type * cache, 124 sal_Size new_size 125 ) 126 { 127 rtl_cache_bufctl_type ** new_table; 128 sal_Size new_bytes; 129 130 new_bytes = new_size * sizeof(rtl_cache_bufctl_type*); 131 new_table = (rtl_cache_bufctl_type**)rtl_arena_alloc(gp_cache_arena, &new_bytes); 132 133 if (new_table != 0) 134 { 135 rtl_cache_bufctl_type ** old_table; 136 sal_Size old_size, i; 137 138 memset (new_table, 0, new_bytes); 139 140 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); 141 142 old_table = cache->m_hash_table; 143 old_size = cache->m_hash_size; 144 145 OSL_TRACE( 146 "rtl_cache_hash_rescale(\"%s\"): " 147 "nbuf: % " PRIu64 " (ave: %" PRIu64 "), frees: %" PRIu64 " " 148 "[old_size: %lu, new_size: %lu]", 149 cache->m_name, 150 cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free, 151 (cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free) >> cache->m_hash_shift, 152 cache->m_slab_stats.m_free, 153 old_size, new_size); 154 155 cache->m_hash_table = new_table; 156 cache->m_hash_size = new_size; 157 cache->m_hash_shift = highbit(cache->m_hash_size) - 1; 158 159 for (i = 0; i < old_size; i++) 160 { 161 rtl_cache_bufctl_type * curr = old_table[i]; 162 while (curr != 0) 163 { 164 rtl_cache_bufctl_type * next = curr->m_next; 165 rtl_cache_bufctl_type ** head; 166 167 head = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, curr->m_addr)]); 168 curr->m_next = (*head); 169 (*head) = curr; 170 171 curr = next; 172 } 173 old_table[i] = 0; 174 } 175 176 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); 177 178 if (old_table != cache->m_hash_table_0) 179 { 180 sal_Size old_bytes = old_size * sizeof(rtl_cache_bufctl_type*); 181 rtl_arena_free (gp_cache_arena, old_table, old_bytes); 182 } 183 } 184 } 185 186 /** rtl_cache_hash_insert() 187 */ 188 static RTL_MEMORY_INLINE sal_uIntPtr 189 rtl_cache_hash_insert ( 190 rtl_cache_type * cache, 191 rtl_cache_bufctl_type * bufctl 192 ) 193 { 194 rtl_cache_bufctl_type ** ppHead; 195 196 ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, bufctl->m_addr)]); 197 198 bufctl->m_next = (*ppHead); 199 (*ppHead) = bufctl; 200 201 return (bufctl->m_addr); 202 } 203 204 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) 205 #pragma inline(rtl_cache_hash_insert) 206 #endif /* __SUNPRO_C */ 207 208 209 /** rtl_cache_hash_remove() 210 */ 211 static rtl_cache_bufctl_type * 212 rtl_cache_hash_remove ( 213 rtl_cache_type * cache, 214 sal_uIntPtr addr 215 ) 216 { 217 rtl_cache_bufctl_type ** ppHead; 218 rtl_cache_bufctl_type * bufctl; 219 sal_Size lookups = 0; 220 221 ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, addr)]); 222 while ((bufctl = *ppHead) != 0) 223 { 224 if (bufctl->m_addr == addr) 225 { 226 *ppHead = bufctl->m_next, bufctl->m_next = 0; 227 break; 228 } 229 230 lookups += 1; 231 ppHead = &(bufctl->m_next); 232 } 233 234 OSL_ASSERT (bufctl != 0); /* bad free */ 235 236 if (lookups > 1) 237 { 238 sal_Size nbuf = (sal_Size)(cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free); 239 if (nbuf > 4 * cache->m_hash_size) 240 { 241 if (!(cache->m_features & RTL_CACHE_FEATURE_RESCALE)) 242 { 243 sal_Size ave = nbuf >> cache->m_hash_shift; 244 sal_Size new_size = cache->m_hash_size << (highbit(ave) - 1); 245 246 cache->m_features |= RTL_CACHE_FEATURE_RESCALE; 247 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); 248 rtl_cache_hash_rescale (cache, new_size); 249 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); 250 cache->m_features &= ~RTL_CACHE_FEATURE_RESCALE; 251 } 252 } 253 } 254 255 return (bufctl); 256 } 257 258 /* ================================================================= */ 259 260 /** RTL_CACHE_SLAB() 261 */ 262 #define RTL_CACHE_SLAB(addr, size) \ 263 (((rtl_cache_slab_type*)(RTL_MEMORY_P2END((sal_uIntPtr)(addr), (size)))) - 1) 264 265 266 /** rtl_cache_slab_constructor() 267 */ 268 static int 269 rtl_cache_slab_constructor (void * obj, void * arg) 270 { 271 rtl_cache_slab_type * slab = (rtl_cache_slab_type*)(obj); 272 273 (void) arg; /* unused */ 274 275 QUEUE_START_NAMED(slab, slab_); 276 slab->m_ntypes = 0; 277 278 return (1); 279 } 280 281 282 /** rtl_cache_slab_destructor() 283 */ 284 static void 285 rtl_cache_slab_destructor (void * obj, void * arg) 286 { 287 #if OSL_DEBUG_LEVEL == 0 288 (void) obj; /* unused */ 289 #else /* OSL_DEBUG_LEVEL */ 290 rtl_cache_slab_type * slab = (rtl_cache_slab_type*)(obj); 291 292 /* assure removed from queue(s) */ 293 OSL_ASSERT(QUEUE_STARTED_NAMED(slab, slab_)); 294 295 /* assure no longer referenced */ 296 OSL_ASSERT(slab->m_ntypes == 0); 297 #endif /* OSL_DEBUG_LEVEL */ 298 299 (void) arg; /* unused */ 300 } 301 302 303 /** rtl_cache_slab_create() 304 * 305 * @precond cache->m_slab_lock released. 306 */ 307 static rtl_cache_slab_type * 308 rtl_cache_slab_create ( 309 rtl_cache_type * cache 310 ) 311 { 312 rtl_cache_slab_type * slab = 0; 313 void * addr; 314 sal_Size size; 315 316 size = cache->m_slab_size; 317 addr = rtl_arena_alloc (cache->m_source, &size); 318 if (addr != 0) 319 { 320 OSL_ASSERT(size >= cache->m_slab_size); 321 322 if (cache->m_features & RTL_CACHE_FEATURE_HASH) 323 { 324 /* allocate slab struct from slab cache */ 325 OSL_ASSERT (cache != gp_cache_slab_cache); 326 slab = (rtl_cache_slab_type*)rtl_cache_alloc (gp_cache_slab_cache); 327 } 328 else 329 { 330 /* construct embedded slab struct */ 331 slab = RTL_CACHE_SLAB(addr, cache->m_slab_size); 332 (void) rtl_cache_slab_constructor (slab, 0); 333 } 334 if (slab != 0) 335 { 336 slab->m_data = (sal_uIntPtr)(addr); 337 338 /* dynamic freelist initialization */ 339 slab->m_bp = slab->m_data; 340 slab->m_sp = 0; 341 } 342 else 343 { 344 rtl_arena_free (cache->m_source, addr, size); 345 } 346 } 347 return (slab); 348 } 349 350 351 /** rtl_cache_slab_destroy() 352 * 353 * @precond cache->m_slab_lock released. 354 */ 355 static void 356 rtl_cache_slab_destroy ( 357 rtl_cache_type * cache, 358 rtl_cache_slab_type * slab 359 ) 360 { 361 void * addr = (void*)(slab->m_data); 362 sal_Size refcnt = slab->m_ntypes; slab->m_ntypes = 0; 363 364 if (cache->m_features & RTL_CACHE_FEATURE_HASH) 365 { 366 /* cleanup bufctl(s) for free buffer(s) */ 367 sal_Size ntypes = (slab->m_bp - slab->m_data) / cache->m_type_size; 368 for (ntypes -= refcnt; slab->m_sp != 0; ntypes--) 369 { 370 rtl_cache_bufctl_type * bufctl = slab->m_sp; 371 372 /* pop from freelist */ 373 slab->m_sp = bufctl->m_next, bufctl->m_next = 0; 374 375 /* return bufctl struct to bufctl cache */ 376 rtl_cache_free (gp_cache_bufctl_cache, bufctl); 377 } 378 OSL_ASSERT(ntypes == 0); 379 380 /* return slab struct to slab cache */ 381 rtl_cache_free (gp_cache_slab_cache, slab); 382 } 383 else 384 { 385 /* destruct embedded slab struct */ 386 rtl_cache_slab_destructor (slab, 0); 387 } 388 389 if ((refcnt == 0) || (cache->m_features & RTL_CACHE_FEATURE_BULKDESTROY)) 390 { 391 /* free memory */ 392 rtl_arena_free (cache->m_source, addr, cache->m_slab_size); 393 } 394 } 395 396 397 /** rtl_cache_slab_populate() 398 * 399 * @precond cache->m_slab_lock acquired. 400 */ 401 static int 402 rtl_cache_slab_populate ( 403 rtl_cache_type * cache 404 ) 405 { 406 rtl_cache_slab_type * slab; 407 408 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); 409 slab = rtl_cache_slab_create (cache); 410 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); 411 if (slab != 0) 412 { 413 /* update buffer start addr w/ current color */ 414 slab->m_bp += cache->m_ncolor; 415 416 /* update color for next slab */ 417 cache->m_ncolor += cache->m_type_align; 418 if (cache->m_ncolor > cache->m_ncolor_max) 419 cache->m_ncolor = 0; 420 421 /* update stats */ 422 cache->m_slab_stats.m_mem_total += cache->m_slab_size; 423 424 /* insert onto 'free' queue */ 425 QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_); 426 } 427 return (slab != 0); 428 } 429 430 /* ================================================================= */ 431 432 /** rtl_cache_slab_alloc() 433 * 434 * Allocate a buffer from slab layer; used by magazine layer. 435 */ 436 static void * 437 rtl_cache_slab_alloc ( 438 rtl_cache_type * cache 439 ) 440 { 441 void * addr = 0; 442 rtl_cache_slab_type * head; 443 444 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); 445 446 head = &(cache->m_free_head); 447 if ((head->m_slab_next != head) || rtl_cache_slab_populate (cache)) 448 { 449 rtl_cache_slab_type * slab; 450 rtl_cache_bufctl_type * bufctl; 451 452 slab = head->m_slab_next; 453 OSL_ASSERT(slab->m_ntypes < cache->m_ntypes); 454 455 if (slab->m_sp == 0) 456 { 457 /* initialize bufctl w/ current 'slab->m_bp' */ 458 OSL_ASSERT (slab->m_bp < slab->m_data + cache->m_ntypes * cache->m_type_size + cache->m_ncolor_max); 459 if (cache->m_features & RTL_CACHE_FEATURE_HASH) 460 { 461 /* allocate bufctl */ 462 OSL_ASSERT (cache != gp_cache_bufctl_cache); 463 bufctl = (rtl_cache_bufctl_type*)rtl_cache_alloc (gp_cache_bufctl_cache); 464 if (bufctl == 0) 465 { 466 /* out of memory */ 467 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); 468 return (0); 469 } 470 471 bufctl->m_addr = slab->m_bp; 472 bufctl->m_slab = (sal_uIntPtr)(slab); 473 } 474 else 475 { 476 /* embedded bufctl */ 477 bufctl = (rtl_cache_bufctl_type*)(slab->m_bp); 478 } 479 bufctl->m_next = 0; 480 481 /* update 'slab->m_bp' to next free buffer */ 482 slab->m_bp += cache->m_type_size; 483 484 /* assign bufctl to freelist */ 485 slab->m_sp = bufctl; 486 } 487 488 /* pop front */ 489 bufctl = slab->m_sp; 490 slab->m_sp = bufctl->m_next; 491 492 /* increment usage, check for full slab */ 493 if ((slab->m_ntypes += 1) == cache->m_ntypes) 494 { 495 /* remove from 'free' queue */ 496 QUEUE_REMOVE_NAMED(slab, slab_); 497 498 /* insert onto 'used' queue (tail) */ 499 QUEUE_INSERT_TAIL_NAMED(&(cache->m_used_head), slab, slab_); 500 } 501 502 /* update stats */ 503 cache->m_slab_stats.m_alloc += 1; 504 cache->m_slab_stats.m_mem_alloc += cache->m_type_size; 505 506 if (cache->m_features & RTL_CACHE_FEATURE_HASH) 507 addr = (void*)rtl_cache_hash_insert (cache, bufctl); 508 else 509 addr = bufctl; 510 511 /* DEBUG ONLY: mark allocated, undefined */ 512 OSL_DEBUG_ONLY(memset(addr, 0x77777777, cache->m_type_size)); 513 VALGRIND_MEMPOOL_ALLOC(cache, addr, cache->m_type_size); 514 } 515 516 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); 517 return (addr); 518 } 519 520 521 /** rtl_cache_slab_free() 522 * 523 * Return a buffer to slab layer; used by magazine layer. 524 */ 525 static void 526 rtl_cache_slab_free ( 527 rtl_cache_type * cache, 528 void * addr 529 ) 530 { 531 rtl_cache_bufctl_type * bufctl; 532 rtl_cache_slab_type * slab; 533 534 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); 535 536 /* DEBUG ONLY: mark unallocated, undefined */ 537 VALGRIND_MEMPOOL_FREE(cache, addr); 538 /* OSL_DEBUG_ONLY() */ VALGRIND_MAKE_MEM_UNDEFINED(addr, cache->m_type_size); 539 OSL_DEBUG_ONLY(memset(addr, 0x33333333, cache->m_type_size)); 540 541 /* determine slab from addr */ 542 if (cache->m_features & RTL_CACHE_FEATURE_HASH) 543 { 544 bufctl = rtl_cache_hash_remove (cache, (sal_uIntPtr)(addr)); 545 slab = (bufctl != 0) ? (rtl_cache_slab_type*)(bufctl->m_slab) : 0; 546 } 547 else 548 { 549 /* embedded slab struct */ 550 bufctl = (rtl_cache_bufctl_type*)(addr); 551 slab = RTL_CACHE_SLAB(addr, cache->m_slab_size); 552 } 553 554 if (slab != 0) 555 { 556 /* check for full slab */ 557 if (slab->m_ntypes == cache->m_ntypes) 558 { 559 /* remove from 'used' queue */ 560 QUEUE_REMOVE_NAMED(slab, slab_); 561 562 /* insert onto 'free' queue (head) */ 563 QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_); 564 } 565 566 /* push front */ 567 bufctl->m_next = slab->m_sp; 568 slab->m_sp = bufctl; 569 570 /* update stats */ 571 cache->m_slab_stats.m_free += 1; 572 cache->m_slab_stats.m_mem_alloc -= cache->m_type_size; 573 574 /* decrement usage, check for empty slab */ 575 if ((slab->m_ntypes -= 1) == 0) 576 { 577 /* remove from 'free' queue */ 578 QUEUE_REMOVE_NAMED(slab, slab_); 579 580 /* update stats */ 581 cache->m_slab_stats.m_mem_total -= cache->m_slab_size; 582 583 /* free 'empty' slab */ 584 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); 585 rtl_cache_slab_destroy (cache, slab); 586 return; 587 } 588 } 589 590 RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); 591 } 592 593 /* ================================================================= */ 594 595 /** rtl_cache_magazine_constructor() 596 */ 597 static int 598 rtl_cache_magazine_constructor (void * obj, void * arg) 599 { 600 rtl_cache_magazine_type * mag = (rtl_cache_magazine_type*)(obj); 601 /* @@@ sal_Size size = (sal_Size)(arg); @@@ */ 602 603 (void) arg; /* unused */ 604 605 mag->m_mag_next = 0; 606 mag->m_mag_size = RTL_CACHE_MAGAZINE_SIZE; 607 mag->m_mag_used = 0; 608 609 return (1); 610 } 611 612 613 /** rtl_cache_magazine_destructor() 614 */ 615 static void 616 rtl_cache_magazine_destructor (void * obj, void * arg) 617 { 618 #if OSL_DEBUG_LEVEL == 0 619 (void) obj; /* unused */ 620 #else /* OSL_DEBUG_LEVEL */ 621 rtl_cache_magazine_type * mag = (rtl_cache_magazine_type*)(obj); 622 623 /* assure removed from queue(s) */ 624 OSL_ASSERT(mag->m_mag_next == 0); 625 626 /* assure no longer referenced */ 627 OSL_ASSERT(mag->m_mag_used == 0); 628 #endif /* OSL_DEBUG_LEVEL */ 629 630 (void) arg; /* unused */ 631 } 632 633 634 /** rtl_cache_magazine_clear() 635 */ 636 static void 637 rtl_cache_magazine_clear ( 638 rtl_cache_type * cache, 639 rtl_cache_magazine_type * mag 640 ) 641 { 642 for (; mag->m_mag_used > 0; --mag->m_mag_used) 643 { 644 void * obj = mag->m_objects[mag->m_mag_used - 1]; 645 mag->m_objects[mag->m_mag_used - 1] = 0; 646 647 /* DEBUG ONLY: mark cached object allocated, undefined */ 648 VALGRIND_MEMPOOL_ALLOC(cache, obj, cache->m_type_size); 649 if (cache->m_destructor != 0) 650 { 651 /* DEBUG ONLY: keep constructed object defined */ 652 VALGRIND_MAKE_MEM_DEFINED(obj, cache->m_type_size); 653 654 /* destruct object */ 655 (cache->m_destructor)(obj, cache->m_userarg); 656 } 657 658 /* return buffer to slab layer */ 659 rtl_cache_slab_free (cache, obj); 660 } 661 } 662 663 /* ================================================================= */ 664 665 /** rtl_cache_depot_enqueue() 666 * 667 * @precond cache->m_depot_lock acquired. 668 */ 669 static RTL_MEMORY_INLINE void 670 rtl_cache_depot_enqueue ( 671 rtl_cache_depot_type * depot, 672 rtl_cache_magazine_type * mag 673 ) 674 { 675 /* enqueue empty magazine */ 676 mag->m_mag_next = depot->m_mag_next; 677 depot->m_mag_next = mag; 678 679 /* update depot stats */ 680 depot->m_mag_count++; 681 } 682 683 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) 684 #pragma inline(rtl_cache_depot_enqueue) 685 #endif /* __SUNPRO_C */ 686 687 688 /** rtl_cache_depot_dequeue() 689 * 690 * @precond cache->m_depot_lock acquired. 691 */ 692 static RTL_MEMORY_INLINE rtl_cache_magazine_type * 693 rtl_cache_depot_dequeue ( 694 rtl_cache_depot_type * depot 695 ) 696 { 697 rtl_cache_magazine_type * mag = 0; 698 if (depot->m_mag_count > 0) 699 { 700 /* dequeue magazine */ 701 OSL_ASSERT(depot->m_mag_next != 0); 702 703 mag = depot->m_mag_next; 704 depot->m_mag_next = mag->m_mag_next; 705 mag->m_mag_next = 0; 706 707 /* update depot stats */ 708 depot->m_mag_count--; 709 depot->m_curr_min = SAL_MIN(depot->m_curr_min, depot->m_mag_count); 710 } 711 return (mag); 712 } 713 714 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) 715 #pragma inline(rtl_cache_depot_dequeue) 716 #endif /* __SUNPRO_C */ 717 718 719 /** rtl_cache_depot_exchange_alloc() 720 * 721 * @precond cache->m_depot_lock acquired. 722 */ 723 static RTL_MEMORY_INLINE rtl_cache_magazine_type * 724 rtl_cache_depot_exchange_alloc ( 725 rtl_cache_type * cache, 726 rtl_cache_magazine_type * empty 727 ) 728 { 729 rtl_cache_magazine_type * full; 730 731 OSL_ASSERT((empty == 0) || (empty->m_mag_used == 0)); 732 733 /* dequeue full magazine */ 734 full = rtl_cache_depot_dequeue (&(cache->m_depot_full)); 735 if ((full != 0) && (empty != 0)) 736 { 737 /* enqueue empty magazine */ 738 rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty); 739 } 740 741 OSL_ASSERT((full == 0) || (full->m_mag_used > 0)); 742 743 return (full); 744 } 745 746 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) 747 #pragma inline(rtl_cache_depot_exchange_alloc) 748 #endif /* __SUNPRO_C */ 749 750 751 /** rtl_cache_depot_exchange_free() 752 * 753 * @precond cache->m_depot_lock acquired. 754 */ 755 static RTL_MEMORY_INLINE rtl_cache_magazine_type * 756 rtl_cache_depot_exchange_free ( 757 rtl_cache_type * cache, 758 rtl_cache_magazine_type * full 759 ) 760 { 761 rtl_cache_magazine_type * empty; 762 763 OSL_ASSERT((full == 0) || (full->m_mag_used > 0)); 764 765 /* dequeue empty magazine */ 766 empty = rtl_cache_depot_dequeue (&(cache->m_depot_empty)); 767 if ((empty != 0) && (full != 0)) 768 { 769 /* enqueue full magazine */ 770 rtl_cache_depot_enqueue (&(cache->m_depot_full), full); 771 } 772 773 OSL_ASSERT((empty == 0) || (empty->m_mag_used == 0)); 774 775 return (empty); 776 } 777 778 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) 779 #pragma inline(rtl_cache_depot_exchange_free) 780 #endif /* __SUNPRO_C */ 781 782 783 /** rtl_cache_depot_populate() 784 * 785 * @precond cache->m_depot_lock acquired. 786 */ 787 static int 788 rtl_cache_depot_populate ( 789 rtl_cache_type * cache 790 ) 791 { 792 rtl_cache_magazine_type * empty = 0; 793 794 if (cache->m_magazine_cache != 0) 795 { 796 /* allocate new empty magazine */ 797 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); 798 empty = (rtl_cache_magazine_type*)rtl_cache_alloc (cache->m_magazine_cache); 799 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); 800 if (empty != 0) 801 { 802 /* enqueue (new) empty magazine */ 803 rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty); 804 } 805 } 806 return (empty != 0); 807 } 808 809 /* ================================================================= */ 810 811 /** rtl_cache_constructor() 812 */ 813 static int 814 rtl_cache_constructor (void * obj) 815 { 816 rtl_cache_type * cache = (rtl_cache_type*)(obj); 817 818 memset (cache, 0, sizeof(rtl_cache_type)); 819 820 /* linkage */ 821 QUEUE_START_NAMED(cache, cache_); 822 823 /* slab layer */ 824 (void)RTL_MEMORY_LOCK_INIT(&(cache->m_slab_lock)); 825 826 QUEUE_START_NAMED(&(cache->m_free_head), slab_); 827 QUEUE_START_NAMED(&(cache->m_used_head), slab_); 828 829 cache->m_hash_table = cache->m_hash_table_0; 830 cache->m_hash_size = RTL_CACHE_HASH_SIZE; 831 cache->m_hash_shift = highbit(cache->m_hash_size) - 1; 832 833 /* depot layer */ 834 (void)RTL_MEMORY_LOCK_INIT(&(cache->m_depot_lock)); 835 836 return (1); 837 } 838 839 /** rtl_cache_destructor() 840 */ 841 static void 842 rtl_cache_destructor (void * obj) 843 { 844 rtl_cache_type * cache = (rtl_cache_type*)(obj); 845 846 /* linkage */ 847 OSL_ASSERT(QUEUE_STARTED_NAMED(cache, cache_)); 848 849 /* slab layer */ 850 (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_slab_lock)); 851 852 OSL_ASSERT(QUEUE_STARTED_NAMED(&(cache->m_free_head), slab_)); 853 OSL_ASSERT(QUEUE_STARTED_NAMED(&(cache->m_used_head), slab_)); 854 855 OSL_ASSERT(cache->m_hash_table == cache->m_hash_table_0); 856 OSL_ASSERT(cache->m_hash_size == RTL_CACHE_HASH_SIZE); 857 OSL_ASSERT(cache->m_hash_shift == (sal_Size)(highbit(cache->m_hash_size) - 1)); 858 859 /* depot layer */ 860 (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_depot_lock)); 861 } 862 863 /* ================================================================= */ 864 865 /** rtl_cache_activate() 866 */ 867 static rtl_cache_type * 868 rtl_cache_activate ( 869 rtl_cache_type * cache, 870 const char * name, 871 size_t objsize, 872 size_t objalign, 873 int (SAL_CALL * constructor)(void * obj, void * userarg), 874 void (SAL_CALL * destructor) (void * obj, void * userarg), 875 void (SAL_CALL * reclaim) (void * userarg), 876 void * userarg, 877 rtl_arena_type * source, 878 int flags 879 ) 880 { 881 OSL_ASSERT(cache != 0); 882 if (cache != 0) 883 { 884 sal_Size slabsize; 885 886 snprintf (cache->m_name, sizeof(cache->m_name), "%s", name); 887 888 /* ensure minimum size (embedded bufctl linkage) */ 889 objsize = SAL_MAX(objsize, sizeof(rtl_cache_bufctl_type*)); 890 891 if (objalign == 0) 892 { 893 /* determine default alignment */ 894 if (objsize >= RTL_MEMORY_ALIGNMENT_8) 895 objalign = RTL_MEMORY_ALIGNMENT_8; 896 else 897 objalign = RTL_MEMORY_ALIGNMENT_4; 898 } 899 else 900 { 901 /* ensure minimum alignment */ 902 objalign = SAL_MAX(objalign, RTL_MEMORY_ALIGNMENT_4); 903 } 904 OSL_ASSERT(RTL_MEMORY_ISP2(objalign)); 905 906 cache->m_type_size = objsize = RTL_MEMORY_P2ROUNDUP(objsize, objalign); 907 cache->m_type_align = objalign; 908 cache->m_type_shift = highbit(cache->m_type_size) - 1; 909 910 cache->m_constructor = constructor; 911 cache->m_destructor = destructor; 912 cache->m_reclaim = reclaim; 913 cache->m_userarg = userarg; 914 915 /* slab layer */ 916 cache->m_source = source; 917 918 slabsize = source->m_quantum; /* minimum slab size */ 919 if (flags & RTL_CACHE_FLAG_QUANTUMCACHE) 920 { 921 /* next power of 2 above 3 * qcache_max */ 922 slabsize = SAL_MAX(slabsize, (1UL << highbit(3 * source->m_qcache_max))); 923 } 924 else 925 { 926 /* waste at most 1/8 of slab */ 927 slabsize = SAL_MAX(slabsize, cache->m_type_size * 8); 928 } 929 930 slabsize = RTL_MEMORY_P2ROUNDUP(slabsize, source->m_quantum); 931 if (!RTL_MEMORY_ISP2(slabsize)) 932 slabsize = 1UL << highbit(slabsize); 933 cache->m_slab_size = slabsize; 934 935 if (cache->m_slab_size > source->m_quantum) 936 { 937 OSL_ASSERT(gp_cache_slab_cache != 0); 938 OSL_ASSERT(gp_cache_bufctl_cache != 0); 939 940 cache->m_features |= RTL_CACHE_FEATURE_HASH; 941 cache->m_ntypes = cache->m_slab_size / cache->m_type_size; 942 cache->m_ncolor_max = cache->m_slab_size % cache->m_type_size; 943 } 944 else 945 { 946 /* embedded slab struct */ 947 cache->m_ntypes = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) / cache->m_type_size; 948 cache->m_ncolor_max = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) % cache->m_type_size; 949 } 950 951 OSL_ASSERT(cache->m_ntypes > 0); 952 cache->m_ncolor = 0; 953 954 if (flags & RTL_CACHE_FLAG_BULKDESTROY) 955 { 956 /* allow bulk slab delete upon cache deactivation */ 957 cache->m_features |= RTL_CACHE_FEATURE_BULKDESTROY; 958 } 959 960 /* magazine layer */ 961 if (!(flags & RTL_CACHE_FLAG_NOMAGAZINE)) 962 { 963 OSL_ASSERT(gp_cache_magazine_cache != 0); 964 cache->m_magazine_cache = gp_cache_magazine_cache; 965 } 966 967 /* insert into cache list */ 968 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 969 QUEUE_INSERT_TAIL_NAMED(&(g_cache_list.m_cache_head), cache, cache_); 970 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 971 } 972 return (cache); 973 } 974 975 /** rtl_cache_deactivate() 976 */ 977 static void 978 rtl_cache_deactivate ( 979 rtl_cache_type * cache 980 ) 981 { 982 int active = 1; 983 984 /* remove from cache list */ 985 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 986 active = QUEUE_STARTED_NAMED(cache, cache_) == 0; 987 QUEUE_REMOVE_NAMED(cache, cache_); 988 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 989 990 OSL_PRECOND(active, "rtl_cache_deactivate(): orphaned cache."); 991 992 /* cleanup magazine layer */ 993 if (cache->m_magazine_cache != 0) 994 { 995 rtl_cache_type * mag_cache; 996 rtl_cache_magazine_type * mag; 997 998 /* prevent recursion */ 999 mag_cache = cache->m_magazine_cache, cache->m_magazine_cache = 0; 1000 1001 /* cleanup cpu layer */ 1002 if ((mag = cache->m_cpu_curr) != 0) 1003 { 1004 cache->m_cpu_curr = 0; 1005 rtl_cache_magazine_clear (cache, mag); 1006 rtl_cache_free (mag_cache, mag); 1007 } 1008 if ((mag = cache->m_cpu_prev) != 0) 1009 { 1010 cache->m_cpu_prev = 0; 1011 rtl_cache_magazine_clear (cache, mag); 1012 rtl_cache_free (mag_cache, mag); 1013 } 1014 1015 /* cleanup depot layer */ 1016 while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_full))) != 0) 1017 { 1018 rtl_cache_magazine_clear (cache, mag); 1019 rtl_cache_free (mag_cache, mag); 1020 } 1021 while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_empty))) != 0) 1022 { 1023 rtl_cache_magazine_clear (cache, mag); 1024 rtl_cache_free (mag_cache, mag); 1025 } 1026 } 1027 1028 OSL_TRACE( 1029 "rtl_cache_deactivate(\"%s\"): " 1030 "[slab]: allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu; " 1031 "[cpu]: allocs: %"PRIu64", frees: %"PRIu64"; " 1032 "[total]: allocs: %"PRIu64", frees: %"PRIu64"", 1033 cache->m_name, 1034 cache->m_slab_stats.m_alloc, cache->m_slab_stats.m_free, 1035 cache->m_slab_stats.m_mem_total, cache->m_slab_stats.m_mem_alloc, 1036 cache->m_cpu_stats.m_alloc, cache->m_cpu_stats.m_free, 1037 cache->m_slab_stats.m_alloc + cache->m_cpu_stats.m_alloc, 1038 cache->m_slab_stats.m_free + cache->m_cpu_stats.m_free 1039 ); 1040 1041 /* cleanup slab layer */ 1042 if (cache->m_slab_stats.m_alloc > cache->m_slab_stats.m_free) 1043 { 1044 OSL_TRACE( 1045 "rtl_cache_deactivate(\"%s\"): " 1046 "cleaning up %"PRIu64" leaked buffer(s) [%lu bytes] [%lu total]", 1047 cache->m_name, 1048 cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free, 1049 cache->m_slab_stats.m_mem_alloc, cache->m_slab_stats.m_mem_total 1050 ); 1051 1052 if (cache->m_features & RTL_CACHE_FEATURE_HASH) 1053 { 1054 /* cleanup bufctl(s) for leaking buffer(s) */ 1055 sal_Size i, n = cache->m_hash_size; 1056 for (i = 0; i < n; i++) 1057 { 1058 rtl_cache_bufctl_type * bufctl; 1059 while ((bufctl = cache->m_hash_table[i]) != 0) 1060 { 1061 /* pop from hash table */ 1062 cache->m_hash_table[i] = bufctl->m_next, bufctl->m_next = 0; 1063 1064 /* return to bufctl cache */ 1065 rtl_cache_free (gp_cache_bufctl_cache, bufctl); 1066 } 1067 } 1068 } 1069 { 1070 /* force cleanup of remaining slabs */ 1071 rtl_cache_slab_type *head, *slab; 1072 1073 head = &(cache->m_used_head); 1074 for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next) 1075 { 1076 /* remove from 'used' queue */ 1077 QUEUE_REMOVE_NAMED(slab, slab_); 1078 1079 /* update stats */ 1080 cache->m_slab_stats.m_mem_total -= cache->m_slab_size; 1081 1082 /* free slab */ 1083 rtl_cache_slab_destroy (cache, slab); 1084 } 1085 1086 head = &(cache->m_free_head); 1087 for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next) 1088 { 1089 /* remove from 'free' queue */ 1090 QUEUE_REMOVE_NAMED(slab, slab_); 1091 1092 /* update stats */ 1093 cache->m_slab_stats.m_mem_total -= cache->m_slab_size; 1094 1095 /* free slab */ 1096 rtl_cache_slab_destroy (cache, slab); 1097 } 1098 } 1099 } 1100 1101 if (cache->m_hash_table != cache->m_hash_table_0) 1102 { 1103 rtl_arena_free ( 1104 gp_cache_arena, 1105 cache->m_hash_table, 1106 cache->m_hash_size * sizeof(rtl_cache_bufctl_type*)); 1107 1108 cache->m_hash_table = cache->m_hash_table_0; 1109 cache->m_hash_size = RTL_CACHE_HASH_SIZE; 1110 cache->m_hash_shift = highbit(cache->m_hash_size) - 1; 1111 } 1112 } 1113 1114 /* ================================================================= * 1115 * 1116 * cache implementation. 1117 * 1118 * ================================================================= */ 1119 1120 /** rtl_cache_create() 1121 */ 1122 rtl_cache_type * 1123 SAL_CALL rtl_cache_create ( 1124 const char * name, 1125 sal_Size objsize, 1126 sal_Size objalign, 1127 int (SAL_CALL * constructor)(void * obj, void * userarg), 1128 void (SAL_CALL * destructor) (void * obj, void * userarg), 1129 void (SAL_CALL * reclaim) (void * userarg), 1130 void * userarg, 1131 rtl_arena_type * source, 1132 int flags 1133 ) SAL_THROW_EXTERN_C() 1134 { 1135 rtl_cache_type * result = 0; 1136 sal_Size size = sizeof(rtl_cache_type); 1137 1138 try_alloc: 1139 result = (rtl_cache_type*)rtl_arena_alloc (gp_cache_arena, &size); 1140 if (result != 0) 1141 { 1142 rtl_cache_type * cache = result; 1143 VALGRIND_CREATE_MEMPOOL(cache, 0, 0); 1144 (void) rtl_cache_constructor (cache); 1145 1146 if (!source) 1147 { 1148 /* use default arena */ 1149 OSL_ASSERT(gp_default_arena != 0); 1150 source = gp_default_arena; 1151 } 1152 1153 result = rtl_cache_activate ( 1154 cache, 1155 name, 1156 objsize, 1157 objalign, 1158 constructor, 1159 destructor, 1160 reclaim, 1161 userarg, 1162 source, 1163 flags 1164 ); 1165 1166 if (result == 0) 1167 { 1168 /* activation failed */ 1169 rtl_cache_deactivate (cache); 1170 rtl_cache_destructor (cache); 1171 VALGRIND_DESTROY_MEMPOOL(cache); 1172 rtl_arena_free (gp_cache_arena, cache, size); 1173 } 1174 } 1175 else if (gp_cache_arena == 0) 1176 { 1177 if (rtl_cache_init()) 1178 { 1179 /* try again */ 1180 goto try_alloc; 1181 } 1182 } 1183 return (result); 1184 } 1185 1186 /** rtl_cache_destroy() 1187 */ 1188 void SAL_CALL rtl_cache_destroy ( 1189 rtl_cache_type * cache 1190 ) SAL_THROW_EXTERN_C() 1191 { 1192 if (cache != 0) 1193 { 1194 rtl_cache_deactivate (cache); 1195 rtl_cache_destructor (cache); 1196 VALGRIND_DESTROY_MEMPOOL(cache); 1197 rtl_arena_free (gp_cache_arena, cache, sizeof(rtl_cache_type)); 1198 } 1199 } 1200 1201 /** rtl_cache_alloc() 1202 */ 1203 void * 1204 SAL_CALL rtl_cache_alloc ( 1205 rtl_cache_type * cache 1206 ) SAL_THROW_EXTERN_C() 1207 { 1208 void * obj = 0; 1209 1210 if (cache == 0) 1211 return (0); 1212 1213 if (cache->m_cpu_curr != 0) 1214 { 1215 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); 1216 1217 for (;;) 1218 { 1219 /* take object from magazine layer */ 1220 rtl_cache_magazine_type *curr, *prev, *temp; 1221 1222 curr = cache->m_cpu_curr; 1223 if ((curr != 0) && (curr->m_mag_used > 0)) 1224 { 1225 obj = curr->m_objects[--curr->m_mag_used]; 1226 #if defined(HAVE_VALGRIND_MEMCHECK_H) 1227 VALGRIND_MEMPOOL_ALLOC(cache, obj, cache->m_type_size); 1228 if (cache->m_constructor != 0) 1229 { 1230 /* keep constructed object defined */ 1231 VALGRIND_MAKE_MEM_DEFINED(obj, cache->m_type_size); 1232 } 1233 #endif /* HAVE_VALGRIND_MEMCHECK_H */ 1234 cache->m_cpu_stats.m_alloc += 1; 1235 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); 1236 1237 return (obj); 1238 } 1239 1240 prev = cache->m_cpu_prev; 1241 if ((prev != 0) && (prev->m_mag_used > 0)) 1242 { 1243 temp = cache->m_cpu_curr; 1244 cache->m_cpu_curr = cache->m_cpu_prev; 1245 cache->m_cpu_prev = temp; 1246 1247 continue; 1248 } 1249 1250 temp = rtl_cache_depot_exchange_alloc (cache, prev); 1251 if (temp != 0) 1252 { 1253 cache->m_cpu_prev = cache->m_cpu_curr; 1254 cache->m_cpu_curr = temp; 1255 1256 continue; 1257 } 1258 1259 /* no full magazine: fall through to slab layer */ 1260 break; 1261 } 1262 1263 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); 1264 } 1265 1266 /* alloc buffer from slab layer */ 1267 obj = rtl_cache_slab_alloc (cache); 1268 if ((obj != 0) && (cache->m_constructor != 0)) 1269 { 1270 /* construct object */ 1271 if (!((cache->m_constructor)(obj, cache->m_userarg))) 1272 { 1273 /* construction failure */ 1274 rtl_cache_slab_free (cache, obj), obj = 0; 1275 } 1276 } 1277 return (obj); 1278 } 1279 1280 /** rtl_cache_free() 1281 */ 1282 void 1283 SAL_CALL rtl_cache_free ( 1284 rtl_cache_type * cache, 1285 void * obj 1286 ) SAL_THROW_EXTERN_C() 1287 { 1288 if ((obj != 0) && (cache != 0)) 1289 { 1290 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); 1291 1292 for (;;) 1293 { 1294 /* return object to magazine layer */ 1295 rtl_cache_magazine_type *curr, *prev, *temp; 1296 1297 curr = cache->m_cpu_curr; 1298 if ((curr != 0) && (curr->m_mag_used < curr->m_mag_size)) 1299 { 1300 curr->m_objects[curr->m_mag_used++] = obj; 1301 #if defined(HAVE_VALGRIND_MEMCHECK_H) 1302 VALGRIND_MEMPOOL_FREE(cache, obj); 1303 #endif /* HAVE_VALGRIND_MEMCHECK_H */ 1304 cache->m_cpu_stats.m_free += 1; 1305 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); 1306 1307 return; 1308 } 1309 1310 prev = cache->m_cpu_prev; 1311 if ((prev != 0) && (prev->m_mag_used == 0)) 1312 { 1313 temp = cache->m_cpu_curr; 1314 cache->m_cpu_curr = cache->m_cpu_prev; 1315 cache->m_cpu_prev = temp; 1316 1317 continue; 1318 } 1319 1320 temp = rtl_cache_depot_exchange_free (cache, prev); 1321 if (temp != 0) 1322 { 1323 cache->m_cpu_prev = cache->m_cpu_curr; 1324 cache->m_cpu_curr = temp; 1325 1326 continue; 1327 } 1328 1329 if (rtl_cache_depot_populate(cache) != 0) 1330 { 1331 continue; 1332 } 1333 1334 /* no empty magazine: fall through to slab layer */ 1335 break; 1336 } 1337 1338 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); 1339 1340 /* no space for constructed object in magazine layer */ 1341 if (cache->m_destructor != 0) 1342 { 1343 /* destruct object */ 1344 (cache->m_destructor)(obj, cache->m_userarg); 1345 } 1346 1347 /* return buffer to slab layer */ 1348 rtl_cache_slab_free (cache, obj); 1349 } 1350 } 1351 1352 /* ================================================================= * 1353 * 1354 * cache wsupdate (machdep) internals. 1355 * 1356 * ================================================================= */ 1357 1358 /** rtl_cache_wsupdate_init() 1359 * 1360 * @precond g_cache_list.m_lock initialized 1361 */ 1362 static void 1363 rtl_cache_wsupdate_init (void); 1364 1365 1366 /** rtl_cache_wsupdate_wait() 1367 * 1368 * @precond g_cache_list.m_lock acquired 1369 */ 1370 static void 1371 rtl_cache_wsupdate_wait ( 1372 unsigned int seconds 1373 ); 1374 1375 /** rtl_cache_wsupdate_fini() 1376 * 1377 */ 1378 static void 1379 rtl_cache_wsupdate_fini (void); 1380 1381 /* ================================================================= */ 1382 1383 #if defined(SAL_UNX) || defined(SAL_OS2) 1384 1385 #include <sys/time.h> 1386 1387 static void * 1388 rtl_cache_wsupdate_all (void * arg); 1389 1390 static void 1391 rtl_cache_wsupdate_init (void) 1392 { 1393 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 1394 g_cache_list.m_update_done = 0; 1395 (void) pthread_cond_init (&(g_cache_list.m_update_cond), NULL); 1396 if (pthread_create ( 1397 &(g_cache_list.m_update_thread), NULL, rtl_cache_wsupdate_all, (void*)(10)) != 0) 1398 { 1399 /* failure */ 1400 g_cache_list.m_update_thread = (pthread_t)(0); 1401 } 1402 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 1403 } 1404 1405 static void 1406 rtl_cache_wsupdate_wait (unsigned int seconds) 1407 { 1408 if (seconds > 0) 1409 { 1410 struct timeval now; 1411 struct timespec wakeup; 1412 1413 gettimeofday(&now, 0); 1414 wakeup.tv_sec = now.tv_sec + (seconds); 1415 wakeup.tv_nsec = now.tv_usec * 1000; 1416 1417 (void) pthread_cond_timedwait ( 1418 &(g_cache_list.m_update_cond), 1419 &(g_cache_list.m_lock), 1420 &wakeup); 1421 } 1422 } 1423 1424 static void 1425 rtl_cache_wsupdate_fini (void) 1426 { 1427 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 1428 g_cache_list.m_update_done = 1; 1429 pthread_cond_signal (&(g_cache_list.m_update_cond)); 1430 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 1431 1432 if (g_cache_list.m_update_thread != (pthread_t)(0)) 1433 pthread_join (g_cache_list.m_update_thread, NULL); 1434 } 1435 1436 /* ================================================================= */ 1437 1438 #elif defined(SAL_W32) 1439 1440 static DWORD WINAPI 1441 rtl_cache_wsupdate_all (void * arg); 1442 1443 static void 1444 rtl_cache_wsupdate_init (void) 1445 { 1446 DWORD dwThreadId; 1447 1448 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 1449 g_cache_list.m_update_done = 0; 1450 g_cache_list.m_update_cond = CreateEvent (0, TRUE, FALSE, 0); 1451 1452 g_cache_list.m_update_thread = 1453 CreateThread (NULL, 0, rtl_cache_wsupdate_all, (LPVOID)(10), 0, &dwThreadId); 1454 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 1455 } 1456 1457 static void 1458 rtl_cache_wsupdate_wait (unsigned int seconds) 1459 { 1460 if (seconds > 0) 1461 { 1462 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 1463 WaitForSingleObject (g_cache_list.m_update_cond, (DWORD)(seconds * 1000)); 1464 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 1465 } 1466 } 1467 1468 static void 1469 rtl_cache_wsupdate_fini (void) 1470 { 1471 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 1472 g_cache_list.m_update_done = 1; 1473 SetEvent (g_cache_list.m_update_cond); 1474 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 1475 1476 WaitForSingleObject (g_cache_list.m_update_thread, INFINITE); 1477 } 1478 1479 #endif /* SAL_UNX || SAL_W32 */ 1480 1481 /* ================================================================= */ 1482 1483 /** rtl_cache_depot_wsupdate() 1484 * update depot stats and purge excess magazines. 1485 * 1486 * @precond cache->m_depot_lock acquired 1487 */ 1488 static void 1489 rtl_cache_depot_wsupdate ( 1490 rtl_cache_type * cache, 1491 rtl_cache_depot_type * depot 1492 ) 1493 { 1494 sal_Size npurge; 1495 1496 depot->m_prev_min = depot->m_curr_min; 1497 depot->m_curr_min = depot->m_mag_count; 1498 1499 npurge = SAL_MIN(depot->m_curr_min, depot->m_prev_min); 1500 for (; npurge > 0; npurge--) 1501 { 1502 rtl_cache_magazine_type * mag = rtl_cache_depot_dequeue (depot); 1503 if (mag != 0) 1504 { 1505 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); 1506 rtl_cache_magazine_clear (cache, mag); 1507 rtl_cache_free (cache->m_magazine_cache, mag); 1508 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); 1509 } 1510 } 1511 } 1512 1513 /** rtl_cache_wsupdate() 1514 * 1515 * @precond cache->m_depot_lock released 1516 */ 1517 static void 1518 rtl_cache_wsupdate ( 1519 rtl_cache_type * cache 1520 ) 1521 { 1522 if (cache->m_magazine_cache != 0) 1523 { 1524 RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); 1525 1526 OSL_TRACE( 1527 "rtl_cache_wsupdate(\"%s\") " 1528 "[depot: count, curr_min, prev_min] " 1529 "full: %lu, %lu, %lu; empty: %lu, %lu, %lu", 1530 cache->m_name, 1531 cache->m_depot_full.m_mag_count, 1532 cache->m_depot_full.m_curr_min, 1533 cache->m_depot_full.m_prev_min, 1534 cache->m_depot_empty.m_mag_count, 1535 cache->m_depot_empty.m_curr_min, 1536 cache->m_depot_empty.m_prev_min 1537 ); 1538 1539 rtl_cache_depot_wsupdate (cache, &(cache->m_depot_full)); 1540 rtl_cache_depot_wsupdate (cache, &(cache->m_depot_empty)); 1541 1542 RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); 1543 } 1544 } 1545 1546 /** rtl_cache_wsupdate_all() 1547 * 1548 */ 1549 #if defined(SAL_UNX) || defined(SAL_OS2) 1550 static void * 1551 #elif defined(SAL_W32) 1552 static DWORD WINAPI 1553 #endif /* SAL_UNX || SAL_W32 */ 1554 rtl_cache_wsupdate_all (void * arg) 1555 { 1556 unsigned int seconds = (unsigned int)SAL_INT_CAST(sal_uIntPtr, arg); 1557 1558 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 1559 while (!g_cache_list.m_update_done) 1560 { 1561 rtl_cache_wsupdate_wait (seconds); 1562 if (!g_cache_list.m_update_done) 1563 { 1564 rtl_cache_type * head, * cache; 1565 1566 head = &(g_cache_list.m_cache_head); 1567 for (cache = head->m_cache_next; 1568 cache != head; 1569 cache = cache->m_cache_next) 1570 { 1571 rtl_cache_wsupdate (cache); 1572 } 1573 } 1574 } 1575 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 1576 1577 return (0); 1578 } 1579 1580 /* ================================================================= * 1581 * 1582 * cache initialization. 1583 * 1584 * ================================================================= */ 1585 1586 static void 1587 rtl_cache_once_init (void) 1588 { 1589 { 1590 /* list of caches */ 1591 RTL_MEMORY_LOCK_INIT(&(g_cache_list.m_lock)); 1592 (void) rtl_cache_constructor (&(g_cache_list.m_cache_head)); 1593 } 1594 { 1595 /* cache: internal arena */ 1596 OSL_ASSERT(gp_cache_arena == 0); 1597 1598 gp_cache_arena = rtl_arena_create ( 1599 "rtl_cache_internal_arena", 1600 64, /* quantum */ 1601 0, /* no quantum caching */ 1602 NULL, /* default source */ 1603 rtl_arena_alloc, 1604 rtl_arena_free, 1605 0 /* flags */ 1606 ); 1607 OSL_ASSERT(gp_cache_arena != 0); 1608 1609 /* check 'gp_default_arena' initialization */ 1610 OSL_ASSERT(gp_default_arena != 0); 1611 } 1612 { 1613 /* cache: magazine cache */ 1614 static rtl_cache_type g_cache_magazine_cache; 1615 1616 OSL_ASSERT(gp_cache_magazine_cache == 0); 1617 VALGRIND_CREATE_MEMPOOL(&g_cache_magazine_cache, 0, 0); 1618 (void) rtl_cache_constructor (&g_cache_magazine_cache); 1619 1620 gp_cache_magazine_cache = rtl_cache_activate ( 1621 &g_cache_magazine_cache, 1622 "rtl_cache_magazine_cache", 1623 sizeof(rtl_cache_magazine_type), /* objsize */ 1624 0, /* objalign */ 1625 rtl_cache_magazine_constructor, 1626 rtl_cache_magazine_destructor, 1627 0, /* reclaim */ 1628 0, /* userarg: NYI */ 1629 gp_default_arena, /* source */ 1630 RTL_CACHE_FLAG_NOMAGAZINE /* during bootstrap; activated below */ 1631 ); 1632 OSL_ASSERT(gp_cache_magazine_cache != 0); 1633 1634 /* activate magazine layer */ 1635 g_cache_magazine_cache.m_magazine_cache = gp_cache_magazine_cache; 1636 } 1637 { 1638 /* cache: slab (struct) cache */ 1639 static rtl_cache_type g_cache_slab_cache; 1640 1641 OSL_ASSERT(gp_cache_slab_cache == 0); 1642 VALGRIND_CREATE_MEMPOOL(&g_cache_slab_cache, 0, 0); 1643 (void) rtl_cache_constructor (&g_cache_slab_cache); 1644 1645 gp_cache_slab_cache = rtl_cache_activate ( 1646 &g_cache_slab_cache, 1647 "rtl_cache_slab_cache", 1648 sizeof(rtl_cache_slab_type), /* objsize */ 1649 0, /* objalign */ 1650 rtl_cache_slab_constructor, 1651 rtl_cache_slab_destructor, 1652 0, /* reclaim */ 1653 0, /* userarg: none */ 1654 gp_default_arena, /* source */ 1655 0 /* flags: none */ 1656 ); 1657 OSL_ASSERT(gp_cache_slab_cache != 0); 1658 } 1659 { 1660 /* cache: bufctl cache */ 1661 static rtl_cache_type g_cache_bufctl_cache; 1662 1663 OSL_ASSERT(gp_cache_bufctl_cache == 0); 1664 VALGRIND_CREATE_MEMPOOL(&g_cache_bufctl_cache, 0, 0); 1665 (void) rtl_cache_constructor (&g_cache_bufctl_cache); 1666 1667 gp_cache_bufctl_cache = rtl_cache_activate ( 1668 &g_cache_bufctl_cache, 1669 "rtl_cache_bufctl_cache", 1670 sizeof(rtl_cache_bufctl_type), /* objsize */ 1671 0, /* objalign */ 1672 0, /* constructor */ 1673 0, /* destructor */ 1674 0, /* reclaim */ 1675 0, /* userarg */ 1676 gp_default_arena, /* source */ 1677 0 /* flags: none */ 1678 ); 1679 OSL_ASSERT(gp_cache_bufctl_cache != 0); 1680 } 1681 1682 rtl_cache_wsupdate_init(); 1683 } 1684 1685 static int 1686 rtl_cache_init (void) 1687 { 1688 static sal_once_type g_once = SAL_ONCE_INIT; 1689 SAL_ONCE(&g_once, rtl_cache_once_init); 1690 return (gp_cache_arena != 0); 1691 } 1692 1693 /* ================================================================= */ 1694 1695 /* 1696 Issue http://udk.openoffice.org/issues/show_bug.cgi?id=92388 1697 1698 Mac OS X does not seem to support "__cxa__atexit", thus leading 1699 to the situation that "__attribute__((destructor))__" functions 1700 (in particular "rtl_{memory|cache|arena}_fini") become called 1701 _before_ global C++ object d'tors. 1702 1703 Delegated the call to "rtl_cache_fini()" into a dummy C++ object, 1704 see alloc_fini.cxx . 1705 */ 1706 #if defined(__GNUC__) && !defined(MACOSX) 1707 static void rtl_cache_fini (void) __attribute__((destructor)); 1708 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) 1709 #pragma fini(rtl_cache_fini) 1710 static void rtl_cache_fini (void); 1711 #endif /* __GNUC__ || __SUNPRO_C */ 1712 1713 void 1714 rtl_cache_fini (void) 1715 { 1716 if (gp_cache_arena != 0) 1717 { 1718 rtl_cache_type * cache, * head; 1719 1720 rtl_cache_wsupdate_fini(); 1721 1722 if (gp_cache_bufctl_cache != 0) 1723 { 1724 cache = gp_cache_bufctl_cache, gp_cache_bufctl_cache = 0; 1725 rtl_cache_deactivate (cache); 1726 rtl_cache_destructor (cache); 1727 VALGRIND_DESTROY_MEMPOOL(cache); 1728 } 1729 if (gp_cache_slab_cache != 0) 1730 { 1731 cache = gp_cache_slab_cache, gp_cache_slab_cache = 0; 1732 rtl_cache_deactivate (cache); 1733 rtl_cache_destructor (cache); 1734 VALGRIND_DESTROY_MEMPOOL(cache); 1735 } 1736 if (gp_cache_magazine_cache != 0) 1737 { 1738 cache = gp_cache_magazine_cache, gp_cache_magazine_cache = 0; 1739 rtl_cache_deactivate (cache); 1740 rtl_cache_destructor (cache); 1741 VALGRIND_DESTROY_MEMPOOL(cache); 1742 } 1743 if (gp_cache_arena != 0) 1744 { 1745 rtl_arena_destroy (gp_cache_arena); 1746 gp_cache_arena = 0; 1747 } 1748 1749 RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); 1750 head = &(g_cache_list.m_cache_head); 1751 for (cache = head->m_cache_next; cache != head; cache = cache->m_cache_next) 1752 { 1753 OSL_TRACE( 1754 "rtl_cache_fini(\"%s\") " 1755 "[slab]: allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu; " 1756 "[cpu]: allocs: %"PRIu64", frees: %"PRIu64"; " 1757 "[total]: allocs: %"PRIu64", frees: %"PRIu64"", 1758 cache->m_name, 1759 cache->m_slab_stats.m_alloc, cache->m_slab_stats.m_free, 1760 cache->m_slab_stats.m_mem_total, cache->m_slab_stats.m_mem_alloc, 1761 cache->m_cpu_stats.m_alloc, cache->m_cpu_stats.m_free, 1762 cache->m_slab_stats.m_alloc + cache->m_cpu_stats.m_alloc, 1763 cache->m_slab_stats.m_free + cache->m_cpu_stats.m_free 1764 ); 1765 } 1766 RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); 1767 } 1768 } 1769 1770 /* ================================================================= */ 1771