blob: 611782a0b224e8b68ba12c5c16d31d26871e9e13 [file] [log] [blame]
/* malloc.c - Memory allocator - Public Domain - 2016 Mattias Jansson / Rampant Pixels
*
* This library provides a cross-platform lock free thread caching malloc implementation in C11.
* The latest source code is always available at
*
* https://github.com/rampantpixels/rpmalloc
*
* This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
*
*/
#include "rpmalloc.h"
//This file provides overrides for the standard library malloc style entry points
extern void*
calloc(size_t count, size_t size);
extern void
free(void* ptr);
extern void*
malloc(size_t size);
extern void *
realloc(void* ptr, size_t size);
extern void*
aligned_alloc(size_t alignment, size_t size);
extern void*
memalign(size_t alignment, size_t size);
extern int
posix_memalign(void** memptr, size_t alignment, size_t size);
extern size_t
malloc_usable_size(void* ptr);
void*
calloc(size_t count, size_t size) {
return rpcalloc(count, size);
}
void
free(void* ptr) {
rpfree(ptr);
}
void*
malloc(size_t size) {
return rpmalloc(size);
}
void*
realloc(void* ptr, size_t size) {
return rprealloc(ptr, size);
}
void*
aligned_alloc(size_t alignment, size_t size) {
return rpaligned_alloc(alignment, size);
}
void*
memalign(size_t alignment, size_t size) {
return rpmemalign(alignment, size);
}
int
posix_memalign(void** memptr, size_t alignment, size_t size) {
return rpposix_memalign(memptr, alignment, size);
}
size_t
malloc_usable_size(void* ptr) {
return rpmalloc_usable_size(ptr);
}
#ifdef _WIN32
//TODO: Injection from rpmalloc compiled as DLL not yet implemented
#else
#include <pthread.h>
#include <stdlib.h>
static pthread_key_t destructor_key;
static void
thread_destructor(void*);
static __attribute__((constructor)) void
initialize_rpmalloc(void) {
pthread_key_create(&destructor_key, thread_destructor);
rpmalloc_initialize();
}
static __attribute__((destructor)) void
finalize_rpmalloc(void) {
rpmalloc_finalize();
}
typedef struct {
void* (*real_start)(void*);
void* real_arg;
} thread_starter_arg;
static void*
thread_starter(void* argptr) {
thread_starter_arg* arg = argptr;
void* (*real_start)(void*) = arg->real_start;
void* real_arg = arg->real_arg;
rpmalloc_thread_initialize();
rpfree(argptr);
pthread_setspecific(destructor_key, (void*)1);
return (*real_start)(real_arg);
}
static void
thread_destructor(void* value) {
(void)sizeof(value);
rpmalloc_thread_finalize();
}
#ifdef __APPLE__
static int
pthread_create_proxy(pthread_t* thread,
const pthread_attr_t* attr,
void* (*start_routine)(void*),
void* arg) {
rpmalloc_thread_initialize();
thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
starter_arg->real_start = start_routine;
starter_arg->real_arg = arg;
return pthread_create(thread, attr, thread_starter, starter_arg);
}
typedef struct interpose_s {
void* new_func;
void* orig_func;
} interpose_t;
#define MAC_INTERPOSE(newf, oldf) __attribute__((used)) \
static const interpose_t macinterpose##newf##oldf \
__attribute__ ((section("__DATA, __interpose"))) = \
{ (void *) newf, (void *) oldf }
MAC_INTERPOSE(pthread_create_proxy, pthread_create);
#else
#include <dlfcn.h>
int
pthread_create(pthread_t* thread,
const pthread_attr_t* attr,
void* (*start_routine)(void*),
void* arg) {
#if defined(__linux__) || defined(__APPLE__)
char fname[] = "pthread_create";
#else
char fname[] = "_pthread_create";
#endif
void* real_pthread_create = dlsym(RTLD_NEXT, fname);
rpmalloc_thread_initialize();
thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
starter_arg->real_start = start_routine;
starter_arg->real_arg = arg;
return (*(int (*)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*))real_pthread_create)(thread, attr, thread_starter, starter_arg);
}
#endif
#endif