@@ -509,24 +509,32 @@ static void mi_subproc_unsafe_destroy(mi_subproc_t* subproc)
509509 mi_heap_t * heap = subproc -> heaps ;
510510 while (heap != NULL ) {
511511 mi_heap_t * next = heap -> next ;
512- if (heap != subproc -> heap_main ) {mi_heap_destroy (heap ); }
512+ if (heap != subproc -> heap_main ) { mi_heap_destroy (heap ); }
513513 heap = next ;
514514 }
515515 mi_assert_internal (subproc -> heaps == subproc -> heap_main );
516- mi_heap_destroy (subproc -> heap_main );
516+ _mi_heap_force_destroy (subproc -> heap_main ); // no warning if destroying the main heap
517517 }
518518
519+ // remove associated arenas
520+ _mi_arenas_unsafe_destroy_all (subproc );
521+
519522 // merge stats back into the main subproc?
520523 if (subproc != & subproc_main ) {
521- _mi_arenas_unsafe_destroy_all (subproc );
522524 _mi_stats_merge_into (& subproc_main .stats , & subproc -> stats );
525+ }
523526
524- // safe to release
525- // todo: should we refcount subprocesses?
526- mi_lock_done (& subproc -> arena_reserve_lock );
527- mi_lock_done (& subproc -> heaps_lock );
527+ // safe to release
528+ // todo: should we refcount subprocesses?
529+ mi_lock_done (& subproc -> arena_reserve_lock );
530+ mi_lock_done (& subproc -> heaps_lock );
531+ if (subproc != & subproc_main ) {
528532 _mi_meta_free (subproc , sizeof (mi_subproc_t ), subproc -> memid );
529533 }
534+ else {
535+ // for the main subproc, also release the global page map
536+ _mi_page_map_unsafe_destroy (& subproc_main );
537+ }
530538}
531539
532540void mi_subproc_destroy (mi_subproc_id_t subproc_id ) {
@@ -761,8 +769,8 @@ mi_decl_cold mi_decl_noinline mi_theap_t* _mi_theap_empty_get(void) {
761769#else
762770// with only direct entries, use the "arbitrary user data" field
763771// and assume it is NULL (see also <http://www.nynaeve.net/?p=98>)
764- #define MI_TLS_INITIAL_EXPANSION_SLOT (0)
765772#define MI_TLS_INITIAL_SLOT (5)
773+ #define MI_TLS_INITIAL_EXPANSION_SLOT (0)
766774#endif
767775
768776// we initially use the last of the expansion slots as the default NULL.
@@ -772,38 +780,63 @@ mi_decl_hidden size_t _mi_theap_default_expansion_slot = MI_TLS_INITIAL_EXPANSIO
772780mi_decl_hidden size_t _mi_theap_cached_slot = MI_TLS_INITIAL_SLOT ;
773781mi_decl_hidden size_t _mi_theap_cached_expansion_slot = MI_TLS_INITIAL_EXPANSION_SLOT ;
774782
775- static size_t mi_win_tls_slot_alloc (size_t * extended ) {
776- const DWORD slot = TlsAlloc ();
777- if (slot == TLS_OUT_OF_INDEXES || slot >= MI_TLS_DIRECT_SLOTS + MI_TLS_EXPANSION_SLOTS - 1 ) {
778- // note: we also fail if the program already allocated the maximum number of expansion slots (as we use the last one as the default)
783+ static DWORD mi_tls_raw_index_default = TLS_OUT_OF_INDEXES ;
784+ static DWORD mi_tls_raw_index_cached = TLS_OUT_OF_INDEXES ;
785+
786+ static bool mi_win_tls_slot_alloc (size_t * slot , size_t * extended , DWORD * raw_index ) {
787+ const DWORD index = TlsAlloc ();
788+ * raw_index = index ;
789+ if (index == TLS_OUT_OF_INDEXES ) {
779790 * extended = 0 ;
780- return 0 ;
791+ * slot = 0 ;
792+ return false;
781793 }
782- else if (slot < MI_TLS_DIRECT_SLOTS ) {
794+ else if (index < MI_TLS_DIRECT_SLOTS ) {
783795 * extended = 0 ;
784- return (slot + MI_TLS_DIRECT_FIRST );
796+ * slot = index + MI_TLS_DIRECT_FIRST ;
797+ return true;
798+ }
799+ #if !MI_WIN_DIRECT_TLS
800+ else if (index < MI_TLS_DIRECT_SLOTS + MI_TLS_EXPANSION_SLOTS - 1 ) { // check maximum number of expansion slots - 1 (as we use the last one as the default)
801+ * extended = index - MI_TLS_DIRECT_SLOTS ;
802+ * slot = MI_TLS_EXPANSION_SLOT ;
803+ return true;
785804 }
805+ #endif
786806 else {
787- #if MI_WIN_DIRECT_TLS
807+ // to high an index for us
808+ _mi_error_message (EFAULT , "returned tls index was too high (%u)\n" , index );
809+ TlsFree (index );
810+ * raw_index = TLS_OUT_OF_INDEXES ;
788811 * extended = 0 ;
789- return 0 ;
790- #else
791- * extended = (slot - MI_TLS_DIRECT_SLOTS );
792- return MI_TLS_EXPANSION_SLOT ;
793- #endif
812+ * slot = 0 ;
813+ return false;
814+ }
815+ }
816+
817+ static void mi_win_tls_slot_free (DWORD * raw_index ) {
818+ if (* raw_index != TLS_OUT_OF_INDEXES ) {
819+ TlsFree (* raw_index );
820+ * raw_index = TLS_OUT_OF_INDEXES ;
794821 }
795822}
796823
797- mi_decl_cold mi_theap_t * _mi_win_tls_slots_init (void ) {
824+ static void mi_tls_slots_init (void ) {
798825 static mi_atomic_once_t tls_slots_init ;
799826 if (mi_atomic_once (& tls_slots_init )) {
800- _mi_theap_default_slot = mi_win_tls_slot_alloc (& _mi_theap_default_expansion_slot );
801- _mi_theap_cached_slot = mi_win_tls_slot_alloc (& _mi_theap_cached_expansion_slot );
802- if (_mi_theap_cached_slot == 0 ) {
827+ bool ok = mi_win_tls_slot_alloc (& _mi_theap_default_slot , & _mi_theap_default_expansion_slot , & mi_tls_raw_index_default );
828+ if (ok ) {
829+ ok = mi_win_tls_slot_alloc (& _mi_theap_cached_slot , & _mi_theap_cached_expansion_slot , & mi_tls_raw_index_cached );
830+ }
831+ if (!ok ) {
803832 _mi_error_message (EFAULT , "unable to allocate fast TLS user slot (0x%zx)\n" , _mi_theap_cached_slot );
804833 }
805834 }
806- return (mi_theap_t * )& _mi_theap_empty ;
835+ }
836+
837+ static void mi_tls_slots_done (void ) {
838+ mi_win_tls_slot_free (& mi_tls_raw_index_default );
839+ mi_win_tls_slot_free (& mi_tls_raw_index_cached );
807840}
808841
809842static void mi_win_tls_slot_set (size_t slot , size_t extended_slot , void * value ) {
@@ -823,13 +856,38 @@ static void mi_win_tls_slot_set(size_t slot, size_t extended_slot, void* value)
823856mi_decl_hidden pthread_key_t _mi_theap_default_key = 0 ;
824857mi_decl_hidden pthread_key_t _mi_theap_cached_key = 0 ;
825858
826- mi_decl_cold mi_theap_t * _mi_tls_keys_init (void ) {
859+ static void mi_tls_slots_init (void ) {
827860 static mi_atomic_once_t tls_keys_init ;
828861 if (mi_atomic_once (& tls_keys_init )) {
829- pthread_key_create (& _mi_theap_default_key , NULL );
830- pthread_key_create (& _mi_theap_cached_key , NULL );
862+ int err = pthread_key_create (& _mi_theap_default_key , NULL );
863+ if (err == 0 ) {
864+ err = pthread_key_create (& _mi_theap_cached_key , NULL );
865+ }
866+ if (err != 0 ) {
867+ _mi_error_message (EFAULT , "unable to allocate pthread keys (error %d)\n" , err );
868+ }
869+ }
870+ }
871+
872+ static void mi_tls_slots_done (void ) {
873+ if (_mi_theap_default_key != 0 ) {
874+ pthread_key_delete (_mi_theap_default_key );
875+ _mi_theap_default_key = 0 ;
876+ }
877+ if (_mi_theap_cached_key != 0 ) {
878+ pthread_key_delete (_mi_theap_cached_key );
879+ _mi_theap_cached_key = 0 ;
831880 }
832- return (mi_theap_t * )& _mi_theap_empty ;
881+ }
882+
883+ #else
884+
885+ static void mi_tls_slots_init (void ) {
886+ // nothing
887+ }
888+
889+ static void mi_tls_slots_done (void ) {
890+ // nothing
833891}
834892
835893#endif
@@ -838,15 +896,14 @@ void _mi_theap_cached_set(mi_theap_t* theap) {
838896 mi_theap_t * prev = _mi_theap_cached ();
839897 if (prev == theap ) return ;
840898 // set
899+ mi_tls_slots_init ();
841900 #if MI_TLS_MODEL_THREAD_LOCAL
842901 __mi_theap_cached = theap ;
843902 #elif MI_TLS_MODEL_FIXED_SLOT
844903 mi_prim_tls_slot_set (MI_TLS_MODEL_FIXED_SLOT_CACHED , theap );
845904 #elif MI_TLS_MODEL_DYNAMIC_WIN32
846- _mi_win_tls_slots_init ();
847905 mi_win_tls_slot_set (_mi_theap_cached_slot , _mi_theap_cached_expansion_slot , theap );
848906 #elif MI_TLS_MODEL_DYNAMIC_PTHREADS
849- _mi_tls_keys_init ();
850907 if (_mi_theap_cached_key != 0 ) pthread_setspecific (_mi_theap_cached_key , theap );
851908 #endif
852909 // update refcounts (so cached theap memory keeps available until no longer cached)
@@ -858,15 +915,14 @@ void _mi_theap_default_set(mi_theap_t* theap) {
858915 mi_theap_t * const theap_old = _mi_theap_default ();
859916 mi_assert_internal (theap != NULL );
860917 mi_assert_internal (theap -> tld -> thread_id == 0 || theap -> tld -> thread_id == _mi_thread_id ());
918+ mi_tls_slots_init ();
861919 #if MI_TLS_MODEL_THREAD_LOCAL
862920 __mi_theap_default = theap ;
863921 #elif MI_TLS_MODEL_FIXED_SLOT
864922 mi_prim_tls_slot_set (MI_TLS_MODEL_FIXED_SLOT_DEFAULT , theap );
865923 #elif MI_TLS_MODEL_DYNAMIC_WIN32
866- _mi_win_tls_slots_init ();
867924 mi_win_tls_slot_set (_mi_theap_default_slot , _mi_theap_default_expansion_slot , theap );
868925 #elif MI_TLS_MODEL_DYNAMIC_PTHREADS
869- _mi_tls_keys_init ();
870926 if (_mi_theap_default_key != 0 ) pthread_setspecific (_mi_theap_default_key , theap );
871927 #endif
872928
@@ -1080,17 +1136,18 @@ void mi_cdecl mi_process_done(void) mi_attr_noexcept {
10801136 // since after process_done there might still be other code running that calls `free` (like at_exit routines,
10811137 // or C-runtime termination code.
10821138 if (mi_option_is_enabled (mi_option_destroy_on_exit )) {
1083- mi_subprocs_unsafe_destroy_all ();
1084- _mi_page_map_unsafe_destroy (_mi_subproc_main ());
1139+ mi_subprocs_unsafe_destroy_all (); // destroys all subprocs, arenas, and the page_map!
10851140 }
10861141 else {
10871142 mi_heap_stats_merge_to_subproc (mi_heap_main ());
10881143 }
1089-
1144+
1145+ // careful now to no longer access any allocator functionality
10901146 if (mi_option_is_enabled (mi_option_show_stats ) || mi_option_is_enabled (mi_option_verbose )) {
10911147 mi_subproc_stats_print_out (NULL , NULL , NULL );
10921148 }
10931149 mi_lock_done (& subprocs_lock );
1150+ mi_tls_slots_done ();
10941151 _mi_allocator_done ();
10951152 _mi_verbose_message ("process done: 0x%zx\n" , tld_main .thread_id );
10961153 os_preloading = true; // don't call the C runtime anymore
0 commit comments