1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_APACHE_LICENSE_HEADER_START@ 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * @APPLE_APACHE_LICENSE_HEADER_END@ 19 */ 20/* 21 BlockRef.cpp 22 Block sieve helper classes. 23 Copyright (c) 2010-2011 Apple Inc. All rights reserved. 24 */ 25 26#include "BlockRef.h" 27 28namespace Auto { 29 30 // SubzoneBlockRef 31 32 usword_t SubzoneBlockRef::refcount() const { 33 int refcount = 0; 34 Admin *admin = subzone()->admin(); 35 SpinLock lock(admin->lock()); 36 if (has_refcount()) { 37 // non-zero reference count, check the overflow table. 38 // BlockRef FIXME: use q instead of address in hash map? 39 PtrIntHashMap &retains = admin->retains(); 40 PtrIntHashMap::iterator retain_iter = retains.find(address()); 41 if (retain_iter != retains.end() && retain_iter->first == address()) { 42 refcount = retain_iter->second; 43 } else { 44 refcount = 1; 45 } 46 } 47 return refcount; 48 } 49 50 usword_t SubzoneBlockRef::inc_refcount() const { 51 int refcount; 52 Admin *admin = subzone()->admin(); 53 SpinLock lock(admin->lock()); 54 void *block = address(); 55 if (has_refcount()) { 56 // non-trivial reference count, check the overflow table. 57 PtrIntHashMap &retains = admin->retains(); 58 PtrIntHashMap::iterator retain_iter = retains.find(block); 59 if (retain_iter != retains.end() && retain_iter->first == block) { 60 refcount = ++retain_iter->second; 61 } else { 62 // transition from 1 -> 2 63 refcount = (retains[block] = 2); 64 } 65 } else { 66 // transition from 0 -> 1 67 Thread &thread = admin->zone()->registered_thread(); 68 thread.block_escaped(*this); 69 subzone()->set_has_refcount(q()); 70 refcount = 1; 71 } 72 return refcount; 73 } 74 75 usword_t SubzoneBlockRef::dec_refcount_no_lock() const { 76 Admin *admin = subzone()->admin(); 77 if (has_refcount()) { 78 // non-zero reference count, check the overflow table. 79 PtrIntHashMap &retains = admin->retains(); 80 PtrIntHashMap::iterator retain_iter = retains.find(address()); 81 if (retain_iter != retains.end() && retain_iter->first == address()) { 82 if (--retain_iter->second == 1) { 83 // transition from 2 -> 1 84 retains.erase(retain_iter); 85 return 1; 86 } else { 87 return retain_iter->second; 88 } 89 } else { 90 // transition from 1 -> 0 91 subzone()->clear_has_refcount(q()); 92 return 0; 93 } 94 } 95 // underflow. 96 malloc_printf("reference count underflow for %p, break on auto_refcount_underflow_error to debug.\n", address()); 97 auto_refcount_underflow_error(address()); 98 return -1; 99 } 100 101 usword_t SubzoneBlockRef::dec_refcount() const { 102 Admin *admin = subzone()->admin(); 103 SpinLock lock(admin->lock()); 104 return dec_refcount_no_lock(); 105 } 106 107 108 109 // LargeBlockRef 110 111 usword_t LargeBlockRef::inc_refcount() const { 112 SpinLock lock(zone()->large_lock()); 113 usword_t refcount = _large->refcount() + 1; 114 _large->set_refcount(refcount); 115 return refcount; 116 } 117 118 usword_t LargeBlockRef::dec_refcount_no_lock() const { 119 usword_t rc = refcount(); 120 if (rc <= 0) { 121 malloc_printf("reference count underflow for %p, break on auto_refcount_underflow_error to debug\n", address()); 122 auto_refcount_underflow_error(address()); 123 } else { 124 rc = rc - 1; 125 _large->set_refcount(rc); 126 } 127 return rc; 128 } 129 130 usword_t LargeBlockRef::dec_refcount() const { 131 SpinLock lock(zone()->large_lock()); 132 return dec_refcount_no_lock(); 133 } 134 135} 136