@@ -116,7 +116,7 @@ static void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz)
116116 if (bufsz <= pool_sizes [JL_N_STACK_POOLS - 1 ]) {
117117 unsigned pool_id = select_pool (bufsz );
118118 if (pool_sizes [pool_id ] == bufsz ) {
119- arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
119+ small_arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
120120 return ;
121121 }
122122 }
@@ -145,7 +145,7 @@ void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task)
145145#ifdef _COMPILER_ASAN_ENABLED_
146146 __asan_unpoison_stack_memory ((uintptr_t )stkbuf , bufsz );
147147#endif
148- arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
148+ small_arraylist_push (& ptls -> heap .free_stacks [pool_id ], stkbuf );
149149 }
150150 }
151151}
@@ -160,9 +160,9 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO
160160 if (ssize <= pool_sizes [JL_N_STACK_POOLS - 1 ]) {
161161 unsigned pool_id = select_pool (ssize );
162162 ssize = pool_sizes [pool_id ];
163- arraylist_t * pool = & ptls -> heap .free_stacks [pool_id ];
163+ small_arraylist_t * pool = & ptls -> heap .free_stacks [pool_id ];
164164 if (pool -> len > 0 ) {
165- stk = arraylist_pop (pool );
165+ stk = small_arraylist_pop (pool );
166166 }
167167 }
168168 else {
@@ -181,8 +181,8 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO
181181 }
182182 * bufsz = ssize ;
183183 if (owner ) {
184- arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
185- arraylist_push (live_tasks , owner );
184+ small_arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
185+ mtarraylist_push (live_tasks , owner );
186186 }
187187 return stk ;
188188}
@@ -206,7 +206,7 @@ void sweep_stack_pools(void)
206206
207207 // free half of stacks that remain unused since last sweep
208208 for (int p = 0 ; p < JL_N_STACK_POOLS ; p ++ ) {
209- arraylist_t * al = & ptls2 -> heap .free_stacks [p ];
209+ small_arraylist_t * al = & ptls2 -> heap .free_stacks [p ];
210210 size_t n_to_free ;
211211 if (al -> len > MIN_STACK_MAPPINGS_PER_POOL ) {
212212 n_to_free = al -> len / 2 ;
@@ -217,12 +217,12 @@ void sweep_stack_pools(void)
217217 n_to_free = 0 ;
218218 }
219219 for (int n = 0 ; n < n_to_free ; n ++ ) {
220- void * stk = arraylist_pop (al );
220+ void * stk = small_arraylist_pop (al );
221221 free_stack (stk , pool_sizes [p ]);
222222 }
223223 }
224224
225- arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
225+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
226226 size_t n = 0 ;
227227 size_t ndel = 0 ;
228228 size_t l = live_tasks -> len ;
@@ -265,24 +265,52 @@ void sweep_stack_pools(void)
265265
266266JL_DLLEXPORT jl_array_t * jl_live_tasks (void )
267267{
268- jl_task_t * ct = jl_current_task ;
269- jl_ptls_t ptls = ct -> ptls ;
270- arraylist_t * live_tasks = & ptls -> heap .live_tasks ;
271- size_t i , j , l ;
272- jl_array_t * a ;
273- do {
274- l = live_tasks -> len ;
275- a = jl_alloc_vec_any (l + 1 ); // may gc, changing the number of tasks
276- } while (l + 1 < live_tasks -> len );
277- l = live_tasks -> len ;
278- void * * lst = live_tasks -> items ;
279- j = 0 ;
280- ((void * * )jl_array_data (a ))[j ++ ] = ptls -> root_task ;
281- for (i = 0 ; i < l ; i ++ ) {
282- if (((jl_task_t * )lst [i ])-> stkbuf != NULL )
283- ((void * * )jl_array_data (a ))[j ++ ] = lst [i ];
268+ size_t nthreads = jl_atomic_load_acquire (& jl_n_threads );
269+ jl_ptls_t * allstates = jl_atomic_load_relaxed (& jl_all_tls_states );
270+ 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
271+ restart :
272+ for (size_t i = 0 ; i < nthreads ; i ++ ) {
273+ // skip GC threads since they don't have tasks
274+ if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads ) {
275+ continue ;
276+ }
277+ jl_ptls_t ptls2 = allstates [i ];
278+ if (ptls2 == NULL )
279+ continue ;
280+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
281+ size_t n = mtarraylist_length (live_tasks );
282+ l += n + (ptls2 -> root_task -> stkbuf != NULL );
283+ }
284+ l += l / 20 ; // add 5% for margin of estimation error
285+ jl_array_t * a = jl_alloc_vec_any (l ); // may gc, changing the number of tasks and forcing us to reload everything
286+ nthreads = jl_atomic_load_acquire (& jl_n_threads );
287+ allstates = jl_atomic_load_relaxed (& jl_all_tls_states );
288+ size_t j = 0 ;
289+ for (size_t i = 0 ; i < nthreads ; i ++ ) {
290+ // skip GC threads since they don't have tasks
291+ if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads ) {
292+ continue ;
293+ }
294+ jl_ptls_t ptls2 = allstates [i ];
295+ if (ptls2 == NULL )
296+ continue ;
297+ jl_task_t * t = ptls2 -> root_task ;
298+ if (t -> stkbuf != NULL ) {
299+ if (j == l )
300+ goto restart ;
301+ ((void * * )jl_array_data (a ))[j ++ ] = t ;
302+ }
303+ small_arraylist_t * live_tasks = & ptls2 -> heap .live_tasks ;
304+ size_t n = mtarraylist_length (live_tasks );
305+ for (size_t i = 0 ; i < n ; i ++ ) {
306+ jl_task_t * t = (jl_task_t * )mtarraylist_get (live_tasks , i );
307+ if (t -> stkbuf != NULL ) {
308+ if (j == l )
309+ goto restart ;
310+ ((void * * )jl_array_data (a ))[j ++ ] = t ;
311+ }
312+ }
284313 }
285- l = jl_array_len (a );
286314 if (j < l ) {
287315 JL_GC_PUSH1 (& a );
288316 jl_array_del_end (a , l - j );
0 commit comments