aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_mtrace.c
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2013-04-15 14:07:42 +0200
committerSverker Eriksson <[email protected]>2013-04-15 14:07:42 +0200
commit4caf3f8b94a38e738314f484d18b531dfa16ff8a (patch)
tree76a9ad62cec2628baef0288eb808b64196ac9688 /erts/emulator/beam/erl_mtrace.c
parent0e9c7394b12d627b08a5f1acd1ba1c21dbfd6e2a (diff)
downloadotp-4caf3f8b94a38e738314f484d18b531dfa16ff8a.tar.gz
otp-4caf3f8b94a38e738314f484d18b531dfa16ff8a.tar.bz2
otp-4caf3f8b94a38e738314f484d18b531dfa16ff8a.zip
erts: Fix locking order violation for allocation wrappers
Some query functions in erl_alloc_util.c lock the allocator mutex and then use erts_printf that in turn may call the sys allocator through the wrappers. To avoid breaking locking order these query functions first "pre-locks" all allocator wrappers.
Diffstat (limited to 'erts/emulator/beam/erl_mtrace.c')
-rw-r--r--erts/emulator/beam/erl_mtrace.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/erts/emulator/beam/erl_mtrace.c b/erts/emulator/beam/erl_mtrace.c
index e538ba30c2..c8bb126687 100644
--- a/erts/emulator/beam/erl_mtrace.c
+++ b/erts/emulator/beam/erl_mtrace.c
@@ -222,6 +222,8 @@ static byte *tracep;
static byte *endp;
static SysTimeval last_tv;
+static ErtsAllocatorWrapper_t mtrace_wrapper;
+
#if ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0
#error ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0
#endif
@@ -555,6 +557,8 @@ write_trace_header(char *nodename, char *pid, char *hostname)
return 1;
}
+static void mtrace_pre_lock(void);
+static void mtrace_pre_unlock(void);
static void *mtrace_alloc(ErtsAlcType_t, void *, Uint);
static void *mtrace_realloc(ErtsAlcType_t, void *, void *, Uint);
static void mtrace_free(ErtsAlcType_t, void *, void *);
@@ -635,12 +639,16 @@ erts_mtrace_install_wrapper_functions(void)
erts_allctrs[i].free = mtrace_free;
erts_allctrs[i].extra = (void *) &real_allctrs[i];
}
+ mtrace_wrapper.lock = mtrace_pre_lock;
+ mtrace_wrapper.unlock = mtrace_pre_unlock;
+ erts_allctr_wrapper_prelock_init(&mtrace_wrapper);
}
}
void
erts_mtrace_stop(void)
{
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&mtrace_op_mutex);
erts_mtx_lock(&mtrace_buf_mutex);
if (erts_mtrace_enabled) {
@@ -677,6 +685,7 @@ erts_mtrace_stop(void)
void
erts_mtrace_exit(Uint32 exit_value)
{
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&mtrace_op_mutex);
erts_mtx_lock(&mtrace_buf_mutex);
if (erts_mtrace_enabled) {
@@ -935,18 +944,33 @@ write_free_entry(byte tag,
erts_mtx_unlock(&mtrace_buf_mutex);
}
+static void mtrace_pre_lock(void)
+{
+ erts_mtx_lock(&mtrace_op_mutex);
+}
+
+static void mtrace_pre_unlock(void)
+{
+ erts_mtx_unlock(&mtrace_op_mutex);
+}
+
+
static void *
mtrace_alloc(ErtsAlcType_t n, void *extra, Uint size)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *res;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
res = (*real_af->alloc)(n, real_af->extra, size);
write_alloc_entry(ERTS_MT_ALLOC_BDY_TAG, res, n, 0, size);
- erts_mtx_unlock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&mtrace_op_mutex);
+ }
return res;
}
@@ -957,12 +981,16 @@ mtrace_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *res;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
res = (*real_af->realloc)(n, real_af->extra, ptr, size);
write_realloc_entry(ERTS_MT_REALLOC_BDY_TAG, res, n, 0, ptr, size);
- erts_mtx_unlock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&mtrace_op_mutex);
+ }
return res;
@@ -973,10 +1001,14 @@ mtrace_free(ErtsAlcType_t n, void *extra, void *ptr)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
(*real_af->free)(n, real_af->extra, ptr);
- write_free_entry(ERTS_MT_FREE_BDY_TAG, n, 0, ptr);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ write_free_entry(ERTS_MT_FREE_BDY_TAG, n, 0, ptr);
+ }
erts_mtx_unlock(&mtrace_op_mutex);
}