#include <grpc/support/port_platform.h>
#include "src/core/lib/gpr/arena.h"
#include <string.h>
#include <new>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gprpp/memory.h"
namespace {
enum init_strategy {
NO_INIT, ZERO_INIT, NON_ZERO_INIT, };
gpr_once g_init_strategy_once = GPR_ONCE_INIT;
init_strategy g_init_strategy = NO_INIT;
}
static void set_strategy_from_env() {
char* str = gpr_getenv("GRPC_ARENA_INIT_STRATEGY");
if (str == nullptr) {
g_init_strategy = NO_INIT;
} else if (strcmp(str, "zero_init") == 0) {
g_init_strategy = ZERO_INIT;
} else if (strcmp(str, "non_zero_init") == 0) {
g_init_strategy = NON_ZERO_INIT;
} else {
g_init_strategy = NO_INIT;
}
gpr_free(str);
}
static void* gpr_arena_alloc_maybe_init(size_t size) {
void* mem = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT);
gpr_once_init(&g_init_strategy_once, set_strategy_from_env);
if (GPR_UNLIKELY(g_init_strategy != NO_INIT)) {
if (g_init_strategy == ZERO_INIT) {
memset(mem, 0, size);
} else { memset(mem, 0xFE, size);
}
}
return mem;
}
void gpr_arena_init() {
gpr_once_init(&g_init_strategy_once, set_strategy_from_env);
}
#ifdef SIMPLE_ARENA_FOR_DEBUGGING
struct gpr_arena {
gpr_arena() { gpr_mu_init(&mu); }
~gpr_arena() {
gpr_mu_destroy(&mu);
for (size_t i = 0; i < num_ptrs; ++i) {
gpr_free_aligned(ptrs[i]);
}
gpr_free(ptrs);
}
gpr_mu mu;
void** ptrs = nullptr;
size_t num_ptrs = 0;
};
gpr_arena* gpr_arena_create(size_t ignored_initial_size) {
return grpc_core::New<gpr_arena>();
}
size_t gpr_arena_destroy(gpr_arena* arena) {
grpc_core::Delete(arena);
return 1; }
void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
gpr_mu_lock(&arena->mu);
arena->ptrs =
(void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1));
void* retval = arena->ptrs[arena->num_ptrs++] =
gpr_arena_alloc_maybe_init(size);
gpr_mu_unlock(&arena->mu);
return retval;
}
#else
typedef struct zone {
zone* next = nullptr;
} zone;
struct gpr_arena {
gpr_arena(size_t initial_size)
: initial_zone_size(initial_size), last_zone(&initial_zone) {
gpr_mu_init(&arena_growth_mutex);
}
~gpr_arena() {
gpr_mu_destroy(&arena_growth_mutex);
zone* z = initial_zone.next;
while (z) {
zone* next_z = z->next;
z->~zone();
gpr_free_aligned(z);
z = next_z;
}
}
gpr_atm total_used = 0;
size_t initial_zone_size;
zone initial_zone;
zone* last_zone;
gpr_mu arena_growth_mutex;
};
gpr_arena* gpr_arena_create(size_t initial_size) {
initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size);
return new (gpr_arena_alloc_maybe_init(
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size))
gpr_arena(initial_size);
}
size_t gpr_arena_destroy(gpr_arena* arena) {
const gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used);
arena->~gpr_arena();
gpr_free_aligned(arena);
return static_cast<size_t>(size);
}
void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size);
size_t begin = gpr_atm_no_barrier_fetch_add(&arena->total_used, size);
if (begin + size <= arena->initial_zone_size) {
return reinterpret_cast<char*>(arena) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + begin;
} else {
gpr_mu_lock(&arena->arena_growth_mutex);
zone* z = new (gpr_arena_alloc_maybe_init(
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)) zone();
arena->last_zone->next = z;
arena->last_zone = z;
gpr_mu_unlock(&arena->arena_growth_mutex);
return reinterpret_cast<char*>(z) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone));
}
}
#endif