@@ -112,7 +112,7 @@ static void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz)
112112 if (bufsz <= pool_sizes [JL_N_STACK_POOLS - 1 ]) {
113113 unsigned pool_id = select_pool (bufsz );
114114 if (pool_sizes [pool_id ] == bufsz ) {
115- arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
115+ small_arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
116116 return ;
117117 }
118118 }
@@ -141,7 +141,7 @@ void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task)
141141#ifdef _COMPILER_ASAN_ENABLED_
142142 __asan_unpoison_stack_memory ((uintptr_t )stkbuf , bufsz );
143143#endif
144- arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
144+ small_arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
145145 }
146146 }
147147}
@@ -156,9 +156,9 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO
156156 if (ssize <= pool_sizes [JL_N_STACK_POOLS - 1 ]) {
157157 unsigned pool_id = select_pool (ssize );
158158 ssize = pool_sizes [pool_id ];
159- arraylist_t * pool = & ptls -> heap .free_stacks [pool_id ];
159+ small_arraylist_t * pool = & ptls -> heap .free_stacks [pool_id ];
160160 if (pool -> len > 0 ) {
161- stk = arraylist_pop (pool );
161+ stk = small_arraylist_pop (pool );
162162 }
163163 }
164164 else {
@@ -177,8 +177,8 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO
177177 }
178178 * bufsz = ssize ;
179179 if (owner ) {
180- arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
181- arraylist_push (live_tasks , owner );
180+ small_arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
181+ mtarraylist_push (live_tasks , owner );
182182 }
183183 return stk ;
184184}
@@ -202,7 +202,7 @@ void sweep_stack_pools(void)
202202
203203 // free half of stacks that remain unused since last sweep
204204 for (int p = 0 ; p < JL_N_STACK_POOLS ; p ++ ) {
205- arraylist_t * al = & ptls2 -> heap .free_stacks [p ];
205+ small_arraylist_t * al = & ptls2 -> heap .free_stacks [p ];
206206 size_t n_to_free ;
207207 if (al -> len > MIN_STACK_MAPPINGS_PER_POOL ) {
208208 n_to_free = al -> len / 2 ;
@@ -213,12 +213,12 @@ void sweep_stack_pools(void)
213213 n_to_free = 0 ;
214214 }
215215 for (int n = 0 ; n < n_to_free ; n ++ ) {
216- void * stk = arraylist_pop (al );
216+ void * stk = small_arraylist_pop (al );
217217 free_stack (stk , pool_sizes [p ]);
218218 }
219219 }
220220
221- arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
221+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
222222 size_t n = 0 ;
223223 size_t ndel = 0 ;
224224 size_t l = live_tasks -> len ;
@@ -261,24 +261,52 @@ void sweep_stack_pools(void)
261261
262262JL_DLLEXPORT jl_array_t * jl_live_tasks (void )
263263{
264- jl_task_t * ct = jl_current_task ;
265- jl_ptls_t ptls = ct -> ptls ;
266- arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
267- size_t i , j , l ;
268- jl_array_t * a ;
269- do {
270- l = live_tasks -> len ;
271- a = jl_alloc_vec_any (l + 1 ); // may gc, changing the number of tasks
272- } while (l + 1 < live_tasks -> len );
273- l = live_tasks -> len ;
274- void * * lst = live_tasks -> items ;
275- j = 0 ;
276- ((void * * )jl_array_data (a ))[j ++ ] = ptls -> root_task ;
277- for (i = 0 ; i < l ; i ++ ) {
278- if (((jl_task_t * )lst [i ])-> stkbuf != NULL )
279- ((void * * )jl_array_data (a ))[j ++ ] = lst [i ];
264+ size_t nthreads = jl_atomic_load_acquire (& jl_n_threads );
265+ jl_ptls_t * allstates = jl_atomic_load_relaxed (& jl_all_tls_states );
266+ 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
267+ restart :
268+ for (size_t i = 0 ; i < nthreads ; i ++ ) {
269+ // skip GC threads since they don't have tasks
270+ if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads ) {
271+ continue ;
272+ }
273+ jl_ptls_t ptls2 = allstates [i ];
274+ if (ptls2 == NULL )
275+ continue ;
276+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
277+ size_t n = mtarraylist_length (live_tasks );
278+ l += n + (ptls2 -> root_task -> stkbuf != NULL );
279+ }
280+ l += l / 20 ; // add 5% for margin of estimation error
281+ jl_array_t * a = jl_alloc_vec_any (l ); // may gc, changing the number of tasks and forcing us to reload everything
282+ nthreads = jl_atomic_load_acquire (& jl_n_threads );
283+ allstates = jl_atomic_load_relaxed (& jl_all_tls_states );
284+ size_t j = 0 ;
285+ for (size_t i = 0 ; i < nthreads ; i ++ ) {
286+ // skip GC threads since they don't have tasks
287+ if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads ) {
288+ continue ;
289+ }
290+ jl_ptls_t ptls2 = allstates [i ];
291+ if (ptls2 == NULL )
292+ continue ;
293+ jl_task_t * t = ptls2 -> root_task ;
294+ if (t -> stkbuf != NULL ) {
295+ if (j == l )
296+ goto restart ;
297+ ((void * * )jl_array_data (a ))[j ++ ] = t ;
298+ }
299+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
300+ size_t n = mtarraylist_length (live_tasks );
301+ for (size_t i = 0 ; i < n ; i ++ ) {
302+ jl_task_t * t = (jl_task_t * )mtarraylist_get (live_tasks , i );
303+ if (t -> stkbuf != NULL ) {
304+ if (j == l )
305+ goto restart ;
306+ ((void * * )jl_array_data (a ))[j ++ ] = t ;
307+ }
308+ }
280309 }
281- l = jl_array_len (a );
282310 if (j < l ) {
283311 JL_GC_PUSH1 (& a );
284312 jl_array_del_end (a , l - j );
0 commit comments