~ chicken-core (chicken-5) 41ca5155a45984e8181bf8353bd2af52227e5857
commit 41ca5155a45984e8181bf8353bd2af52227e5857
Author: Peter Bex <peter@more-magic.net>
AuthorDate: Sat Sep 16 21:03:33 2017 +0200
Commit: Evan Hanson <evhan@foldling.org>
CommitDate: Sun Sep 17 13:02:59 2017 +1200
Pre-allocate profile bucket to avoid malloc() in signal handler
This can cause deadlock because malloc() is not reentrant, see #1414.
Signed-off-by: Evan Hanson <evhan@foldling.org>
diff --git a/NEWS b/NEWS
index 46420a00..31eda452 100644
--- a/NEWS
+++ b/NEWS
@@ -124,6 +124,10 @@
- Large literals no longer crash with "invalid encoded numeric literal"
on mingw-64 (#1344, thanks to Lemonboy).
+- Runtime system:
+ - The profiler no longer uses malloc from a signal handler which may
+ cause deadlocks (#1414, thanks to Lemonboy).
+
- Syntax expander
- Renaming an identifier twice no longer results in an undo of the
rename (fixes #1362, thanks to "megane").
diff --git a/runtime.c b/runtime.c
index ae032f3a..42504d17 100644
--- a/runtime.c
+++ b/runtime.c
@@ -473,7 +473,9 @@ static C_TLS FINALIZER_NODE
static C_TLS void *current_module_handle;
static C_TLS int flonum_print_precision = FLONUM_PRINT_PRECISION;
static C_TLS HDUMP_BUCKET **hdump_table;
-static C_TLS PROFILE_BUCKET **profile_table = NULL;
+static C_TLS PROFILE_BUCKET
+ *next_profile_bucket = NULL,
+ **profile_table = NULL;
static C_TLS int
pending_interrupts[ MAX_PENDING_INTERRUPTS ],
pending_interrupts_count,
@@ -4391,10 +4393,10 @@ static void take_profile_sample()
}
/* Not found, allocate a new item and use it as bucket's new head */
- b = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
+ b = next_profile_bucket;
+ next_profile_bucket = NULL;
- if(b == NULL)
- panic(C_text("out of memory - cannot allocate profile table-bucket"));
+ assert(b != NULL);
b->next = *bp;
b->key = key;
@@ -4415,6 +4417,17 @@ C_regparm void C_fcall C_trace(C_char *name)
C_fputc('\n', C_stderr);
}
+ /*
+ * When profiling, pre-allocate profile bucket if necessary. This
+ * is used in the signal handler, because it may not malloc.
+ */
+ if(profiling && next_profile_bucket == NULL) {
+ next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
+ if (next_profile_bucket == NULL) {
+ panic(C_text("out of memory - cannot allocate profile table-bucket"));
+ }
+ }
+
if(trace_buffer_top >= trace_buffer_limit) {
trace_buffer_top = trace_buffer;
trace_buffer_full = 1;
@@ -4430,6 +4443,14 @@ C_regparm void C_fcall C_trace(C_char *name)
C_regparm C_word C_fcall C_emit_trace_info2(char *raw, C_word x, C_word y, C_word t)
{
+ /* See above */
+ if(profiling && next_profile_bucket == NULL) {
+ next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET));
+ if (next_profile_bucket == NULL) {
+ panic(C_text("out of memory - cannot allocate profile table-bucket"));
+ }
+ }
+
if(trace_buffer_top >= trace_buffer_limit) {
trace_buffer_top = trace_buffer;
trace_buffer_full = 1;
Trap