diff --git a/src/libsysprof/preload/gconstructor.h b/src/libsysprof/preload/gconstructor.h new file mode 100644 index 00000000..df98f835 --- /dev/null +++ b/src/libsysprof/preload/gconstructor.h @@ -0,0 +1,94 @@ +/* + If G_HAS_CONSTRUCTORS is true then the compiler support *both* constructors and + destructors, in a sane way, including e.g. on library unload. If not you're on + your own. + + Some compilers need #pragma to handle this, which does not work with macros, + so the way you need to use this is (for constructors): + + #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA + #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(my_constructor) + #endif + G_DEFINE_CONSTRUCTOR(my_constructor) + static void my_constructor(void) { + ... + } + +*/ + +#ifndef __GTK_DOC_IGNORE__ + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) + +#define G_HAS_CONSTRUCTORS 1 + +#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void); +#define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void); + +#elif defined (_MSC_VER) && (_MSC_VER >= 1500) +/* Visual studio 2008 and later has _Pragma */ + +#define G_HAS_CONSTRUCTORS 1 + +#define G_DEFINE_CONSTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _wrapper(void) { _func(); return 0; } \ + __pragma(section(".CRT$XCU",read)) \ + __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _wrapper; + +#define G_DEFINE_DESTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _constructor(void) { atexit (_func); return 0; } \ + __pragma(section(".CRT$XCU",read)) \ + __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor; + +#elif defined (_MSC_VER) + +#define G_HAS_CONSTRUCTORS 1 + +/* Pre Visual studio 2008 must use #pragma section */ +#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1 +#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1 + +#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \ + section(".CRT$XCU",read) +#define G_DEFINE_CONSTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _wrapper(void) { _func(); return 0; } \ + __declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper; + +#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \ + section(".CRT$XCU",read) +#define G_DEFINE_DESTRUCTOR(_func) \ + static void _func(void); \ + static int _func ## _constructor(void) { atexit (_func); return 0; } \ + __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor; + +#elif defined(__SUNPRO_C) + +/* This is not tested, but i believe it should work, based on: + * http://opensource.apple.com/source/OpenSSL098/OpenSSL098-35/src/fips/fips_premain.c + */ + +#define G_HAS_CONSTRUCTORS 1 + +#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1 +#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1 + +#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \ + init(_func) +#define G_DEFINE_CONSTRUCTOR(_func) \ + static void _func(void); + +#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \ + fini(_func) +#define G_DEFINE_DESTRUCTOR(_func) \ + static void _func(void); + +#else + +/* constructors not supported for this compiler */ + +#endif + +#endif /* __GTK_DOC_IGNORE__ */ diff --git a/src/libsysprof/preload/sysprof-memory-collector.c b/src/libsysprof/preload/sysprof-memory-collector.c index 1e6b240c..a9b81acd 100644 --- a/src/libsysprof/preload/sysprof-memory-collector.c +++ b/src/libsysprof/preload/sysprof-memory-collector.c @@ -16,6 +16,8 @@ #include #include +#include "gconstructor.h" + typedef void *(* RealMalloc) (size_t); typedef void (* RealFree) (void *); typedef void *(* RealCalloc) (size_t, size_t); @@ -36,10 +38,8 @@ static void *scratch_realloc (void *, size_t); static void *scratch_calloc (size_t, size_t); static void scratch_free (void *); -static G_LOCK_DEFINE (writer); -static SysprofCaptureWriter *writer; +static int collector_ready; static int hooked; -static int pid; static ScratchAlloc scratch; static RealCalloc real_calloc = scratch_calloc; static RealFree real_free = scratch_free; @@ -49,6 +49,22 @@ static RealAlignedAlloc real_aligned_alloc; static RealPosixMemalign real_posix_memalign; static RealMemalign real_memalign; +#if defined (G_HAS_CONSTRUCTORS) +# ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +# pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(collector_init_ctor) +# endif +G_DEFINE_CONSTRUCTOR(collector_init_ctor) +#else +# error Your platform/compiler is missing constructor support +#endif + +static void +collector_init_ctor (void) +{ + sysprof_collector_init (); + collector_ready = TRUE; +} + static guint backtrace_func (SysprofCaptureAddress *addrs, guint n_addrs, @@ -134,19 +150,9 @@ scratch_free (void *ptr) return; } -static void -flush_writer (void) -{ - G_LOCK (writer); - sysprof_capture_writer_flush (writer); - G_UNLOCK (writer); -} - static void hook_memtable (void) { - const gchar *env; - if (hooked) return; @@ -161,70 +167,27 @@ hook_memtable (void) real_memalign = dlsym (RTLD_NEXT, "memalign"); unsetenv ("LD_PRELOAD"); - - pid = getpid (); - - /* TODO: We want an API that let's us create a new writer - * per-thread instead of something like this (or using an - * environment variable). That will require a control channel - * to sysprof to request new writer/muxed APIs. - */ - - env = getenv ("MEMPROF_TRACE_FD"); - - if (env != NULL) - { - int fd = atoi (env); - - if (fd > 0) - writer = sysprof_capture_writer_new_from_fd (fd, 0); - } - - if (writer == NULL) - writer = sysprof_capture_writer_new ("memory.syscap", 0); - - atexit (flush_writer); } -#define gettid() syscall(__NR_gettid, 0) - static inline void track_malloc (void *ptr, size_t size) { - if G_UNLIKELY (!writer) - return; - - G_LOCK (writer); - sysprof_capture_writer_add_allocation (writer, - SYSPROF_CAPTURE_CURRENT_TIME, - sched_getcpu (), - pid, - gettid(), - GPOINTER_TO_SIZE (ptr), - size, - backtrace_func, - NULL); - G_UNLOCK (writer); + if G_LIKELY (ptr && collector_ready) + sysprof_collector_allocate (GPOINTER_TO_SIZE (ptr), + size, + backtrace_func, + NULL); } static inline void track_free (void *ptr) { - if G_UNLIKELY (!writer) - return; - - G_LOCK (writer); - sysprof_capture_writer_add_allocation (writer, - SYSPROF_CAPTURE_CURRENT_TIME, - sched_getcpu (), - pid, - gettid(), - GPOINTER_TO_SIZE (ptr), - 0, - backtrace_func, - 0); - G_UNLOCK (writer); + if G_LIKELY (ptr && collector_ready) + sysprof_collector_allocate (GPOINTER_TO_SIZE (ptr), + 0, + backtrace_func, + NULL); } void *