Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2005, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // ---
     31 // Author: Sanjay Ghemawat
     32 //
     33 // This has the implementation details of malloc_hook that are needed
     34 // to use malloc-hook inside the tcmalloc system.  It does not hold
     35 // any of the client-facing calls that are used to add new hooks.
     36 
     37 #ifndef _MALLOC_HOOK_INL_H_
     38 #define _MALLOC_HOOK_INL_H_
     39 
     40 #include <stddef.h>
     41 #include <sys/types.h>
     42 #include "base/atomicops.h"
     43 #include "base/basictypes.h"
     44 #include <gperftools/malloc_hook.h>
     45 
     46 namespace base { namespace internal {
     47 
     48 // The following (implementation) code is DEPRECATED.
     49 // A simple atomic pointer class that can be initialized by the linker
     50 // when you define a namespace-scope variable as:
     51 //
     52 //   AtomicPtr<Foo*> my_global = { &initial_value };
     53 //
     54 // This isn't suitable for a general atomic<> class because of the
     55 // public access to data_.
     56 template<typename PtrT>
     57 class AtomicPtr {
     58  public:
     59   COMPILE_ASSERT(sizeof(PtrT) <= sizeof(AtomicWord),
     60                  PtrT_should_fit_in_AtomicWord);
     61 
     62   PtrT Get() const {
     63     // Depending on the system, Acquire_Load(AtomicWord*) may have
     64     // been defined to return an AtomicWord, Atomic32, or Atomic64.
     65     // We hide that implementation detail here with an explicit cast.
     66     // This prevents MSVC 2005, at least, from complaining (it has to
     67     // do with __wp64; AtomicWord is __wp64, but Atomic32/64 aren't).
     68     return reinterpret_cast<PtrT>(static_cast<AtomicWord>(
     69       base::subtle::Acquire_Load(&data_)));
     70   }
     71 
     72   // Sets the contained value to new_val and returns the old value,
     73   // atomically, with acquire and release semantics.
     74   // This is a full-barrier instruction.
     75   PtrT Exchange(PtrT new_val);
     76 
     77   // Atomically executes:
     78   //      result = data_
     79   //      if (data_ == old_val)
     80   //        data_ = new_val;
     81   //      return result;
     82   // This is a full-barrier instruction.
     83   PtrT CompareAndSwap(PtrT old_val, PtrT new_val);
     84 
     85   // Not private so that the class is an aggregate and can be
     86   // initialized by the linker. Don't access this directly.
     87   AtomicWord data_;
     88 };
     89 
     90 // These are initialized in malloc_hook.cc
     91 extern AtomicPtr<MallocHook::NewHook>     new_hook_;
     92 extern AtomicPtr<MallocHook::DeleteHook>  delete_hook_;
     93 extern AtomicPtr<MallocHook::PreMmapHook> premmap_hook_;
     94 extern AtomicPtr<MallocHook::MmapHook>    mmap_hook_;
     95 extern AtomicPtr<MallocHook::MunmapHook>  munmap_hook_;
     96 extern AtomicPtr<MallocHook::MremapHook>  mremap_hook_;
     97 extern AtomicPtr<MallocHook::PreSbrkHook> presbrk_hook_;
     98 extern AtomicPtr<MallocHook::SbrkHook>    sbrk_hook_;
     99 // End DEPRECATED code.
    100 
    101 // Maximum of 7 hooks means that HookList is 8 words.
    102 static const int kHookListMaxValues = 7;
    103 
    104 // HookList: a class that provides synchronized insertions and removals and
    105 // lockless traversal.  Most of the implementation is in malloc_hook.cc.
    106 template <typename T>
    107 struct PERFTOOLS_DLL_DECL HookList {
    108   COMPILE_ASSERT(sizeof(T) <= sizeof(AtomicWord), T_should_fit_in_AtomicWord);
    109 
    110   // Adds value to the list.  Note that duplicates are allowed.  Thread-safe and
    111   // blocking (acquires hooklist_spinlock).  Returns true on success; false
    112   // otherwise (failures include invalid value and no space left).
    113   bool Add(T value);
    114 
    115   // Removes the first entry matching value from the list.  Thread-safe and
    116   // blocking (acquires hooklist_spinlock).  Returns true on success; false
    117   // otherwise (failures include invalid value and no value found).
    118   bool Remove(T value);
    119 
    120   // Store up to n values of the list in output_array, and return the number of
    121   // elements stored.  Thread-safe and non-blocking.  This is fast (one memory
    122   // access) if the list is empty.
    123   int Traverse(T* output_array, int n) const;
    124 
    125   // Fast inline implementation for fast path of Invoke*Hook.
    126   bool empty() const {
    127     return base::subtle::Acquire_Load(&priv_end) == 0;
    128   }
    129 
    130   // This internal data is not private so that the class is an aggregate and can
    131   // be initialized by the linker.  Don't access this directly.  Use the
    132   // INIT_HOOK_LIST macro in malloc_hook.cc.
    133 
    134   // One more than the index of the last valid element in priv_data.  During
    135   // 'Remove' this may be past the last valid element in priv_data, but
    136   // subsequent values will be 0.
    137   AtomicWord priv_end;
    138   AtomicWord priv_data[kHookListMaxValues];
    139 };
    140 
    141 extern HookList<MallocHook::NewHook> new_hooks_;
    142 extern HookList<MallocHook::DeleteHook> delete_hooks_;
    143 extern HookList<MallocHook::PreMmapHook> premmap_hooks_;
    144 extern HookList<MallocHook::MmapHook> mmap_hooks_;
    145 extern HookList<MallocHook::MmapReplacement> mmap_replacement_;
    146 extern HookList<MallocHook::MunmapHook> munmap_hooks_;
    147 extern HookList<MallocHook::MunmapReplacement> munmap_replacement_;
    148 extern HookList<MallocHook::MremapHook> mremap_hooks_;
    149 extern HookList<MallocHook::PreSbrkHook> presbrk_hooks_;
    150 extern HookList<MallocHook::SbrkHook> sbrk_hooks_;
    151 
    152 } }  // namespace base::internal
    153 
    154 // The following method is DEPRECATED
    155 inline MallocHook::NewHook MallocHook::GetNewHook() {
    156   return base::internal::new_hook_.Get();
    157 }
    158 
    159 inline void MallocHook::InvokeNewHook(const void* p, size_t s) {
    160   if (!base::internal::new_hooks_.empty()) {
    161     InvokeNewHookSlow(p, s);
    162   }
    163   // The following code is DEPRECATED.
    164   MallocHook::NewHook hook = MallocHook::GetNewHook();
    165   if (hook != NULL) (*hook)(p, s);
    166   // End DEPRECATED code.
    167 }
    168 
    169 // The following method is DEPRECATED
    170 inline MallocHook::DeleteHook MallocHook::GetDeleteHook() {
    171   return base::internal::delete_hook_.Get();
    172 }
    173 
    174 inline void MallocHook::InvokeDeleteHook(const void* p) {
    175   if (!base::internal::delete_hooks_.empty()) {
    176     InvokeDeleteHookSlow(p);
    177   }
    178   // The following code is DEPRECATED.
    179   MallocHook::DeleteHook hook = MallocHook::GetDeleteHook();
    180   if (hook != NULL) (*hook)(p);
    181   // End DEPRECATED code.
    182 }
    183 
    184 // The following method is DEPRECATED
    185 inline MallocHook::PreMmapHook MallocHook::GetPreMmapHook() {
    186   return base::internal::premmap_hook_.Get();
    187 }
    188 
    189 inline void MallocHook::InvokePreMmapHook(const void* start,
    190                                           size_t size,
    191                                           int protection,
    192                                           int flags,
    193                                           int fd,
    194                                           off_t offset) {
    195   if (!base::internal::premmap_hooks_.empty()) {
    196     InvokePreMmapHookSlow(start, size, protection, flags, fd, offset);
    197   }
    198   // The following code is DEPRECATED.
    199   MallocHook::PreMmapHook hook = MallocHook::GetPreMmapHook();
    200   if (hook != NULL) (*hook)(start, size,
    201                             protection, flags,
    202                             fd, offset);
    203   // End DEPRECATED code.
    204 }
    205 
    206 // The following method is DEPRECATED
    207 inline MallocHook::MmapHook MallocHook::GetMmapHook() {
    208   return base::internal::mmap_hook_.Get();
    209 }
    210 
    211 inline void MallocHook::InvokeMmapHook(const void* result,
    212                                        const void* start,
    213                                        size_t size,
    214                                        int protection,
    215                                        int flags,
    216                                        int fd,
    217                                        off_t offset) {
    218   if (!base::internal::mmap_hooks_.empty()) {
    219     InvokeMmapHookSlow(result, start, size, protection, flags, fd, offset);
    220   }
    221   // The following code is DEPRECATED.
    222   MallocHook::MmapHook hook = MallocHook::GetMmapHook();
    223   if (hook != NULL) (*hook)(result,
    224                             start, size,
    225                             protection, flags,
    226                             fd, offset);
    227   // End DEPRECATED code.
    228 }
    229 
    230 inline bool MallocHook::InvokeMmapReplacement(const void* start,
    231                                               size_t size,
    232                                               int protection,
    233                                               int flags,
    234                                               int fd,
    235                                               off_t offset,
    236                                               void** result) {
    237   if (!base::internal::mmap_replacement_.empty()) {
    238     return InvokeMmapReplacementSlow(start, size,
    239                                      protection, flags,
    240                                      fd, offset,
    241                                      result);
    242   }
    243   return false;
    244 }
    245 
    246 // The following method is DEPRECATED
    247 inline MallocHook::MunmapHook MallocHook::GetMunmapHook() {
    248   return base::internal::munmap_hook_.Get();
    249 }
    250 
    251 inline void MallocHook::InvokeMunmapHook(const void* p, size_t size) {
    252   if (!base::internal::munmap_hooks_.empty()) {
    253     InvokeMunmapHookSlow(p, size);
    254   }
    255   // The following code is DEPRECATED.
    256   MallocHook::MunmapHook hook = MallocHook::GetMunmapHook();
    257   if (hook != NULL) (*hook)(p, size);
    258   // End DEPRECATED code.
    259 }
    260 
    261 inline bool MallocHook::InvokeMunmapReplacement(
    262     const void* p, size_t size, int* result) {
    263   if (!base::internal::mmap_replacement_.empty()) {
    264     return InvokeMunmapReplacementSlow(p, size, result);
    265   }
    266   return false;
    267 }
    268 
    269 // The following method is DEPRECATED
    270 inline MallocHook::MremapHook MallocHook::GetMremapHook() {
    271   return base::internal::mremap_hook_.Get();
    272 }
    273 
    274 inline void MallocHook::InvokeMremapHook(const void* result,
    275                                          const void* old_addr,
    276                                          size_t old_size,
    277                                          size_t new_size,
    278                                          int flags,
    279                                          const void* new_addr) {
    280   if (!base::internal::mremap_hooks_.empty()) {
    281     InvokeMremapHookSlow(result, old_addr, old_size, new_size, flags, new_addr);
    282   }
    283   // The following code is DEPRECATED.
    284   MallocHook::MremapHook hook = MallocHook::GetMremapHook();
    285   if (hook != NULL) (*hook)(result,
    286                             old_addr, old_size,
    287                             new_size, flags, new_addr);
    288   // End DEPRECATED code.
    289 }
    290 
    291 // The following method is DEPRECATED
    292 inline MallocHook::PreSbrkHook MallocHook::GetPreSbrkHook() {
    293   return base::internal::presbrk_hook_.Get();
    294 }
    295 
    296 inline void MallocHook::InvokePreSbrkHook(ptrdiff_t increment) {
    297   if (!base::internal::presbrk_hooks_.empty() && increment != 0) {
    298     InvokePreSbrkHookSlow(increment);
    299   }
    300   // The following code is DEPRECATED.
    301   MallocHook::PreSbrkHook hook = MallocHook::GetPreSbrkHook();
    302   if (hook != NULL && increment != 0) (*hook)(increment);
    303   // End DEPRECATED code.
    304 }
    305 
    306 // The following method is DEPRECATED
    307 inline MallocHook::SbrkHook MallocHook::GetSbrkHook() {
    308   return base::internal::sbrk_hook_.Get();
    309 }
    310 
    311 inline void MallocHook::InvokeSbrkHook(const void* result,
    312                                        ptrdiff_t increment) {
    313   if (!base::internal::sbrk_hooks_.empty() && increment != 0) {
    314     InvokeSbrkHookSlow(result, increment);
    315   }
    316   // The following code is DEPRECATED.
    317   MallocHook::SbrkHook hook = MallocHook::GetSbrkHook();
    318   if (hook != NULL && increment != 0) (*hook)(result, increment);
    319   // End DEPRECATED code.
    320 }
    321 
    322 #endif /* _MALLOC_HOOK_INL_H_ */
    323