00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <rosrt/malloc_wrappers.h>
00036
00037 #include <ros/assert.h>
00038 #include <ros/atomic.h>
00039
00040 #include "boost/thread.hpp"
00041
00042 #include <iostream>
00043 #include <dlfcn.h>
00044
00045 #if defined(WIN32)
00046 #define STATIC_TLS_KW __declspec(thread)
00047 #define HAS_TLS_KW 1
00048 #elif defined(__APPLE__)
00049 #define HAS_TLS_KW 0
00050 #else
00051 #define STATIC_TLS_KW __thread
00052 #define HAS_TLS_KW 1
00053 #endif
00054
00055 #if !HAS_TLS_KW
00056 #include <pthread.h>
00057 #define MAX_ALLOC_INFO 1000
00058 #endif
00059
00060 namespace rosrt
00061 {
00062 namespace detail
00063 {
00064
00065 #if HAS_TLS_KW
00066 STATIC_TLS_KW uint64_t g_mallocs = 0;
00067 STATIC_TLS_KW uint64_t g_reallocs = 0;
00068 STATIC_TLS_KW uint64_t g_callocs = 0;
00069 STATIC_TLS_KW uint64_t g_memaligns = 0;
00070 STATIC_TLS_KW uint64_t g_frees = 0;
00071 STATIC_TLS_KW uint64_t g_total_ops = 0;
00072 STATIC_TLS_KW uint64_t g_total_memory_allocated = 0;
00073 STATIC_TLS_KW bool g_break_on_alloc_or_free = false;
00074 #else // HAS_TLS_KW
00075
00076 pthread_key_t g_tls_key;
00077 bool g_tls_key_initialized = false;
00078
00079 AllocInfo g_thread_alloc_info[MAX_ALLOC_INFO];
00080 ros::atomic_bool g_alloc_info_used[MAX_ALLOC_INFO];
00081
00082 void tlsDestructor(void* mem)
00083 {
00084 AllocInfo* info = reinterpret_cast<AllocInfo*>(mem);
00085 uint32_t index = info - g_thread_alloc_info;
00086 ROS_ASSERT(index < MAX_ALLOC_INFO);
00087 g_alloc_info_used[index].store(false);
00088 }
00089
00090 struct MallocTLSInit
00091 {
00092 MallocTLSInit()
00093 {
00094 int ret = pthread_key_create(&g_tls_key, tlsDestructor);
00095 ROS_ASSERT_MSG(!ret, "Failed to create TLS");
00096
00097 for (size_t i = 0; i < MAX_ALLOC_INFO; ++i)
00098 {
00099 g_alloc_info_used[i].store(false);
00100 }
00101
00102 g_tls_key_initialized = true;
00103 }
00104
00105 ~MallocTLSInit()
00106 {
00107 g_tls_key_initialized = false;
00108
00109 pthread_key_delete(g_tls_key);
00110 }
00111 };
00112 MallocTLSInit g_malloc_tls_init;
00113
00114 AllocInfo* allocateAllocInfo()
00115 {
00116 if (!g_tls_key_initialized)
00117 {
00118 return 0;
00119 }
00120
00121 void* info = pthread_getspecific(g_tls_key);
00122 if (!info)
00123 {
00124 for (size_t i = 0; i < MAX_ALLOC_INFO; ++i)
00125 {
00126 if (g_alloc_info_used[i].exchange(true) == false)
00127 {
00128 info = g_thread_alloc_info + i;
00129 pthread_setspecific(g_tls_key, info);
00130 break;
00131 }
00132 }
00133 }
00134
00135 return reinterpret_cast<AllocInfo*>(info);
00136 }
00137
00138 #endif // !HAS_TLS_KW
00139
00140 }
00141
00142 AllocInfo getThreadAllocInfo()
00143 {
00144 AllocInfo info;
00145
00146 #if HAS_TLS_KW
00147 info.mallocs = detail::g_mallocs;
00148 info.callocs = detail::g_callocs;
00149 info.reallocs = detail::g_reallocs;
00150 info.memaligns = detail::g_memaligns;
00151 info.frees = detail::g_frees;
00152 info.total_ops = detail::g_total_ops;
00153 info.total_memory_allocated = detail::g_total_memory_allocated;
00154 info.break_on_alloc_or_free = detail::g_break_on_alloc_or_free;
00155 #else
00156 AllocInfo* tls = detail::allocateAllocInfo();
00157 if (tls)
00158 {
00159 info = *tls;
00160 }
00161 #endif
00162 return info;
00163 }
00164
00165 void resetThreadAllocInfo()
00166 {
00167 #if HAS_TLS_KW
00168 detail::g_mallocs = 0;
00169 detail::g_reallocs = 0;
00170 detail::g_callocs = 0;
00171 detail::g_memaligns = 0;
00172 detail::g_frees = 0;
00173 detail::g_total_ops = 0;
00174 detail::g_total_memory_allocated = 0;
00175 #else
00176 AllocInfo* info = detail::allocateAllocInfo();
00177 if (info)
00178 {
00179 *info = AllocInfo();
00180 }
00181 #endif
00182 }
00183
00184 void setThreadBreakOnAllocOrFree(bool b)
00185 {
00186 #if HAS_TLS_KW
00187 detail::g_break_on_alloc_or_free = b;
00188 #else
00189 AllocInfo* info = detail::allocateAllocInfo();
00190 if (info)
00191 {
00192 info->break_on_alloc_or_free = b;
00193 }
00194 #endif
00195 }
00196
00197 }
00198
00199 extern "C"
00200 {
00201
00202 typedef void* (*MallocType)(size_t size);
00203 typedef void* (*CallocType)(size_t nmemb, size_t size);
00204 typedef void* (*ReallocType)(void *ptr, size_t size);
00205 typedef void* (*MemalignType)(size_t boundary, size_t size);
00206 typedef int (*PosixMemalignType)(void **memptr, size_t alignment, size_t size);
00207 typedef void (*FreeType)(void* ptr);
00208
00209 #if HAS_TLS_KW
00210 #define UPDATE_ALLOC_INFO(result, size, type) \
00211 if (result) \
00212 { \
00213 rosrt::detail::g_total_memory_allocated += size; \
00214 } \
00215 \
00216 ++rosrt::detail::g_##type; \
00217 ++rosrt::detail::g_total_ops; \
00218 \
00219 if (rosrt::detail::g_break_on_alloc_or_free) \
00220 { \
00221 std::cerr << "Issuing break due to break_on_alloc_or_free being set" << std::endl; \
00222 ROS_ISSUE_BREAK(); \
00223 }
00224 #else
00225 #define UPDATE_ALLOC_INFO(result, size, type) \
00226 rosrt::AllocInfo* tls = rosrt::detail::allocateAllocInfo(); \
00227 if (tls) \
00228 { \
00229 if (result) \
00230 { \
00231 tls->total_memory_allocated += size; \
00232 } \
00233 \
00234 ++tls->type; \
00235 ++tls->total_ops; \
00236 \
00237 if (tls->break_on_alloc_or_free) \
00238 { \
00239 std::cerr << "Issuing break due to break_on_alloc_or_free being set" << std::endl; \
00240 ROS_ISSUE_BREAK(); \
00241 } \
00242 }
00243 #endif
00244
00245 void* malloc(size_t size)
00246 {
00247 static MallocType original_function = reinterpret_cast<MallocType>(dlsym(RTLD_NEXT, "malloc"));
00248
00249 void* result = original_function(size);
00250
00251 UPDATE_ALLOC_INFO(result, size, mallocs);
00252
00253 return result;
00254 }
00255
00256 void* __libc_malloc(size_t size)
00257 {
00258 return malloc(size);
00259 }
00260
00261 void* realloc(void* ptr, size_t size)
00262 {
00263 static ReallocType original_function = reinterpret_cast<ReallocType>(dlsym(RTLD_NEXT, "realloc"));
00264
00265 void* result = original_function(ptr, size);
00266
00267 UPDATE_ALLOC_INFO(result, size, reallocs);
00268
00269 return result;
00270 }
00271
00272 void* __libc_realloc(void* ptr, size_t size)
00273 {
00274 return realloc(ptr, size);
00275 }
00276
00277 void* memalign(size_t boundary, size_t size)
00278 {
00279 static MemalignType original_function = reinterpret_cast<MemalignType>(dlsym(RTLD_NEXT, "memalign"));
00280
00281 void* result = original_function(boundary, size);
00282
00283 UPDATE_ALLOC_INFO(result, size, memaligns);
00284
00285 return result;
00286 }
00287
00288 void* __libc_memalign(size_t boundary, size_t size)
00289 {
00290 return memalign(boundary, size);
00291 }
00292
00293 void free(void *ptr)
00294 {
00295 static FreeType original_function = reinterpret_cast<FreeType>(dlsym(RTLD_NEXT, "free"));
00296
00297 original_function(ptr);
00298
00299 uint32_t size = 0;
00300 void* result = 0;
00301 UPDATE_ALLOC_INFO(result, size, frees);
00302 }
00303
00304 void __libc_free(void* ptr)
00305 {
00306 return free(ptr);
00307 }
00308
00309
00310 static void* nullCalloc(size_t nmemb, size_t size)
00311 {
00312 return 0;
00313 }
00314
00315 void* calloc(size_t nmemb, size_t size)
00316 {
00317 static CallocType original_function = 0;
00318 if (original_function == 0)
00319 {
00320 original_function = nullCalloc;
00321 original_function = reinterpret_cast<CallocType>(dlsym(RTLD_NEXT, "calloc"));
00322 }
00323
00324 void* result = original_function(nmemb, size);
00325
00326 UPDATE_ALLOC_INFO(result, size * nmemb, callocs);
00327
00328 return result;
00329 }
00330
00331 void* __libc_calloc(size_t nmemb, size_t size)
00332 {
00333 return calloc(nmemb, size);
00334 }
00335
00336 int posix_memalign(void** ptr, size_t alignment, size_t size) {
00337 static PosixMemalignType original_function = reinterpret_cast<PosixMemalignType>(dlsym(RTLD_NEXT, "posix_memalign"));
00338
00339 int result = original_function(ptr, alignment, size);
00340
00341 UPDATE_ALLOC_INFO(!result, size, memaligns);
00342
00343 return result;
00344 }
00345
00346
00347 }
00348
00349