blob: a1619ae84399c9776322d799699d2125c8bde648 [file] [log] [blame]
/*
* Copyright 2016-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.
*/
#include <unistd.h>
#include <sys/types.h>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include "tscore/ink_memory.h"
#include "tscore/ink_error.h"
#include "tscore/ink_assert.h"
#include "tscore/ink_align.h"
#include "tscore/JeAllocator.h"
namespace jearena
{
JemallocNodumpAllocator::JemallocNodumpAllocator()
{
extend_and_setup_arena();
}
#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
extent_hooks_t JemallocNodumpAllocator::extent_hooks_;
extent_alloc_t *JemallocNodumpAllocator::original_alloc_ = nullptr;
void *
JemallocNodumpAllocator::alloc(extent_hooks_t *extent, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit,
unsigned arena_ind)
{
void *result = original_alloc_(extent, new_addr, size, alignment, zero, commit, arena_ind);
if (result != nullptr) {
// Seems like we don't really care if the advice went through
// in the original code, so just keeping it the same here.
ats_madvise((caddr_t)result, size, MADV_DONTDUMP);
}
return result;
}
#endif /* JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED */
bool
JemallocNodumpAllocator::extend_and_setup_arena()
{
#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
size_t arena_index_len_ = sizeof(arena_index_);
if (auto ret = mallctl("arenas.create", &arena_index_, &arena_index_len_, nullptr, 0)) {
ink_abort("Unable to extend arena: %s", std::strerror(ret));
}
flags_ = MALLOCX_ARENA(arena_index_) | MALLOCX_TCACHE_NONE;
// Read the existing hooks
const auto key = "arena." + std::to_string(arena_index_) + ".extent_hooks";
extent_hooks_t *hooks;
size_t hooks_len = sizeof(hooks);
if (auto ret = mallctl(key.c_str(), &hooks, &hooks_len, nullptr, 0)) {
ink_abort("Unable to get the hooks: %s", std::strerror(ret));
}
if (original_alloc_ == nullptr) {
original_alloc_ = hooks->alloc;
} else {
ink_release_assert(original_alloc_ == hooks->alloc);
}
// Set the custom hook
extent_hooks_ = *hooks;
extent_hooks_.alloc = &JemallocNodumpAllocator::alloc;
extent_hooks_t *new_hooks = &extent_hooks_;
if (auto ret = mallctl(key.c_str(), nullptr, nullptr, &new_hooks, sizeof(new_hooks))) {
ink_abort("Unable to set the hooks: %s", std::strerror(ret));
}
return true;
#else /* JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED */
return false;
#endif /* JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED */
}
/**
* This will retain the original functionality if
* !defined(JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED)
*/
void *
JemallocNodumpAllocator::allocate(InkFreeList *f)
{
void *newp = nullptr;
if (f->advice) {
#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
if (likely(f->type_size > 0)) {
int flags = flags_ | MALLOCX_ALIGN(f->alignment);
if (unlikely((newp = mallocx(f->type_size, flags)) == nullptr)) {
ink_abort("couldn't allocate %u bytes", f->type_size);
}
}
#else
newp = ats_memalign(f->alignment, f->type_size);
if (INK_ALIGN((uint64_t)newp, ats_pagesize()) == (uint64_t)newp) {
ats_madvise(static_cast<caddr_t>(newp), INK_ALIGN(f->type_size, f->alignment), f->advice);
}
#endif
} else {
newp = ats_memalign(f->alignment, f->type_size);
}
return newp;
}
/**
* This will retain the original functionality if
* !defined(JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED)
*/
void
JemallocNodumpAllocator::deallocate(InkFreeList *f, void *ptr)
{
if (f->advice) {
#ifdef JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
if (likely(ptr)) {
dallocx(ptr, flags_);
}
#else
ats_memalign_free(ptr);
#endif
} else {
ats_memalign_free(ptr);
}
}
JemallocNodumpAllocator &
globalJemallocNodumpAllocator()
{
static auto instance = new JemallocNodumpAllocator();
return *instance;
}
} // namespace jearena