/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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 <atomic>
#include <cassert>
#include <cstdint>
#include <system_error>
#include <folly/Exception.h>
#include <folly/portability/SysMman.h>
#include <folly/portability/Unistd.h>
namespace folly {
namespace detail {
class MMapAlloc {
private:
size_t computeSize(size_t size) {
long pagesize = sysconf(_SC_PAGESIZE);
size_t mmapLength = ((size - 1) & ~(pagesize - 1)) + pagesize;
assert(size <= mmapLength && mmapLength < size + pagesize);
assert((mmapLength % pagesize) == 0);
return mmapLength;
}
public:
void* allocate(size_t size) {
auto len = computeSize(size);
int extraflags = 0;
#if defined(MAP_POPULATE)
extraflags |= MAP_POPULATE;
#endif
// MAP_HUGETLB is a perf win, but requires cooperation from the
// deployment environment (and a change to computeSize()).
void* mem = static_cast<void*>(mmap(
nullptr,
len,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | extraflags,
-1,
0));
if (mem == reinterpret_cast<void*>(-1)) {
throw std::system_error(errno, errorCategoryForErrnoDomain());
}
#if !defined(MAP_POPULATE) && defined(MADV_WILLNEED)
madvise(mem, size, MADV_WILLNEED);
#endif
return mem;
}
void deallocate(void* p, size_t size) {
auto len = computeSize(size);
munmap(p, len);
}
};
template <typename Allocator>
struct GivesZeroFilledMemory : public std::false_type {};
template <>
struct GivesZeroFilledMemory<MMapAlloc> : public std::true_type {};
} // namespace detail
} // namespace folly