Date: Tuesday, July 4, 2017 @ 06:48:19 Author: eworm Revision: 299652
delete upstream patches Deleted: jemalloc/repos/testing-i686/0001-only-abort-on-dlsym-when-necessary.patch jemalloc/repos/testing-i686/0002-clear-tcache_ql-after-fork-in-child.patch jemalloc/repos/testing-i686/0003-Add-minimal-initialized-tsd.patch jemalloc/repos/testing-x86_64/0001-only-abort-on-dlsym-when-necessary.patch jemalloc/repos/testing-x86_64/0002-clear-tcache_ql-after-fork-in-child.patch jemalloc/repos/testing-x86_64/0003-Add-minimal-initialized-tsd.patch jemalloc/trunk/0001-only-abort-on-dlsym-when-necessary.patch jemalloc/trunk/0002-clear-tcache_ql-after-fork-in-child.patch jemalloc/trunk/0003-Add-minimal-initialized-tsd.patch ---------------------------------------------------------------------+ repos/testing-i686/0001-only-abort-on-dlsym-when-necessary.patch | 75 --- repos/testing-i686/0002-clear-tcache_ql-after-fork-in-child.patch | 194 ---------- repos/testing-i686/0003-Add-minimal-initialized-tsd.patch | 37 - repos/testing-x86_64/0001-only-abort-on-dlsym-when-necessary.patch | 75 --- repos/testing-x86_64/0002-clear-tcache_ql-after-fork-in-child.patch | 194 ---------- repos/testing-x86_64/0003-Add-minimal-initialized-tsd.patch | 37 - trunk/0001-only-abort-on-dlsym-when-necessary.patch | 75 --- trunk/0002-clear-tcache_ql-after-fork-in-child.patch | 194 ---------- trunk/0003-Add-minimal-initialized-tsd.patch | 37 - 9 files changed, 918 deletions(-) Deleted: repos/testing-i686/0001-only-abort-on-dlsym-when-necessary.patch =================================================================== --- repos/testing-i686/0001-only-abort-on-dlsym-when-necessary.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ repos/testing-i686/0001-only-abort-on-dlsym-when-necessary.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,75 +0,0 @@ -From a4d6fe73cf07b3be3af6b7811cfc5950320bb37f Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Wed, 14 Jun 2017 12:12:23 -0700 -Subject: [PATCH] Only abort on dlsym when necessary. - -If neither background_thread nor lazy_lock is in use, do not abort on dlsym -errors. ---- - include/jemalloc/internal/background_thread_externs.h | 1 + - src/background_thread.c | 14 +++++++++++--- - src/ctl.c | 7 +++++++ - 3 files changed, 19 insertions(+), 3 deletions(-) - -diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h -index 7c883697..8b4b8471 100644 ---- a/include/jemalloc/internal/background_thread_externs.h -+++ b/include/jemalloc/internal/background_thread_externs.h -@@ -6,6 +6,7 @@ extern malloc_mutex_t background_thread_lock; - extern atomic_b_t background_thread_enabled_state; - extern size_t n_background_threads; - extern background_thread_info_t *background_thread_info; -+extern bool can_enable_background_thread; - - bool background_thread_create(tsd_t *tsd, unsigned arena_ind); - bool background_threads_enable(tsd_t *tsd); -diff --git a/src/background_thread.c b/src/background_thread.c -index a7403b85..1ff59447 100644 ---- a/src/background_thread.c -+++ b/src/background_thread.c -@@ -20,6 +20,9 @@ size_t n_background_threads; - /* Thread info per-index. */ - background_thread_info_t *background_thread_info; - -+/* False if no necessary runtime support. */ -+bool can_enable_background_thread; -+ - /******************************************************************************/ - - #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER -@@ -785,9 +788,14 @@ background_thread_boot0(void) { - #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER - pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); - if (pthread_create_fptr == NULL) { -- malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, " -- "\"pthread_create\")\n"); -- abort(); -+ can_enable_background_thread = false; -+ if (config_lazy_lock || opt_background_thread) { -+ malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, " -+ "\"pthread_create\")\n"); -+ abort(); -+ } -+ } else { -+ can_enable_background_thread = true; - } - #endif - return false; -diff --git a/src/ctl.c b/src/ctl.c -index b3ae4aab..f1310cdf 100644 ---- a/src/ctl.c -+++ b/src/ctl.c -@@ -1522,6 +1522,13 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - - background_thread_enabled_set(tsd_tsdn(tsd), newval); - if (newval) { -+ if (!can_enable_background_thread) { -+ malloc_printf("<jemalloc>: Error in dlsym(" -+ "RTLD_NEXT, \"pthread_create\"). Cannot " -+ "enable background_thread\n"); -+ ret = EFAULT; -+ goto label_return; -+ } - if (background_threads_enable(tsd)) { - ret = EFAULT; - goto label_return; Deleted: repos/testing-i686/0002-clear-tcache_ql-after-fork-in-child.patch =================================================================== --- repos/testing-i686/0002-clear-tcache_ql-after-fork-in-child.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ repos/testing-i686/0002-clear-tcache_ql-after-fork-in-child.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,194 +0,0 @@ -From 9b1befabbb7a7105501d27843873d14e1c2de54b Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Thu, 15 Jun 2017 16:53:22 -0700 -Subject: [PATCH] Add minimal initialized TSD. - -We use the minimal_initilized tsd (which requires no cleanup) for free() -specifically, if tsd hasn't been initialized yet. - -Any other activity will transit the state from minimal to normal. This is to -workaround the case where a thread has no malloc calls in its lifetime until -during thread termination, free() happens after tls destructors. ---- - include/jemalloc/internal/tsd.h | 30 ++++++++++++++++++++-------- - src/jemalloc.c | 10 +++++++++- - src/tsd.c | 44 +++++++++++++++++++++++++++-------------- - 3 files changed, 60 insertions(+), 24 deletions(-) - -diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h -index 631fbf1f..155a2ec6 100644 ---- a/include/jemalloc/internal/tsd.h -+++ b/include/jemalloc/internal/tsd.h -@@ -99,9 +99,10 @@ enum { - tsd_state_nominal_slow = 1, /* Initialized but on slow path. */ - /* the above 2 nominal states should be lower values. */ - tsd_state_nominal_max = 1, /* used for comparison only. */ -- tsd_state_purgatory = 2, -- tsd_state_reincarnated = 3, -- tsd_state_uninitialized = 4 -+ tsd_state_minimal_initialized = 2, -+ tsd_state_purgatory = 3, -+ tsd_state_reincarnated = 4, -+ tsd_state_uninitialized = 5 - }; - - /* Manually limit tsd_state_t to a single byte. */ -@@ -190,7 +191,8 @@ JEMALLOC_ALWAYS_INLINE t * \ - tsd_##n##p_get(tsd_t *tsd) { \ - assert(tsd->state == tsd_state_nominal || \ - tsd->state == tsd_state_nominal_slow || \ -- tsd->state == tsd_state_reincarnated); \ -+ tsd->state == tsd_state_reincarnated || \ -+ tsd->state == tsd_state_minimal_initialized); \ - return tsd_##n##p_get_unsafe(tsd); \ - } - MALLOC_TSD -@@ -225,7 +227,8 @@ MALLOC_TSD - #define O(n, t, nt) \ - JEMALLOC_ALWAYS_INLINE void \ - tsd_##n##_set(tsd_t *tsd, t val) { \ -- assert(tsd->state != tsd_state_reincarnated); \ -+ assert(tsd->state != tsd_state_reincarnated && \ -+ tsd->state != tsd_state_minimal_initialized); \ - *tsd_##n##p_get(tsd) = val; \ - } - MALLOC_TSD -@@ -248,7 +251,7 @@ tsd_fast(tsd_t *tsd) { - } - - JEMALLOC_ALWAYS_INLINE tsd_t * --tsd_fetch_impl(bool init, bool internal) { -+tsd_fetch_impl(bool init, bool minimal) { - tsd_t *tsd = tsd_get(init); - - if (!init && tsd_get_allocates() && tsd == NULL) { -@@ -257,7 +260,7 @@ tsd_fetch_impl(bool init, bool internal) { - assert(tsd != NULL); - - if (unlikely(tsd->state != tsd_state_nominal)) { -- return tsd_fetch_slow(tsd, internal); -+ return tsd_fetch_slow(tsd, minimal); - } - assert(tsd_fast(tsd)); - tsd_assert_fast(tsd); -@@ -265,11 +268,22 @@ tsd_fetch_impl(bool init, bool internal) { - return tsd; - } - -+/* Get a minimal TSD that requires no cleanup. See comments in free(). */ - JEMALLOC_ALWAYS_INLINE tsd_t * --tsd_internal_fetch(void) { -+tsd_fetch_min(void) { - return tsd_fetch_impl(true, true); - } - -+/* For internal background threads use only. */ -+JEMALLOC_ALWAYS_INLINE tsd_t * -+tsd_internal_fetch(void) { -+ tsd_t *tsd = tsd_fetch_min(); -+ /* Use reincarnated state to prevent full initialization. */ -+ tsd->state = tsd_state_reincarnated; -+ -+ return tsd; -+} -+ - JEMALLOC_ALWAYS_INLINE tsd_t * - tsd_fetch(void) { - return tsd_fetch_impl(true, false); -diff --git a/src/jemalloc.c b/src/jemalloc.c -index 52c86aa6..c773cc44 100644 ---- a/src/jemalloc.c -+++ b/src/jemalloc.c -@@ -2264,7 +2264,15 @@ JEMALLOC_EXPORT void JEMALLOC_NOTHROW - je_free(void *ptr) { - UTRACE(ptr, 0, 0); - if (likely(ptr != NULL)) { -- tsd_t *tsd = tsd_fetch(); -+ /* -+ * We avoid setting up tsd fully (e.g. tcache, arena binding) -+ * based on only free() calls -- other activities trigger the -+ * minimal to full transition. This is because free() may -+ * happen during thread shutdown after tls deallocation: if a -+ * thread never had any malloc activities until then, a -+ * fully-setup tsd won't be destructed properly. -+ */ -+ tsd_t *tsd = tsd_fetch_min(); - check_entry_exit_locking(tsd_tsdn(tsd)); - - tcache_t *tcache; -diff --git a/src/tsd.c b/src/tsd.c -index 97330332..f968992f 100644 ---- a/src/tsd.c -+++ b/src/tsd.c -@@ -87,7 +87,8 @@ assert_tsd_data_cleanup_done(tsd_t *tsd) { - - static bool - tsd_data_init_nocleanup(tsd_t *tsd) { -- assert(tsd->state == tsd_state_reincarnated); -+ assert(tsd->state == tsd_state_reincarnated || -+ tsd->state == tsd_state_minimal_initialized); - /* - * During reincarnation, there is no guarantee that the cleanup function - * will be called (deallocation may happen after all tsd destructors). -@@ -103,15 +104,8 @@ tsd_data_init_nocleanup(tsd_t *tsd) { - } - - tsd_t * --tsd_fetch_slow(tsd_t *tsd, bool internal) { -- if (internal) { -- /* For internal background threads use only. */ -- assert(tsd->state == tsd_state_uninitialized); -- tsd->state = tsd_state_reincarnated; -- tsd_set(tsd); -- tsd_data_init_nocleanup(tsd); -- return tsd; -- } -+tsd_fetch_slow(tsd_t *tsd, bool minimal) { -+ assert(!tsd_fast(tsd)); - - if (tsd->state == tsd_state_nominal_slow) { - /* On slow path but no work needed. */ -@@ -119,11 +113,28 @@ tsd_fetch_slow(tsd_t *tsd, bool internal) { - tsd_reentrancy_level_get(tsd) > 0 || - *tsd_arenas_tdata_bypassp_get(tsd)); - } else if (tsd->state == tsd_state_uninitialized) { -- tsd->state = tsd_state_nominal; -- tsd_slow_update(tsd); -- /* Trigger cleanup handler registration. */ -- tsd_set(tsd); -- tsd_data_init(tsd); -+ if (!minimal) { -+ tsd->state = tsd_state_nominal; -+ tsd_slow_update(tsd); -+ /* Trigger cleanup handler registration. */ -+ tsd_set(tsd); -+ tsd_data_init(tsd); -+ } else { -+ tsd->state = tsd_state_minimal_initialized; -+ tsd_set(tsd); -+ tsd_data_init_nocleanup(tsd); -+ } -+ } else if (tsd->state == tsd_state_minimal_initialized) { -+ if (!minimal) { -+ /* Switch to fully initialized. */ -+ tsd->state = tsd_state_nominal; -+ assert(*tsd_reentrancy_levelp_get(tsd) >= 1); -+ (*tsd_reentrancy_levelp_get(tsd))--; -+ tsd_slow_update(tsd); -+ tsd_data_init(tsd); -+ } else { -+ assert_tsd_data_cleanup_done(tsd); -+ } - } else if (tsd->state == tsd_state_purgatory) { - tsd->state = tsd_state_reincarnated; - tsd_set(tsd); -@@ -197,6 +208,9 @@ tsd_cleanup(void *arg) { - case tsd_state_uninitialized: - /* Do nothing. */ - break; -+ case tsd_state_minimal_initialized: -+ /* This implies the thread only did free() in its life time. */ -+ /* Fall through. */ - case tsd_state_reincarnated: - /* - * Reincarnated means another destructor deallocated memory Deleted: repos/testing-i686/0003-Add-minimal-initialized-tsd.patch =================================================================== --- repos/testing-i686/0003-Add-minimal-initialized-tsd.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ repos/testing-i686/0003-Add-minimal-initialized-tsd.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,37 +0,0 @@ -From d35c037e03e1450794dcf595e49a1e1f97f87ac4 Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Mon, 19 Jun 2017 21:19:15 -0700 -Subject: [PATCH] Clear tcache_ql after fork in child. - ---- - src/arena.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/src/arena.c b/src/arena.c -index 019dd877..d401808b 100644 ---- a/src/arena.c -+++ b/src/arena.c -@@ -2133,6 +2133,23 @@ void - arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { - unsigned i; - -+ atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED); -+ atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED); -+ if (tsd_arena_get(tsdn_tsd(tsdn)) == arena) { -+ arena_nthreads_inc(arena, false); -+ } -+ if (tsd_iarena_get(tsdn_tsd(tsdn)) == arena) { -+ arena_nthreads_inc(arena, true); -+ } -+ if (config_stats) { -+ ql_new(&arena->tcache_ql); -+ tcache_t *tcache = tcache_get(tsdn_tsd(tsdn)); -+ if (tcache != NULL && tcache->arena == arena) { -+ ql_elm_new(tcache, link); -+ ql_tail_insert(&arena->tcache_ql, tcache, link); -+ } -+ } -+ - for (i = 0; i < NBINS; i++) { - malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); - } Deleted: repos/testing-x86_64/0001-only-abort-on-dlsym-when-necessary.patch =================================================================== --- repos/testing-x86_64/0001-only-abort-on-dlsym-when-necessary.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ repos/testing-x86_64/0001-only-abort-on-dlsym-when-necessary.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,75 +0,0 @@ -From a4d6fe73cf07b3be3af6b7811cfc5950320bb37f Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Wed, 14 Jun 2017 12:12:23 -0700 -Subject: [PATCH] Only abort on dlsym when necessary. - -If neither background_thread nor lazy_lock is in use, do not abort on dlsym -errors. ---- - include/jemalloc/internal/background_thread_externs.h | 1 + - src/background_thread.c | 14 +++++++++++--- - src/ctl.c | 7 +++++++ - 3 files changed, 19 insertions(+), 3 deletions(-) - -diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h -index 7c883697..8b4b8471 100644 ---- a/include/jemalloc/internal/background_thread_externs.h -+++ b/include/jemalloc/internal/background_thread_externs.h -@@ -6,6 +6,7 @@ extern malloc_mutex_t background_thread_lock; - extern atomic_b_t background_thread_enabled_state; - extern size_t n_background_threads; - extern background_thread_info_t *background_thread_info; -+extern bool can_enable_background_thread; - - bool background_thread_create(tsd_t *tsd, unsigned arena_ind); - bool background_threads_enable(tsd_t *tsd); -diff --git a/src/background_thread.c b/src/background_thread.c -index a7403b85..1ff59447 100644 ---- a/src/background_thread.c -+++ b/src/background_thread.c -@@ -20,6 +20,9 @@ size_t n_background_threads; - /* Thread info per-index. */ - background_thread_info_t *background_thread_info; - -+/* False if no necessary runtime support. */ -+bool can_enable_background_thread; -+ - /******************************************************************************/ - - #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER -@@ -785,9 +788,14 @@ background_thread_boot0(void) { - #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER - pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); - if (pthread_create_fptr == NULL) { -- malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, " -- "\"pthread_create\")\n"); -- abort(); -+ can_enable_background_thread = false; -+ if (config_lazy_lock || opt_background_thread) { -+ malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, " -+ "\"pthread_create\")\n"); -+ abort(); -+ } -+ } else { -+ can_enable_background_thread = true; - } - #endif - return false; -diff --git a/src/ctl.c b/src/ctl.c -index b3ae4aab..f1310cdf 100644 ---- a/src/ctl.c -+++ b/src/ctl.c -@@ -1522,6 +1522,13 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - - background_thread_enabled_set(tsd_tsdn(tsd), newval); - if (newval) { -+ if (!can_enable_background_thread) { -+ malloc_printf("<jemalloc>: Error in dlsym(" -+ "RTLD_NEXT, \"pthread_create\"). Cannot " -+ "enable background_thread\n"); -+ ret = EFAULT; -+ goto label_return; -+ } - if (background_threads_enable(tsd)) { - ret = EFAULT; - goto label_return; Deleted: repos/testing-x86_64/0002-clear-tcache_ql-after-fork-in-child.patch =================================================================== --- repos/testing-x86_64/0002-clear-tcache_ql-after-fork-in-child.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ repos/testing-x86_64/0002-clear-tcache_ql-after-fork-in-child.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,194 +0,0 @@ -From 9b1befabbb7a7105501d27843873d14e1c2de54b Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Thu, 15 Jun 2017 16:53:22 -0700 -Subject: [PATCH] Add minimal initialized TSD. - -We use the minimal_initilized tsd (which requires no cleanup) for free() -specifically, if tsd hasn't been initialized yet. - -Any other activity will transit the state from minimal to normal. This is to -workaround the case where a thread has no malloc calls in its lifetime until -during thread termination, free() happens after tls destructors. ---- - include/jemalloc/internal/tsd.h | 30 ++++++++++++++++++++-------- - src/jemalloc.c | 10 +++++++++- - src/tsd.c | 44 +++++++++++++++++++++++++++-------------- - 3 files changed, 60 insertions(+), 24 deletions(-) - -diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h -index 631fbf1f..155a2ec6 100644 ---- a/include/jemalloc/internal/tsd.h -+++ b/include/jemalloc/internal/tsd.h -@@ -99,9 +99,10 @@ enum { - tsd_state_nominal_slow = 1, /* Initialized but on slow path. */ - /* the above 2 nominal states should be lower values. */ - tsd_state_nominal_max = 1, /* used for comparison only. */ -- tsd_state_purgatory = 2, -- tsd_state_reincarnated = 3, -- tsd_state_uninitialized = 4 -+ tsd_state_minimal_initialized = 2, -+ tsd_state_purgatory = 3, -+ tsd_state_reincarnated = 4, -+ tsd_state_uninitialized = 5 - }; - - /* Manually limit tsd_state_t to a single byte. */ -@@ -190,7 +191,8 @@ JEMALLOC_ALWAYS_INLINE t * \ - tsd_##n##p_get(tsd_t *tsd) { \ - assert(tsd->state == tsd_state_nominal || \ - tsd->state == tsd_state_nominal_slow || \ -- tsd->state == tsd_state_reincarnated); \ -+ tsd->state == tsd_state_reincarnated || \ -+ tsd->state == tsd_state_minimal_initialized); \ - return tsd_##n##p_get_unsafe(tsd); \ - } - MALLOC_TSD -@@ -225,7 +227,8 @@ MALLOC_TSD - #define O(n, t, nt) \ - JEMALLOC_ALWAYS_INLINE void \ - tsd_##n##_set(tsd_t *tsd, t val) { \ -- assert(tsd->state != tsd_state_reincarnated); \ -+ assert(tsd->state != tsd_state_reincarnated && \ -+ tsd->state != tsd_state_minimal_initialized); \ - *tsd_##n##p_get(tsd) = val; \ - } - MALLOC_TSD -@@ -248,7 +251,7 @@ tsd_fast(tsd_t *tsd) { - } - - JEMALLOC_ALWAYS_INLINE tsd_t * --tsd_fetch_impl(bool init, bool internal) { -+tsd_fetch_impl(bool init, bool minimal) { - tsd_t *tsd = tsd_get(init); - - if (!init && tsd_get_allocates() && tsd == NULL) { -@@ -257,7 +260,7 @@ tsd_fetch_impl(bool init, bool internal) { - assert(tsd != NULL); - - if (unlikely(tsd->state != tsd_state_nominal)) { -- return tsd_fetch_slow(tsd, internal); -+ return tsd_fetch_slow(tsd, minimal); - } - assert(tsd_fast(tsd)); - tsd_assert_fast(tsd); -@@ -265,11 +268,22 @@ tsd_fetch_impl(bool init, bool internal) { - return tsd; - } - -+/* Get a minimal TSD that requires no cleanup. See comments in free(). */ - JEMALLOC_ALWAYS_INLINE tsd_t * --tsd_internal_fetch(void) { -+tsd_fetch_min(void) { - return tsd_fetch_impl(true, true); - } - -+/* For internal background threads use only. */ -+JEMALLOC_ALWAYS_INLINE tsd_t * -+tsd_internal_fetch(void) { -+ tsd_t *tsd = tsd_fetch_min(); -+ /* Use reincarnated state to prevent full initialization. */ -+ tsd->state = tsd_state_reincarnated; -+ -+ return tsd; -+} -+ - JEMALLOC_ALWAYS_INLINE tsd_t * - tsd_fetch(void) { - return tsd_fetch_impl(true, false); -diff --git a/src/jemalloc.c b/src/jemalloc.c -index 52c86aa6..c773cc44 100644 ---- a/src/jemalloc.c -+++ b/src/jemalloc.c -@@ -2264,7 +2264,15 @@ JEMALLOC_EXPORT void JEMALLOC_NOTHROW - je_free(void *ptr) { - UTRACE(ptr, 0, 0); - if (likely(ptr != NULL)) { -- tsd_t *tsd = tsd_fetch(); -+ /* -+ * We avoid setting up tsd fully (e.g. tcache, arena binding) -+ * based on only free() calls -- other activities trigger the -+ * minimal to full transition. This is because free() may -+ * happen during thread shutdown after tls deallocation: if a -+ * thread never had any malloc activities until then, a -+ * fully-setup tsd won't be destructed properly. -+ */ -+ tsd_t *tsd = tsd_fetch_min(); - check_entry_exit_locking(tsd_tsdn(tsd)); - - tcache_t *tcache; -diff --git a/src/tsd.c b/src/tsd.c -index 97330332..f968992f 100644 ---- a/src/tsd.c -+++ b/src/tsd.c -@@ -87,7 +87,8 @@ assert_tsd_data_cleanup_done(tsd_t *tsd) { - - static bool - tsd_data_init_nocleanup(tsd_t *tsd) { -- assert(tsd->state == tsd_state_reincarnated); -+ assert(tsd->state == tsd_state_reincarnated || -+ tsd->state == tsd_state_minimal_initialized); - /* - * During reincarnation, there is no guarantee that the cleanup function - * will be called (deallocation may happen after all tsd destructors). -@@ -103,15 +104,8 @@ tsd_data_init_nocleanup(tsd_t *tsd) { - } - - tsd_t * --tsd_fetch_slow(tsd_t *tsd, bool internal) { -- if (internal) { -- /* For internal background threads use only. */ -- assert(tsd->state == tsd_state_uninitialized); -- tsd->state = tsd_state_reincarnated; -- tsd_set(tsd); -- tsd_data_init_nocleanup(tsd); -- return tsd; -- } -+tsd_fetch_slow(tsd_t *tsd, bool minimal) { -+ assert(!tsd_fast(tsd)); - - if (tsd->state == tsd_state_nominal_slow) { - /* On slow path but no work needed. */ -@@ -119,11 +113,28 @@ tsd_fetch_slow(tsd_t *tsd, bool internal) { - tsd_reentrancy_level_get(tsd) > 0 || - *tsd_arenas_tdata_bypassp_get(tsd)); - } else if (tsd->state == tsd_state_uninitialized) { -- tsd->state = tsd_state_nominal; -- tsd_slow_update(tsd); -- /* Trigger cleanup handler registration. */ -- tsd_set(tsd); -- tsd_data_init(tsd); -+ if (!minimal) { -+ tsd->state = tsd_state_nominal; -+ tsd_slow_update(tsd); -+ /* Trigger cleanup handler registration. */ -+ tsd_set(tsd); -+ tsd_data_init(tsd); -+ } else { -+ tsd->state = tsd_state_minimal_initialized; -+ tsd_set(tsd); -+ tsd_data_init_nocleanup(tsd); -+ } -+ } else if (tsd->state == tsd_state_minimal_initialized) { -+ if (!minimal) { -+ /* Switch to fully initialized. */ -+ tsd->state = tsd_state_nominal; -+ assert(*tsd_reentrancy_levelp_get(tsd) >= 1); -+ (*tsd_reentrancy_levelp_get(tsd))--; -+ tsd_slow_update(tsd); -+ tsd_data_init(tsd); -+ } else { -+ assert_tsd_data_cleanup_done(tsd); -+ } - } else if (tsd->state == tsd_state_purgatory) { - tsd->state = tsd_state_reincarnated; - tsd_set(tsd); -@@ -197,6 +208,9 @@ tsd_cleanup(void *arg) { - case tsd_state_uninitialized: - /* Do nothing. */ - break; -+ case tsd_state_minimal_initialized: -+ /* This implies the thread only did free() in its life time. */ -+ /* Fall through. */ - case tsd_state_reincarnated: - /* - * Reincarnated means another destructor deallocated memory Deleted: repos/testing-x86_64/0003-Add-minimal-initialized-tsd.patch =================================================================== --- repos/testing-x86_64/0003-Add-minimal-initialized-tsd.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ repos/testing-x86_64/0003-Add-minimal-initialized-tsd.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,37 +0,0 @@ -From d35c037e03e1450794dcf595e49a1e1f97f87ac4 Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Mon, 19 Jun 2017 21:19:15 -0700 -Subject: [PATCH] Clear tcache_ql after fork in child. - ---- - src/arena.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/src/arena.c b/src/arena.c -index 019dd877..d401808b 100644 ---- a/src/arena.c -+++ b/src/arena.c -@@ -2133,6 +2133,23 @@ void - arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { - unsigned i; - -+ atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED); -+ atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED); -+ if (tsd_arena_get(tsdn_tsd(tsdn)) == arena) { -+ arena_nthreads_inc(arena, false); -+ } -+ if (tsd_iarena_get(tsdn_tsd(tsdn)) == arena) { -+ arena_nthreads_inc(arena, true); -+ } -+ if (config_stats) { -+ ql_new(&arena->tcache_ql); -+ tcache_t *tcache = tcache_get(tsdn_tsd(tsdn)); -+ if (tcache != NULL && tcache->arena == arena) { -+ ql_elm_new(tcache, link); -+ ql_tail_insert(&arena->tcache_ql, tcache, link); -+ } -+ } -+ - for (i = 0; i < NBINS; i++) { - malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); - } Deleted: trunk/0001-only-abort-on-dlsym-when-necessary.patch =================================================================== --- trunk/0001-only-abort-on-dlsym-when-necessary.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ trunk/0001-only-abort-on-dlsym-when-necessary.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,75 +0,0 @@ -From a4d6fe73cf07b3be3af6b7811cfc5950320bb37f Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Wed, 14 Jun 2017 12:12:23 -0700 -Subject: [PATCH] Only abort on dlsym when necessary. - -If neither background_thread nor lazy_lock is in use, do not abort on dlsym -errors. ---- - include/jemalloc/internal/background_thread_externs.h | 1 + - src/background_thread.c | 14 +++++++++++--- - src/ctl.c | 7 +++++++ - 3 files changed, 19 insertions(+), 3 deletions(-) - -diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h -index 7c883697..8b4b8471 100644 ---- a/include/jemalloc/internal/background_thread_externs.h -+++ b/include/jemalloc/internal/background_thread_externs.h -@@ -6,6 +6,7 @@ extern malloc_mutex_t background_thread_lock; - extern atomic_b_t background_thread_enabled_state; - extern size_t n_background_threads; - extern background_thread_info_t *background_thread_info; -+extern bool can_enable_background_thread; - - bool background_thread_create(tsd_t *tsd, unsigned arena_ind); - bool background_threads_enable(tsd_t *tsd); -diff --git a/src/background_thread.c b/src/background_thread.c -index a7403b85..1ff59447 100644 ---- a/src/background_thread.c -+++ b/src/background_thread.c -@@ -20,6 +20,9 @@ size_t n_background_threads; - /* Thread info per-index. */ - background_thread_info_t *background_thread_info; - -+/* False if no necessary runtime support. */ -+bool can_enable_background_thread; -+ - /******************************************************************************/ - - #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER -@@ -785,9 +788,14 @@ background_thread_boot0(void) { - #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER - pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); - if (pthread_create_fptr == NULL) { -- malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, " -- "\"pthread_create\")\n"); -- abort(); -+ can_enable_background_thread = false; -+ if (config_lazy_lock || opt_background_thread) { -+ malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, " -+ "\"pthread_create\")\n"); -+ abort(); -+ } -+ } else { -+ can_enable_background_thread = true; - } - #endif - return false; -diff --git a/src/ctl.c b/src/ctl.c -index b3ae4aab..f1310cdf 100644 ---- a/src/ctl.c -+++ b/src/ctl.c -@@ -1522,6 +1522,13 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - - background_thread_enabled_set(tsd_tsdn(tsd), newval); - if (newval) { -+ if (!can_enable_background_thread) { -+ malloc_printf("<jemalloc>: Error in dlsym(" -+ "RTLD_NEXT, \"pthread_create\"). Cannot " -+ "enable background_thread\n"); -+ ret = EFAULT; -+ goto label_return; -+ } - if (background_threads_enable(tsd)) { - ret = EFAULT; - goto label_return; Deleted: trunk/0002-clear-tcache_ql-after-fork-in-child.patch =================================================================== --- trunk/0002-clear-tcache_ql-after-fork-in-child.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ trunk/0002-clear-tcache_ql-after-fork-in-child.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,194 +0,0 @@ -From 9b1befabbb7a7105501d27843873d14e1c2de54b Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Thu, 15 Jun 2017 16:53:22 -0700 -Subject: [PATCH] Add minimal initialized TSD. - -We use the minimal_initilized tsd (which requires no cleanup) for free() -specifically, if tsd hasn't been initialized yet. - -Any other activity will transit the state from minimal to normal. This is to -workaround the case where a thread has no malloc calls in its lifetime until -during thread termination, free() happens after tls destructors. ---- - include/jemalloc/internal/tsd.h | 30 ++++++++++++++++++++-------- - src/jemalloc.c | 10 +++++++++- - src/tsd.c | 44 +++++++++++++++++++++++++++-------------- - 3 files changed, 60 insertions(+), 24 deletions(-) - -diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h -index 631fbf1f..155a2ec6 100644 ---- a/include/jemalloc/internal/tsd.h -+++ b/include/jemalloc/internal/tsd.h -@@ -99,9 +99,10 @@ enum { - tsd_state_nominal_slow = 1, /* Initialized but on slow path. */ - /* the above 2 nominal states should be lower values. */ - tsd_state_nominal_max = 1, /* used for comparison only. */ -- tsd_state_purgatory = 2, -- tsd_state_reincarnated = 3, -- tsd_state_uninitialized = 4 -+ tsd_state_minimal_initialized = 2, -+ tsd_state_purgatory = 3, -+ tsd_state_reincarnated = 4, -+ tsd_state_uninitialized = 5 - }; - - /* Manually limit tsd_state_t to a single byte. */ -@@ -190,7 +191,8 @@ JEMALLOC_ALWAYS_INLINE t * \ - tsd_##n##p_get(tsd_t *tsd) { \ - assert(tsd->state == tsd_state_nominal || \ - tsd->state == tsd_state_nominal_slow || \ -- tsd->state == tsd_state_reincarnated); \ -+ tsd->state == tsd_state_reincarnated || \ -+ tsd->state == tsd_state_minimal_initialized); \ - return tsd_##n##p_get_unsafe(tsd); \ - } - MALLOC_TSD -@@ -225,7 +227,8 @@ MALLOC_TSD - #define O(n, t, nt) \ - JEMALLOC_ALWAYS_INLINE void \ - tsd_##n##_set(tsd_t *tsd, t val) { \ -- assert(tsd->state != tsd_state_reincarnated); \ -+ assert(tsd->state != tsd_state_reincarnated && \ -+ tsd->state != tsd_state_minimal_initialized); \ - *tsd_##n##p_get(tsd) = val; \ - } - MALLOC_TSD -@@ -248,7 +251,7 @@ tsd_fast(tsd_t *tsd) { - } - - JEMALLOC_ALWAYS_INLINE tsd_t * --tsd_fetch_impl(bool init, bool internal) { -+tsd_fetch_impl(bool init, bool minimal) { - tsd_t *tsd = tsd_get(init); - - if (!init && tsd_get_allocates() && tsd == NULL) { -@@ -257,7 +260,7 @@ tsd_fetch_impl(bool init, bool internal) { - assert(tsd != NULL); - - if (unlikely(tsd->state != tsd_state_nominal)) { -- return tsd_fetch_slow(tsd, internal); -+ return tsd_fetch_slow(tsd, minimal); - } - assert(tsd_fast(tsd)); - tsd_assert_fast(tsd); -@@ -265,11 +268,22 @@ tsd_fetch_impl(bool init, bool internal) { - return tsd; - } - -+/* Get a minimal TSD that requires no cleanup. See comments in free(). */ - JEMALLOC_ALWAYS_INLINE tsd_t * --tsd_internal_fetch(void) { -+tsd_fetch_min(void) { - return tsd_fetch_impl(true, true); - } - -+/* For internal background threads use only. */ -+JEMALLOC_ALWAYS_INLINE tsd_t * -+tsd_internal_fetch(void) { -+ tsd_t *tsd = tsd_fetch_min(); -+ /* Use reincarnated state to prevent full initialization. */ -+ tsd->state = tsd_state_reincarnated; -+ -+ return tsd; -+} -+ - JEMALLOC_ALWAYS_INLINE tsd_t * - tsd_fetch(void) { - return tsd_fetch_impl(true, false); -diff --git a/src/jemalloc.c b/src/jemalloc.c -index 52c86aa6..c773cc44 100644 ---- a/src/jemalloc.c -+++ b/src/jemalloc.c -@@ -2264,7 +2264,15 @@ JEMALLOC_EXPORT void JEMALLOC_NOTHROW - je_free(void *ptr) { - UTRACE(ptr, 0, 0); - if (likely(ptr != NULL)) { -- tsd_t *tsd = tsd_fetch(); -+ /* -+ * We avoid setting up tsd fully (e.g. tcache, arena binding) -+ * based on only free() calls -- other activities trigger the -+ * minimal to full transition. This is because free() may -+ * happen during thread shutdown after tls deallocation: if a -+ * thread never had any malloc activities until then, a -+ * fully-setup tsd won't be destructed properly. -+ */ -+ tsd_t *tsd = tsd_fetch_min(); - check_entry_exit_locking(tsd_tsdn(tsd)); - - tcache_t *tcache; -diff --git a/src/tsd.c b/src/tsd.c -index 97330332..f968992f 100644 ---- a/src/tsd.c -+++ b/src/tsd.c -@@ -87,7 +87,8 @@ assert_tsd_data_cleanup_done(tsd_t *tsd) { - - static bool - tsd_data_init_nocleanup(tsd_t *tsd) { -- assert(tsd->state == tsd_state_reincarnated); -+ assert(tsd->state == tsd_state_reincarnated || -+ tsd->state == tsd_state_minimal_initialized); - /* - * During reincarnation, there is no guarantee that the cleanup function - * will be called (deallocation may happen after all tsd destructors). -@@ -103,15 +104,8 @@ tsd_data_init_nocleanup(tsd_t *tsd) { - } - - tsd_t * --tsd_fetch_slow(tsd_t *tsd, bool internal) { -- if (internal) { -- /* For internal background threads use only. */ -- assert(tsd->state == tsd_state_uninitialized); -- tsd->state = tsd_state_reincarnated; -- tsd_set(tsd); -- tsd_data_init_nocleanup(tsd); -- return tsd; -- } -+tsd_fetch_slow(tsd_t *tsd, bool minimal) { -+ assert(!tsd_fast(tsd)); - - if (tsd->state == tsd_state_nominal_slow) { - /* On slow path but no work needed. */ -@@ -119,11 +113,28 @@ tsd_fetch_slow(tsd_t *tsd, bool internal) { - tsd_reentrancy_level_get(tsd) > 0 || - *tsd_arenas_tdata_bypassp_get(tsd)); - } else if (tsd->state == tsd_state_uninitialized) { -- tsd->state = tsd_state_nominal; -- tsd_slow_update(tsd); -- /* Trigger cleanup handler registration. */ -- tsd_set(tsd); -- tsd_data_init(tsd); -+ if (!minimal) { -+ tsd->state = tsd_state_nominal; -+ tsd_slow_update(tsd); -+ /* Trigger cleanup handler registration. */ -+ tsd_set(tsd); -+ tsd_data_init(tsd); -+ } else { -+ tsd->state = tsd_state_minimal_initialized; -+ tsd_set(tsd); -+ tsd_data_init_nocleanup(tsd); -+ } -+ } else if (tsd->state == tsd_state_minimal_initialized) { -+ if (!minimal) { -+ /* Switch to fully initialized. */ -+ tsd->state = tsd_state_nominal; -+ assert(*tsd_reentrancy_levelp_get(tsd) >= 1); -+ (*tsd_reentrancy_levelp_get(tsd))--; -+ tsd_slow_update(tsd); -+ tsd_data_init(tsd); -+ } else { -+ assert_tsd_data_cleanup_done(tsd); -+ } - } else if (tsd->state == tsd_state_purgatory) { - tsd->state = tsd_state_reincarnated; - tsd_set(tsd); -@@ -197,6 +208,9 @@ tsd_cleanup(void *arg) { - case tsd_state_uninitialized: - /* Do nothing. */ - break; -+ case tsd_state_minimal_initialized: -+ /* This implies the thread only did free() in its life time. */ -+ /* Fall through. */ - case tsd_state_reincarnated: - /* - * Reincarnated means another destructor deallocated memory Deleted: trunk/0003-Add-minimal-initialized-tsd.patch =================================================================== --- trunk/0003-Add-minimal-initialized-tsd.patch 2017-07-04 06:45:23 UTC (rev 299651) +++ trunk/0003-Add-minimal-initialized-tsd.patch 2017-07-04 06:48:19 UTC (rev 299652) @@ -1,37 +0,0 @@ -From d35c037e03e1450794dcf595e49a1e1f97f87ac4 Mon Sep 17 00:00:00 2001 -From: Qi Wang <[email protected]> -Date: Mon, 19 Jun 2017 21:19:15 -0700 -Subject: [PATCH] Clear tcache_ql after fork in child. - ---- - src/arena.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/src/arena.c b/src/arena.c -index 019dd877..d401808b 100644 ---- a/src/arena.c -+++ b/src/arena.c -@@ -2133,6 +2133,23 @@ void - arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { - unsigned i; - -+ atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED); -+ atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED); -+ if (tsd_arena_get(tsdn_tsd(tsdn)) == arena) { -+ arena_nthreads_inc(arena, false); -+ } -+ if (tsd_iarena_get(tsdn_tsd(tsdn)) == arena) { -+ arena_nthreads_inc(arena, true); -+ } -+ if (config_stats) { -+ ql_new(&arena->tcache_ql); -+ tcache_t *tcache = tcache_get(tsdn_tsd(tsdn)); -+ if (tcache != NULL && tcache->arena == arena) { -+ ql_elm_new(tcache, link); -+ ql_tail_insert(&arena->tcache_ql, tcache, link); -+ } -+ } -+ - for (i = 0; i < NBINS; i++) { - malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); - }
