@@ -554,6 +554,7 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
554554
555555 if (!VirtualProtect (page , RB_PAGE_SIZE , PAGE_READWRITE | PAGE_GUARD , & old_protect )) {
556556 VirtualFree (allocation -> base , 0 , MEM_RELEASE );
557+ ruby_xfree (allocation );
557558 rb_raise (rb_eFiberError , "can't set a guard page: %s" , ERRNOMSG );
558559 }
559560#elif defined(__wasi__ )
@@ -666,13 +667,23 @@ fiber_pool_allocation_free(struct fiber_pool_allocation * allocation)
666667static struct fiber_pool_stack
667668fiber_pool_stack_acquire (struct fiber_pool * fiber_pool )
668669{
669- struct fiber_pool_vacancy * vacancy ;
670+ struct fiber_pool_vacancy * vacancy ;
671+
670672 RB_VM_LOCK_ENTER ();
671673 {
672674 vacancy = fiber_pool_vacancy_pop (fiber_pool );
673675
674676 if (DEBUG ) fprintf (stderr , "fiber_pool_stack_acquire: %p used=%" PRIuSIZE "\n" , (void * )fiber_pool -> vacancies , fiber_pool -> used );
675677
678+ // During allocation, if we run out of stacks, we may need to collect garbage to free up some stacks before trying to allocate more.
679+ if (!vacancy ) {
680+ if (DEBUG )fprintf (stderr , "fiber_pool_stack_acquire: no stacks available, collecting garbage\n" );
681+ rb_gc ();
682+
683+ // In the worst case, we garbage collect, but all fibers are reachable, so we don't free any stacks. We will try to expand the fiber pool:
684+ vacancy = fiber_pool_vacancy_pop (fiber_pool );
685+ }
686+
676687 if (!vacancy ) {
677688 const size_t maximum = FIBER_POOL_ALLOCATION_MAXIMUM_SIZE ;
678689 const size_t minimum = fiber_pool -> initial_count ;
@@ -681,6 +692,7 @@ fiber_pool_stack_acquire(struct fiber_pool * fiber_pool)
681692 if (count > maximum ) count = maximum ;
682693 if (count < minimum ) count = minimum ;
683694
695+ if (DEBUG )fprintf (stderr , "fiber_pool_stack_acquire: expanding fiber pool to %" PRIuSIZE " stacks\n" , count );
684696 fiber_pool_expand (fiber_pool , count );
685697
686698 // The free list should now contain some stacks:
0 commit comments