Pointers.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <err.h>
  17. #include <inttypes.h>
  18. #include <stdatomic.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/mman.h>
  23. #include <unistd.h>
  24. #include "err.h"
  25. #include "Pointers.h"
  26. Pointers::Pointers(size_t max_allocs) {
  27. size_t pagesize = getpagesize();
  28. // Create a mmap that contains a 4:1 ratio of allocations to entries.
  29. // Align to a page.
  30. pointers_size_ = (max_allocs * 4 * sizeof(pointer_data) + pagesize - 1) & ~(pagesize - 1);
  31. max_pointers_ = pointers_size_ / sizeof(pointer_data);
  32. void* memory = mmap(nullptr, pointers_size_, PROT_READ | PROT_WRITE,
  33. MAP_ANON | MAP_PRIVATE, -1, 0);
  34. if (memory == MAP_FAILED) {
  35. err(1, "Unable to allocate data for pointer hash: %zu total_allocs\n", max_allocs);
  36. }
  37. // Make sure that all of the PSS for this is counted right away.
  38. memset(memory, 0, pointers_size_);
  39. pointers_ = reinterpret_cast<pointer_data*>(memory);
  40. }
  41. Pointers::~Pointers() {
  42. if (pointers_ != nullptr) {
  43. munmap(pointers_, pointers_size_);
  44. pointers_ = nullptr;
  45. }
  46. }
  47. void Pointers::Add(uintptr_t key_pointer, void* pointer) {
  48. pointer_data* data = FindEmpty(key_pointer);
  49. if (data == nullptr) {
  50. err(1, "No empty entry found for 0x%" PRIxPTR "\n", key_pointer);
  51. }
  52. atomic_store(&data->key_pointer, key_pointer);
  53. data->pointer = pointer;
  54. }
  55. void* Pointers::Remove(uintptr_t key_pointer) {
  56. if (key_pointer == 0) {
  57. err(1, "Illegal zero value passed to Remove\n");
  58. }
  59. pointer_data* data = Find(key_pointer);
  60. if (data == nullptr) {
  61. err(1, "No pointer value found for 0x%" PRIxPTR "\n", key_pointer);
  62. }
  63. void* pointer = data->pointer;
  64. atomic_store(&data->key_pointer, uintptr_t(0));
  65. return pointer;
  66. }
  67. pointer_data* Pointers::Find(uintptr_t key_pointer) {
  68. size_t index = GetHash(key_pointer);
  69. for (size_t entries = max_pointers_; entries != 0; entries--) {
  70. if (atomic_load(&pointers_[index].key_pointer) == key_pointer) {
  71. return pointers_ + index;
  72. }
  73. if (++index == max_pointers_) {
  74. index = 0;
  75. }
  76. }
  77. return nullptr;
  78. }
  79. pointer_data* Pointers::FindEmpty(uintptr_t key_pointer) {
  80. size_t index = GetHash(key_pointer);
  81. for (size_t entries = 0; entries < max_pointers_; entries++) {
  82. uintptr_t empty = 0;
  83. if (atomic_compare_exchange_strong(&pointers_[index].key_pointer, &empty,
  84. uintptr_t(1))) {
  85. return pointers_ + index;
  86. }
  87. if (++index == max_pointers_) {
  88. index = 0;
  89. }
  90. }
  91. return nullptr;
  92. }
  93. size_t Pointers::GetHash(uintptr_t key_pointer) {
  94. return key_pointer % max_pointers_;
  95. }
  96. void Pointers::FreeAll() {
  97. for (size_t i = 0; i < max_pointers_; i++) {
  98. if (atomic_load(&pointers_[i].key_pointer) != 0) {
  99. free(pointers_[i].pointer);
  100. }
  101. }
  102. }