X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust-libc-wrapper%2Flttng-ust-malloc.c;h=0ad45445f2041e71985562726fcef5fbd809bb78;hb=ae4b659d95f8dab9f2aa4b890d6937d7d5375f07;hp=8296ae29b9e637920b81afc5f75baffa36dae218;hpb=2594a5b4f2b60642973b4941ee506be41786c4d3;p=lttng-ust.git diff --git a/liblttng-ust-libc-wrapper/lttng-ust-malloc.c b/liblttng-ust-libc-wrapper/lttng-ust-malloc.c index 8296ae29..0ad45445 100644 --- a/liblttng-ust-libc-wrapper/lttng-ust-malloc.c +++ b/liblttng-ust-libc-wrapper/lttng-ust-malloc.c @@ -1,34 +1,30 @@ /* - * Copyright (C) 2009 Pierre-Marc Fournier - * Copyright (C) 2011 Mathieu Desnoyers + * SPDX-License-Identifier: LGPL-2.1-or-later * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) 2009 Pierre-Marc Fournier + * Copyright (C) 2011 Mathieu Desnoyers */ -#define _GNU_SOURCE -#include +/* + * Do _not_ define _LGPL_SOURCE because we don't want to create a + * circular dependency loop between this malloc wrapper, liburcu and + * libc. + */ +#include #include #include #include #include #include #include +#include +#include #include +#include #define TRACEPOINT_DEFINE #define TRACEPOINT_CREATE_PROBES +#define TP_IP_PARAM ip #include "ust_libc.h" #define STATIC_CALLOC_LEN 4096 @@ -47,6 +43,50 @@ struct alloc_functions { static struct alloc_functions cur_alloc; +/* + * Make sure our own use of the LTS compat layer will not cause infinite + * recursion by calling calloc. + */ + +static +void *static_calloc(size_t nmemb, size_t size); + +/* + * pthread mutex replacement for URCU tls compat layer. + */ +static int ust_malloc_lock; + +static __attribute__((unused)) +void ust_malloc_spin_lock(pthread_mutex_t *lock) +{ + /* + * The memory barrier within cmpxchg takes care of ordering + * memory accesses with respect to the start of the critical + * section. + */ + while (uatomic_cmpxchg(&ust_malloc_lock, 0, 1) != 0) + caa_cpu_relax(); +} + +static __attribute__((unused)) +void ust_malloc_spin_unlock(pthread_mutex_t *lock) +{ + /* + * Ensure memory accesses within the critical section do not + * leak outside. + */ + cmm_smp_mb(); + uatomic_set(&ust_malloc_lock, 0); +} + +#define calloc static_calloc +#define pthread_mutex_lock ust_malloc_spin_lock +#define pthread_mutex_unlock ust_malloc_spin_unlock +static DEFINE_URCU_TLS(int, malloc_nesting); +#undef pthread_mutex_unlock +#undef pthread_mutex_lock +#undef calloc + /* * Static allocator to use when initially executing dlsym(). It keeps a * size_t value of each object size prior to the object. @@ -69,7 +109,7 @@ void *static_calloc_aligned(size_t nmemb, size_t size, size_t alignment) res_offset = CMM_LOAD_SHARED(static_calloc_buf_offset); do { prev_offset = res_offset; - aligned_offset = ALIGN(prev_offset + sizeof(size_t), alignment); + aligned_offset = LTTNG_UST_ALIGN(prev_offset + sizeof(size_t), alignment); new_offset = aligned_offset + nmemb * size; if (new_offset > sizeof(static_calloc_buf)) { abort(); @@ -86,7 +126,6 @@ void *static_calloc(size_t nmemb, size_t size) void *retval; retval = static_calloc_aligned(nmemb, size, 1); - tracepoint(ust_libc, calloc, nmemb, size, retval); return retval; } @@ -96,7 +135,6 @@ void *static_malloc(size_t size) void *retval; retval = static_calloc_aligned(1, size, 1); - tracepoint(ust_libc, malloc, size, retval); return retval; } @@ -104,7 +142,6 @@ static void static_free(void *ptr) { /* no-op. */ - tracepoint(ust_libc, free, ptr); } static @@ -133,7 +170,6 @@ void *static_realloc(void *ptr, size_t size) if (ptr) memcpy(retval, ptr, *old_size); end: - tracepoint(ust_libc, realloc, ptr, size, retval); return retval; } @@ -143,29 +179,23 @@ void *static_memalign(size_t alignment, size_t size) void *retval; retval = static_calloc_aligned(1, size, alignment); - tracepoint(ust_libc, memalign, alignment, size, retval); return retval; } static int static_posix_memalign(void **memptr, size_t alignment, size_t size) { - int retval = 0; void *ptr; /* Check for power of 2, larger than void *. */ if (alignment & (alignment - 1) || alignment < sizeof(void *) || alignment == 0) { - retval = EINVAL; goto end; } ptr = static_calloc_aligned(1, size, alignment); *memptr = ptr; - if (size && !ptr) - retval = ENOMEM; end: - tracepoint(ust_libc, posix_memalign, *memptr, alignment, size, retval); return 0; } @@ -214,6 +244,7 @@ void *malloc(size_t size) { void *retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.malloc == NULL) { lookup_all_symbols(); if (cur_alloc.malloc == NULL) { @@ -222,21 +253,29 @@ void *malloc(size_t size) } } retval = cur_alloc.malloc(size); - tracepoint(ust_libc, malloc, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(lttng_ust_libc, malloc, + size, retval, LTTNG_UST_CALLER_IP()); + } + URCU_TLS(malloc_nesting)--; return retval; } void free(void *ptr) { - tracepoint(ust_libc, free, ptr); - + URCU_TLS(malloc_nesting)++; /* * Check whether the memory was allocated with * static_calloc_align, in which case there is nothing to free. */ if (caa_unlikely((char *)ptr >= static_calloc_buf && (char *)ptr < static_calloc_buf + STATIC_CALLOC_LEN)) { - return; + goto end; + } + + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(lttng_ust_libc, free, + ptr, LTTNG_UST_CALLER_IP()); } if (cur_alloc.free == NULL) { @@ -247,12 +286,15 @@ void free(void *ptr) } } cur_alloc.free(ptr); +end: + URCU_TLS(malloc_nesting)--; } void *calloc(size_t nmemb, size_t size) { void *retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.calloc == NULL) { lookup_all_symbols(); if (cur_alloc.calloc == NULL) { @@ -261,7 +303,11 @@ void *calloc(size_t nmemb, size_t size) } } retval = cur_alloc.calloc(nmemb, size); - tracepoint(ust_libc, calloc, nmemb, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(lttng_ust_libc, calloc, + nmemb, size, retval, LTTNG_UST_CALLER_IP()); + } + URCU_TLS(malloc_nesting)--; return retval; } @@ -269,7 +315,9 @@ void *realloc(void *ptr, size_t size) { void *retval; - /* Check whether the memory was allocated with + URCU_TLS(malloc_nesting)++; + /* + * Check whether the memory was allocated with * static_calloc_align, in which case there is nothing * to free, and we need to copy the old data. */ @@ -289,6 +337,13 @@ void *realloc(void *ptr, size_t size) if (retval) { memcpy(retval, ptr, *old_size); } + /* + * Mimick that a NULL pointer has been received, so + * memory allocation analysis based on the trace don't + * get confused by the address from the static + * allocator. + */ + ptr = NULL; goto end; } @@ -301,7 +356,11 @@ void *realloc(void *ptr, size_t size) } retval = cur_alloc.realloc(ptr, size); end: - tracepoint(ust_libc, realloc, ptr, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(lttng_ust_libc, realloc, + ptr, size, retval, LTTNG_UST_CALLER_IP()); + } + URCU_TLS(malloc_nesting)--; return retval; } @@ -309,6 +368,7 @@ void *memalign(size_t alignment, size_t size) { void *retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.memalign == NULL) { lookup_all_symbols(); if (cur_alloc.memalign == NULL) { @@ -317,7 +377,12 @@ void *memalign(size_t alignment, size_t size) } } retval = cur_alloc.memalign(alignment, size); - tracepoint(ust_libc, memalign, alignment, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(lttng_ust_libc, memalign, + alignment, size, retval, + LTTNG_UST_CALLER_IP()); + } + URCU_TLS(malloc_nesting)--; return retval; } @@ -325,6 +390,7 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) { int retval; + URCU_TLS(malloc_nesting)++; if (cur_alloc.posix_memalign == NULL) { lookup_all_symbols(); if (cur_alloc.posix_memalign == NULL) { @@ -333,10 +399,21 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) } } retval = cur_alloc.posix_memalign(memptr, alignment, size); - tracepoint(ust_libc, posix_memalign, *memptr, alignment, size, retval); + if (URCU_TLS(malloc_nesting) == 1) { + tracepoint(lttng_ust_libc, posix_memalign, + *memptr, alignment, size, + retval, LTTNG_UST_CALLER_IP()); + } + URCU_TLS(malloc_nesting)--; return retval; } +static +void lttng_ust_fixup_malloc_nesting_tls(void) +{ + asm volatile ("" : : "m" (URCU_TLS(malloc_nesting))); +} + __attribute__((constructor)) void lttng_ust_malloc_wrapper_init(void) { @@ -344,6 +421,7 @@ void lttng_ust_malloc_wrapper_init(void) if (cur_alloc.calloc) { return; } + lttng_ust_fixup_malloc_nesting_tls(); /* * Ensure the allocator is in place before the process becomes * multithreaded.