aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys/common/erl_mtrace_sys_wrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/sys/common/erl_mtrace_sys_wrap.c')
-rw-r--r--erts/emulator/sys/common/erl_mtrace_sys_wrap.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/erts/emulator/sys/common/erl_mtrace_sys_wrap.c b/erts/emulator/sys/common/erl_mtrace_sys_wrap.c
new file mode 100644
index 0000000000..408aa7e016
--- /dev/null
+++ b/erts/emulator/sys/common/erl_mtrace_sys_wrap.c
@@ -0,0 +1,245 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "sys.h"
+#include "erl_mtrace.h"
+
+#ifdef ERTS_CAN_TRACK_MALLOC
+#if defined(HAVE_END_SYMBOL)
+extern char end;
+#elif defined(HAVE__END_SYMBOL)
+extern char _end;
+#endif
+
+static int inited = 0;
+static int init(void);
+
+static volatile char *heap_start = NULL;
+static volatile char *heap_end = NULL;
+
+#if defined(ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC) /* ----------------- */
+
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
+#undef SBRK_0
+#define SBRK_0 sbrk(0)
+
+static void
+init_hook(void)
+{
+ __after_morecore_hook = erts_mtrace_update_heap_size;
+ if (inited)
+ return;
+ heap_end = NULL;
+#if defined(HAVE_END_SYMBOL)
+ heap_start = &end;
+#elif defined(HAVE__END_SYMBOL)
+ heap_start = &_end;
+#else
+ heap_start = SBRK_0;
+ if (heap_start == (SBRK_RET_TYPE) -1) {
+ heap_start = NULL;
+ return;
+ }
+#endif
+ inited = 1;
+}
+
+static int
+init(void)
+{
+ init_hook();
+ return inited;
+}
+
+void (*__malloc_initialize_hook)(void) = init_hook;
+
+#elif defined(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC) /* ------------------------ */
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+#undef SBRK_0
+#define SBRK_0 (*real_sbrk)(0)
+
+#ifndef HAVE_SBRK
+# error no sbrk()
+#endif
+#if !defined(HAVE_END_SYMBOL) && !defined(HAVE__END_SYMBOL)
+# error no 'end' nor '_end'
+#endif
+
+static void update_heap_size(char *new_end);
+
+#define SBRK_IMPL(RET_TYPE, FUNC, ARG_TYPE) \
+RET_TYPE FUNC (ARG_TYPE); \
+static RET_TYPE (*real_ ## FUNC)(ARG_TYPE) = NULL; \
+RET_TYPE FUNC (ARG_TYPE arg) \
+{ \
+ RET_TYPE res; \
+ if (!inited && !init()) \
+ return (RET_TYPE) -1; \
+ res = (*real_ ## FUNC)(arg); \
+ if (erts_mtrace_enabled && res != ((RET_TYPE) -1)) \
+ update_heap_size((char *) (*real_ ## FUNC)(0)); \
+ return res; \
+}
+
+#define BRK_IMPL(RET_TYPE, FUNC, ARG_TYPE) \
+RET_TYPE FUNC (ARG_TYPE); \
+static RET_TYPE (*real_ ## FUNC)(ARG_TYPE) = NULL; \
+RET_TYPE FUNC (ARG_TYPE arg) \
+{ \
+ RET_TYPE res; \
+ if (!inited && !init()) \
+ return (RET_TYPE) -1; \
+ res = (*real_ ## FUNC)(arg); \
+ if (erts_mtrace_enabled && res != ((RET_TYPE) -1)) \
+ update_heap_size((char *) arg); \
+ return res; \
+}
+
+SBRK_IMPL(SBRK_RET_TYPE, sbrk, SBRK_ARG_TYPE)
+#ifdef HAVE_BRK
+ BRK_IMPL(BRK_RET_TYPE, brk, BRK_ARG_TYPE)
+#endif
+
+#ifdef HAVE__SBRK
+ SBRK_IMPL(SBRK_RET_TYPE, _sbrk, SBRK_ARG_TYPE)
+#endif
+#ifdef HAVE__BRK
+ BRK_IMPL(BRK_RET_TYPE, _brk, BRK_ARG_TYPE)
+#endif
+
+#ifdef HAVE___SBRK
+ SBRK_IMPL(SBRK_RET_TYPE, __sbrk, SBRK_ARG_TYPE)
+#endif
+#ifdef HAVE___BRK
+ BRK_IMPL(BRK_RET_TYPE, __brk, BRK_ARG_TYPE)
+#endif
+
+static int
+init(void)
+{
+ if (inited)
+ return 1;
+
+#define INIT_XBRK_SYM(SYM) \
+do { \
+ if (!real_ ## SYM) { \
+ real_ ## SYM = dlsym(RTLD_NEXT, #SYM); \
+ if (!real_ ## SYM) { \
+ errno = ENOMEM; \
+ return 0; \
+ } \
+ } \
+} while (0)
+
+ heap_end = NULL;
+#if defined(HAVE_END_SYMBOL)
+ heap_start = &end;
+#elif defined(HAVE__END_SYMBOL)
+ heap_start = &_end;
+#endif
+
+ INIT_XBRK_SYM(sbrk);
+#ifdef HAVE_BRK
+ INIT_XBRK_SYM(brk);
+#endif
+#ifdef HAVE__SBRK
+ INIT_XBRK_SYM(_sbrk);
+#endif
+#ifdef HAVE__BRK
+ INIT_XBRK_SYM(_brk);
+#endif
+#ifdef HAVE___SBRK
+ INIT_XBRK_SYM(__sbrk);
+#endif
+#ifdef HAVE___BRK
+ INIT_XBRK_SYM(__brk);
+#endif
+
+ return inited = 1;
+#undef INIT_XBRK_SYM
+}
+
+#endif /* #elif defined(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC) */ /* ----------- */
+
+static void
+update_heap_size(char *new_end)
+{
+ volatile char *new_start, *old_start, *old_end;
+ Uint size;
+
+ if (new_end == ((char *) -1))
+ return;
+
+ new_start = (old_start = heap_start);
+ old_end = heap_end;
+ heap_end = new_end;
+ if (new_end < old_start || !old_start)
+ heap_start = (new_start = new_end);
+
+ size = (Uint) (new_end - new_start);
+
+ if (!old_end) {
+ if (size)
+ erts_mtrace_crr_alloc((void *) new_start,
+ ERTS_ALC_A_SYSTEM,
+ ERTS_MTRACE_SEGMENT_ID,
+ size);
+ else
+ heap_end = NULL;
+ }
+ else {
+ if (old_end != new_end || old_start != new_start) {
+
+ if (size)
+ erts_mtrace_crr_realloc((void *) new_start,
+ ERTS_ALC_A_SYSTEM,
+ ERTS_MTRACE_SEGMENT_ID,
+ (void *) old_start,
+ size);
+ else {
+ if (old_start)
+ erts_mtrace_crr_free(ERTS_ALC_A_SYSTEM,
+ ERTS_MTRACE_SEGMENT_ID,
+ (void *) old_start);
+ heap_end = NULL;
+ }
+ }
+ }
+}
+
+#endif /* #ifdef ERTS_CAN_TRACK_MALLOC */
+
+void
+erts_mtrace_update_heap_size(void)
+{
+#ifdef ERTS_CAN_TRACK_MALLOC
+ if (erts_mtrace_enabled && (inited || init()))
+ update_heap_size((char *) SBRK_0);
+#endif
+}
+