@@ -119,7 +119,7 @@ static void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz)
119119 if (bufsz <= pool_sizes [JL_N_STACK_POOLS - 1 ]) {
120120 unsigned pool_id = select_pool (bufsz );
121121 if (pool_sizes [pool_id ] == bufsz ) {
122- arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
122+ small_arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
123123 return ;
124124 }
125125 }
@@ -148,7 +148,7 @@ void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task)
148148#ifdef _COMPILER_ASAN_ENABLED_
149149 __asan_unpoison_stack_memory ((uintptr_t )stkbuf , bufsz );
150150#endif
151- arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
151+ small_arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
152152 }
153153 }
154154}
@@ -163,9 +163,9 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO
163163 if (ssize <= pool_sizes [JL_N_STACK_POOLS - 1 ]) {
164164 unsigned pool_id = select_pool (ssize );
165165 ssize = pool_sizes [pool_id ];
166- arraylist_t * pool = & ptls -> heap .free_stacks [pool_id ];
166+ small_arraylist_t * pool = & ptls -> heap .free_stacks [pool_id ];
167167 if (pool -> len > 0 ) {
168- stk = arraylist_pop (pool );
168+ stk = small_arraylist_pop (pool );
169169 }
170170 }
171171 else {
@@ -184,8 +184,8 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO
184184 }
185185 * bufsz = ssize ;
186186 if (owner ) {
187- arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
188- arraylist_push (live_tasks , owner );
187+ small_arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
188+ mtarraylist_push (live_tasks , owner );
189189 }
190190 return stk ;
191191}
@@ -209,7 +209,7 @@ void sweep_stack_pools(void)
209209
210210 // free half of stacks that remain unused since last sweep
211211 for (int p = 0 ; p < JL_N_STACK_POOLS ; p ++ ) {
212- arraylist_t * al = & ptls2 -> heap .free_stacks [p ];
212+ small_arraylist_t * al = & ptls2 -> heap .free_stacks [p ];
213213 size_t n_to_free ;
214214 if (al -> len > MIN_STACK_MAPPINGS_PER_POOL ) {
215215 n_to_free = al -> len / 2 ;
@@ -220,12 +220,12 @@ void sweep_stack_pools(void)
220220 n_to_free = 0 ;
221221 }
222222 for (int n = 0 ; n < n_to_free ; n ++ ) {
223- void * stk = arraylist_pop (al );
223+ void * stk = small_arraylist_pop (al );
224224 free_stack (stk , pool_sizes [p ]);
225225 }
226226 }
227227
228- arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
228+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
229229 size_t n = 0 ;
230230 size_t ndel = 0 ;
231231 size_t l = live_tasks -> len ;
@@ -268,24 +268,52 @@ void sweep_stack_pools(void)
268268
269269JL_DLLEXPORT jl_array_t * jl_live_tasks (void )
270270{
271- jl_task_t * ct = jl_current_task ;
272- jl_ptls_t ptls = ct -> ptls ;
273- arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
274- size_t i , j , l ;
275- jl_array_t * a ;
276- do {
277- l = live_tasks -> len ;
278- a = jl_alloc_vec_any (l + 1 ); // may gc, changing the number of tasks
279- } while (l + 1 < live_tasks -> len );
280- l = live_tasks -> len ;
281- void * * lst = live_tasks -> items ;
282- j = 0 ;
283- ((void * * )jl_array_data (a ))[j ++ ] = ptls -> root_task ;
284- for (i = 0 ; i < l ; i ++ ) {
285- if (((jl_task_t * )lst [i ])-> stkbuf != NULL )
286- ((void * * )jl_array_data (a ))[j ++ ] = lst [i ];
271+ size_t nthreads = jl_atomic_load_acquire (& jl_n_threads );
272+ jl_ptls_t * allstates = jl_atomic_load_relaxed (& jl_all_tls_states );
273+ size_t l = 0 ; // l is not reset on restart, so we keep getting more aggressive at making a big enough list everything it fails
274+ restart :
275+ for (size_t i = 0 ; i < nthreads ; i ++ ) {
276+ // skip GC threads since they don't have tasks
277+ if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads ) {
278+ continue ;
279+ }
280+ jl_ptls_t ptls2 = allstates [i ];
281+ if (ptls2 == NULL )
282+ continue ;
283+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
284+ size_t n = mtarraylist_length (live_tasks );
285+ l += n + (ptls2 -> root_task -> stkbuf != NULL );
286+ }
287+ l += l / 20 ; // add 5% for margin of estimation error
288+ jl_array_t * a = jl_alloc_vec_any (l ); // may gc, changing the number of tasks and forcing us to reload everything
289+ nthreads = jl_atomic_load_acquire (& jl_n_threads );
290+ allstates = jl_atomic_load_relaxed (& jl_all_tls_states );
291+ size_t j = 0 ;
292+ for (size_t i = 0 ; i < nthreads ; i ++ ) {
293+ // skip GC threads since they don't have tasks
294+ if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads ) {
295+ continue ;
296+ }
297+ jl_ptls_t ptls2 = allstates [i ];
298+ if (ptls2 == NULL )
299+ continue ;
300+ jl_task_t * t = ptls2 -> root_task ;
301+ if (t -> stkbuf != NULL ) {
302+ if (j == l )
303+ goto restart ;
304+ ((void * * )jl_array_data (a ))[j ++ ] = t ;
305+ }
306+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
307+ size_t n = mtarraylist_length (live_tasks );
308+ for (size_t i = 0 ; i < n ; i ++ ) {
309+ jl_task_t * t = (jl_task_t * )mtarraylist_get (live_tasks , i );
310+ if (t -> stkbuf != NULL ) {
311+ if (j == l )
312+ goto restart ;
313+ ((void * * )jl_array_data (a ))[j ++ ] = t ;
314+ }
315+ }
287316 }
288- l = jl_array_len (a );
289317 if (j < l ) {
290318 JL_GC_PUSH1 (& a );
291319 jl_array_del_end (a , l - j );
0 commit comments