123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- /*
- * Copyright 2014-present Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #pragma once
- #include <climits> // for PATH_MAX
- #include <cstring>
- #include <memory>
- #include <mutex>
- #include <string>
- #include <unordered_map>
- #include <vector>
- #include <boost/container/flat_map.hpp>
- #include <boost/intrusive/list.hpp>
- #include <boost/operators.hpp>
- #include <glog/logging.h>
- #include <folly/Range.h>
- #include <folly/experimental/symbolizer/Elf.h>
- #include <folly/hash/Hash.h>
- namespace folly {
- namespace symbolizer {
- /**
- * Number of ELF files loaded by the dynamic loader.
- */
- size_t countLoadedElfFiles();
- class ElfCacheBase {
- public:
- virtual std::shared_ptr<ElfFile> getFile(StringPiece path) = 0;
- virtual ~ElfCacheBase() {}
- };
- /**
- * Cache ELF files. Async-signal-safe: does memory allocation upfront.
- *
- * Will not grow; once the capacity is reached, lookups for files that
- * aren't already in the cache will fail (return nullptr).
- *
- * Not MT-safe. May not be used concurrently from multiple threads.
- *
- * NOTE that async-signal-safety is preserved only as long as the
- * SignalSafeElfCache object exists; after the SignalSafeElfCache object
- * is destroyed, destroying returned shared_ptr<ElfFile> objects may
- * cause ElfFile objects to be destroyed, and that's not async-signal-safe.
- */
- class SignalSafeElfCache : public ElfCacheBase {
- public:
- explicit SignalSafeElfCache(size_t capacity);
- std::shared_ptr<ElfFile> getFile(StringPiece path) override;
- private:
- // We can't use std::string (allocating memory is bad!) so we roll our
- // own wrapper around a fixed-size, null-terminated string.
- class Path : private boost::totally_ordered<Path> {
- public:
- Path() {
- assign(folly::StringPiece());
- }
- explicit Path(StringPiece s) {
- assign(s);
- }
- void assign(StringPiece s) {
- DCHECK_LE(s.size(), kMaxSize);
- if (!s.empty()) {
- memcpy(data_, s.data(), s.size());
- }
- data_[s.size()] = '\0';
- }
- bool operator<(const Path& other) const {
- return strcmp(data_, other.data_) < 0;
- }
- bool operator==(const Path& other) const {
- return strcmp(data_, other.data_) == 0;
- }
- const char* data() const {
- return data_;
- }
- static constexpr size_t kMaxSize = PATH_MAX - 1;
- private:
- char data_[kMaxSize + 1];
- };
- Path scratchpad_; // Preallocated key for map_ lookups.
- boost::container::flat_map<Path, int> map_;
- std::vector<std::shared_ptr<ElfFile>> slots_;
- };
- /**
- * General-purpose ELF file cache.
- *
- * LRU of given capacity. MT-safe (uses locking). Not async-signal-safe.
- */
- class ElfCache : public ElfCacheBase {
- public:
- explicit ElfCache(size_t capacity);
- std::shared_ptr<ElfFile> getFile(StringPiece path) override;
- private:
- std::mutex mutex_;
- typedef boost::intrusive::list_member_hook<> LruLink;
- struct Entry {
- std::string path;
- ElfFile file;
- LruLink lruLink;
- };
- static std::shared_ptr<ElfFile> filePtr(const std::shared_ptr<Entry>& e);
- size_t capacity_;
- std::unordered_map<StringPiece, std::shared_ptr<Entry>, Hash> files_;
- typedef boost::intrusive::list<
- Entry,
- boost::intrusive::member_hook<Entry, LruLink, &Entry::lruLink>,
- boost::intrusive::constant_time_size<false>>
- LruList;
- LruList lruList_;
- };
- } // namespace symbolizer
- } // namespace folly
|