bee0cb4d08e9c736f198599cb4079afcaff646a8
[folly.git] / folly / experimental / symbolizer / ElfCache.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
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
17 #include <folly/experimental/symbolizer/ElfCache.h>
18
19 namespace folly { namespace symbolizer {
20
21 SignalSafeElfCache::SignalSafeElfCache(size_t capacity) {
22   map_.reserve(capacity);
23   slots_.reserve(capacity);
24
25   // Preallocate
26   for (size_t i = 0; i < capacity; ++i) {
27     slots_.push_back(std::make_shared<ElfFile>());
28   }
29 }
30
31 std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
32   if (p.size() > Path::kMaxSize) {
33     return nullptr;
34   }
35
36   Path path(p);
37   auto pos = map_.find(path);
38   if (pos != map_.end()) {
39     return slots_[pos->second];
40   }
41
42   size_t n = map_.size();
43   if (n >= slots_.size()) {
44     DCHECK_EQ(map_.size(), slots_.size());
45     return nullptr;
46   }
47
48   auto& f = slots_[n];
49
50   const char* msg = "";
51   int r = f->openNoThrow(path.data(), true, &msg);
52   if (r != ElfFile::kSuccess) {
53     return nullptr;
54   }
55
56   map_[path] = n;
57   return f;
58 }
59
60 ElfCache::ElfCache(size_t capacity) : capacity_(capacity) { }
61
62 std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
63   std::lock_guard<std::mutex> lock(mutex_);
64
65   auto pos = files_.find(p);
66   if (pos != files_.end()) {
67     // Found, move to back (MRU)
68     auto& entry = pos->second;
69     lruList_.erase(lruList_.iterator_to(*entry));
70     lruList_.push_back(*entry);
71     return filePtr(entry);
72   }
73
74   auto entry = std::make_shared<Entry>();
75   entry->path = p.str();
76   auto& path = entry->path;
77
78   // No negative caching
79   const char* msg = "";
80   int r = entry->file.openNoThrow(path.c_str(), true, &msg);
81   if (r != ElfFile::kSuccess) {
82     return nullptr;
83   }
84
85   if (files_.size() == capacity_) {
86     auto& e = lruList_.front();
87     lruList_.pop_front();
88     files_.erase(e.path);
89   }
90
91   files_.emplace(entry->path, entry);
92   lruList_.push_back(*entry);
93
94   return filePtr(entry);
95 }
96
97 std::shared_ptr<ElfFile> ElfCache::filePtr(const std::shared_ptr<Entry>& e) {
98   // share ownership
99   return std::shared_ptr<ElfFile>(e, &e->file);
100 }
101
102 }}  // namespaces