| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <sys/mman.h> |
| #include <unistd.h> |
| |
| #include <lib/fxl/files/file.h> |
| #include <lib/fxl/logging.h> |
| |
| #include "file_reader.h" |
| |
| namespace cpuperf { |
| |
| bool FileReader::Create(FileNameProducer file_name_producer, |
| uint32_t num_traces, |
| std::unique_ptr<FileReader>* out_reader) { |
| out_reader->reset(new FileReader(std::move(file_name_producer), num_traces)); |
| return true; |
| } |
| |
| FileReader::FileReader(FileNameProducer file_name_producer, |
| uint32_t num_traces) |
| : Reader(num_traces), |
| file_name_producer_(std::move(file_name_producer)) { |
| } |
| |
| bool FileReader::MapBuffer(const std::string& name, uint32_t trace_num) { |
| if (!UnmapBuffer()) { |
| return false; |
| } |
| |
| std::string file_name = file_name_producer_(trace_num); |
| int raw_fd = open(file_name.c_str(), O_RDONLY); |
| if (raw_fd < 0) { |
| FXL_LOG(ERROR) << name << ": Unable to open buffer file: " << file_name |
| << ": " << strerror(errno); |
| return false; |
| } |
| fxl::UniqueFD fd(raw_fd); |
| file_size_ = lseek(raw_fd, 0, SEEK_END); |
| lseek(raw_fd, 0, SEEK_SET); |
| #ifdef __Fuchsia__ |
| // Mmap can currently fail if the file is on minfs, so just punt. |
| void* buffer = reinterpret_cast<void*>(-1); |
| #else |
| void* buffer = mmap(nullptr, file_size_, PROT_READ, MAP_PRIVATE, raw_fd, 0); |
| if (buffer == reinterpret_cast<void*>(-1)) { |
| FXL_VLOG(2) << name << ": Unable to map buffer file: " << file_name |
| << ": " << strerror(errno); |
| } |
| #endif |
| if (buffer == reinterpret_cast<void*>(-1)) { |
| // Workaround this by just reading in the file. |
| std::pair<uint8_t*, intptr_t> bytes = |
| files::ReadFileDescriptorToBytes(raw_fd); |
| if (bytes.first == nullptr) { |
| FXL_LOG(ERROR) << "Error reading: " << file_name; |
| return false; |
| } |
| if (static_cast<size_t>(bytes.second) != file_size_) { |
| FXL_LOG(ERROR) << "Error reading: " << file_name |
| << ": got " << bytes.second |
| << " bytes instead of expected " << file_size_; |
| return false; |
| } |
| buffer = reinterpret_cast<void*>(bytes.first); |
| file_is_mmapped_ = false; |
| } else { |
| file_is_mmapped_ = true; |
| } |
| buffer_contents_ = buffer; |
| |
| ReaderStatus status = BufferReader::Create(name, buffer_contents_, |
| file_size_, &buffer_reader_); |
| if (status != ReaderStatus::kOk) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool FileReader::UnmapBuffer() { |
| if (buffer_contents_) { |
| buffer_reader_.reset(); |
| if (file_is_mmapped_) { |
| auto buffer = const_cast<void*>(buffer_contents_); |
| int error = munmap(buffer, file_size_); |
| if (error != 0) { |
| FXL_LOG(ERROR) << "Unable to unmap buffer: " << strerror(errno); |
| return false; |
| } |
| } else { |
| free(const_cast<void*>(buffer_contents_)); |
| } |
| buffer_contents_ = nullptr; |
| } |
| return true; |
| } |
| |
| } // namespace cpuperf |