14835251cSDave Rigby/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
24835251cSDave Rigby/*
34835251cSDave Rigby *     Copyright 2016 Couchbase, Inc
44835251cSDave Rigby *
54835251cSDave Rigby *   Licensed under the Apache License, Version 2.0 (the "License");
64835251cSDave Rigby *   you may not use this file except in compliance with the License.
74835251cSDave Rigby *   You may obtain a copy of the License at
84835251cSDave Rigby *
94835251cSDave Rigby *       http://www.apache.org/licenses/LICENSE-2.0
104835251cSDave Rigby *
114835251cSDave Rigby *   Unless required by applicable law or agreed to in writing, software
124835251cSDave Rigby *   distributed under the License is distributed on an "AS IS" BASIS,
134835251cSDave Rigby *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144835251cSDave Rigby *   See the License for the specific language governing permissions and
154835251cSDave Rigby *   limitations under the License.
164835251cSDave Rigby */
174835251cSDave Rigby
184835251cSDave Rigby#include <platform/cb_malloc.h>
194835251cSDave Rigby
204835251cSDave Rigby#include <cstring>
214835251cSDave Rigby
224835251cSDave Rigby// Which underlying memory allocator should we use?
234835251cSDave Rigby#if defined(HAVE_JEMALLOC)
24d74f1970SDave Rigby#  define MALLOC_PREFIX je_
254835251cSDave Rigby/* Irrespective of how jemalloc was configured on this platform,
264835251cSDave Rigby * don't rename je_FOO to FOO.
274835251cSDave Rigby */
284835251cSDave Rigby#  define JEMALLOC_NO_RENAME
294835251cSDave Rigby#  include <jemalloc/jemalloc.h>
304835251cSDave Rigby
314835251cSDave Rigby#else /* system allocator */
324835251cSDave Rigby#  define MALLOC_PREFIX
33a06044f3SJames Harrison#if defined(HAVE_MALLOC_USABLE_SIZE)
34a06044f3SJames Harrison#include <malloc.h>
35a06044f3SJames Harrison#endif
364835251cSDave Rigby#endif
374835251cSDave Rigby
384835251cSDave Rigby
394835251cSDave Rigby// User-registered new and delete hooks
404835251cSDave Rigbycb_malloc_new_hook_t cb_new_hook = nullptr;
414835251cSDave Rigbycb_malloc_delete_hook_t cb_delete_hook = nullptr;
424835251cSDave Rigby
434835251cSDave Rigby// Macros to form the name of the memory allocation function to use based on
444835251cSDave Rigby// the compile-time selected malloc library's prefix ('je_', 'tc_', '')
454835251cSDave Rigby#define CONCAT(A, B) A ## B
464835251cSDave Rigby#define CONCAT2(A, B) CONCAT(A, B)
474835251cSDave Rigby#define MEM_ALLOC(name) CONCAT2(MALLOC_PREFIX, name)
484835251cSDave Rigby
49becffd3bSTrond NorbyePLATFORM_PUBLIC_API void* cb_malloc(size_t size) throw() {
504835251cSDave Rigby    void* ptr = MEM_ALLOC(malloc)(size);
514835251cSDave Rigby    cb_invoke_new_hook(ptr, size);
524835251cSDave Rigby    return ptr;
534835251cSDave Rigby}
544835251cSDave Rigby
55becffd3bSTrond NorbyePLATFORM_PUBLIC_API void* cb_calloc(size_t nmemb, size_t size) throw() {
564835251cSDave Rigby    void* ptr = MEM_ALLOC(calloc)(nmemb, size);
574835251cSDave Rigby    cb_invoke_new_hook(ptr, nmemb * size);
584835251cSDave Rigby    return ptr;
594835251cSDave Rigby}
604835251cSDave Rigby
61becffd3bSTrond NorbyePLATFORM_PUBLIC_API void* cb_realloc(void* ptr, size_t size) throw() {
624835251cSDave Rigby    cb_invoke_delete_hook(ptr);
634835251cSDave Rigby    void* result = MEM_ALLOC(realloc)(ptr, size);
644835251cSDave Rigby    cb_invoke_new_hook(result, size);
654835251cSDave Rigby    return result;
664835251cSDave Rigby}
674835251cSDave Rigby
68becffd3bSTrond NorbyePLATFORM_PUBLIC_API void cb_free(void* ptr) throw() {
694835251cSDave Rigby    cb_invoke_delete_hook(ptr);
704835251cSDave Rigby    return MEM_ALLOC(free)(ptr);
714835251cSDave Rigby}
724835251cSDave Rigby
73becffd3bSTrond NorbyePLATFORM_PUBLIC_API void cb_sized_free(void* ptr, size_t size) throw() {
74b2487b03SJames Harrison    cb_invoke_delete_hook(ptr);
75b2487b03SJames Harrison#if defined(HAVE_JEMALLOC_SDALLOCX)
76b2487b03SJames Harrison    if (ptr != nullptr) {
77b2487b03SJames Harrison        MEM_ALLOC(sdallocx)(ptr, size, /* no flags */ 0);
78b2487b03SJames Harrison    }
79b2487b03SJames Harrison#else
80b2487b03SJames Harrison    MEM_ALLOC(free)(ptr);
81b2487b03SJames Harrison#endif
82b2487b03SJames Harrison}
83b2487b03SJames Harrison
844835251cSDave RigbyPLATFORM_PUBLIC_API char* cb_strdup(const char* s1) {
854835251cSDave Rigby    size_t len = std::strlen(s1);
864835251cSDave Rigby    char* result = static_cast<char*>(cb_malloc(len + 1));
874835251cSDave Rigby    if (result != nullptr) {
884835251cSDave Rigby        std::strncpy(result, s1, len + 1);
894835251cSDave Rigby    }
904835251cSDave Rigby    return result;
914835251cSDave Rigby}
924835251cSDave Rigby
93a06044f3SJames Harrison#if defined(HAVE_MALLOC_USABLE_SIZE)
94becffd3bSTrond NorbyePLATFORM_PUBLIC_API size_t cb_malloc_usable_size(void* ptr) throw() {
95becffd3bSTrond Norbye    return MEM_ALLOC(malloc_usable_size)(ptr);
96a06044f3SJames Harrison}
97a06044f3SJames Harrison#endif
98a06044f3SJames Harrison
994835251cSDave Rigby/*
1004835251cSDave Rigby * Allocation / deallocation hook functions.
1014835251cSDave Rigby */
1024835251cSDave Rigbybool cb_add_new_hook(cb_malloc_new_hook_t f) {
1034835251cSDave Rigby    if (cb_new_hook == nullptr) {
1044835251cSDave Rigby        cb_new_hook = f;
1054835251cSDave Rigby        return true;
1064835251cSDave Rigby    } else {
1074835251cSDave Rigby        return false;
1084835251cSDave Rigby    }
1094835251cSDave Rigby}
1104835251cSDave Rigby
1114835251cSDave Rigbybool cb_remove_new_hook(cb_malloc_new_hook_t f) {
1124835251cSDave Rigby    if (cb_new_hook == f) {
1134835251cSDave Rigby        cb_new_hook = nullptr;
1144835251cSDave Rigby        return true;
1154835251cSDave Rigby    } else {
1164835251cSDave Rigby        return false;
1174835251cSDave Rigby    }
1184835251cSDave Rigby}
1194835251cSDave Rigby
1204835251cSDave Rigbybool cb_add_delete_hook(cb_malloc_delete_hook_t f) {
1214835251cSDave Rigby    if (cb_delete_hook == nullptr) {
1224835251cSDave Rigby        cb_delete_hook = f;
1234835251cSDave Rigby        return true;
1244835251cSDave Rigby    } else {
1254835251cSDave Rigby        return false;
1264835251cSDave Rigby    }
1274835251cSDave Rigby}
1284835251cSDave Rigby
1294835251cSDave Rigbybool cb_remove_delete_hook(cb_malloc_delete_hook_t f) {
1304835251cSDave Rigby    if (cb_delete_hook == f) {
1314835251cSDave Rigby        cb_delete_hook = nullptr;
1324835251cSDave Rigby        return true;
1334835251cSDave Rigby    } else {
1344835251cSDave Rigby        return false;
1354835251cSDave Rigby    }
1364835251cSDave Rigby}
1374835251cSDave Rigby
1384835251cSDave Rigbyvoid cb_invoke_new_hook(const void* ptr, size_t size) {
1394835251cSDave Rigby    if (cb_new_hook != nullptr) {
1404835251cSDave Rigby        cb_new_hook(ptr, size);
1414835251cSDave Rigby    }
1424835251cSDave Rigby}
1434835251cSDave Rigby
1444835251cSDave Rigbyvoid cb_invoke_delete_hook(const void* ptr) {
1454835251cSDave Rigby    if (cb_delete_hook != nullptr) {
1464835251cSDave Rigby        cb_delete_hook(ptr);
1474835251cSDave Rigby    }
1484835251cSDave Rigby}