SPVM-Go

 view release on metacpan or  search on metacpan

lib/SPVM/Go/Schedule/Task.spvm  view on Meta::CPAN

# Copyright (c) 2023 Yuki Kimoto
# MIT License

class Go::Schedule::Task {
  allow Go::Schedule;
  
  use Sys::Time;
  use Sys::Time::Timespec;
  use Sys::Poll::PollfdArray;
  use Sys::Poll::Constant as POLL;
  use Sys::Poll;
  
  has schedule : Go::Schedule;
  
  private static method new : Go::Schedule::Task () {
    
    my $self = new Go::Schedule::Task;
    
    return $self;
  }
  
  private method : void () {
    
    my $schedule = $self->{schedule};
    
    my $poll = $schedule->{poll};
    
    my $loop_count = 0;
    while (1) {
      
      my $coroutines = $schedule->{coroutines};
      
      if ($coroutines->length == 0) {
        last;
      }
      
      my $check_io = $loop_count % 60 == 0;
      
      if ($check_io) {
        $poll->check;
      }
      else {
        my $coroutine = (Go::Coroutine)undef;
        
        if ($coroutines->length > 0) {
          $coroutine = (Go::Coroutine)$coroutines->get(0);
        }
        
        if ($coroutine->{finished}) {
          $coroutines->shift;
          
          $schedule->{current_coroutine} = undef;
          
          if (Go->ENV_DEBUG) {
            Fn->say_stderr(Fn->sprintf("[Go Debug]End goroutine (Callback:%p, QueueNum:%d.)", [(object)$coroutine->{task}, $coroutines->length]));
          }
        }
        elsif ($coroutine->{disable}) {
          $coroutines->push($coroutines->shift);
          
          if (Go->ENV_DEBUG) {
            Fn->say_stderr(Fn->sprintf("[Go Debug]Rotate IO goroutine (Callback:%p, QueueNum:%d.)", [(object)$coroutine->{task}, $coroutines->length]));
          }
        }
        else {
          my $is_over_deadline = 0;
          
          my $deadline_base_timer = $coroutine->{deadline_base_timer};
          my $after = $coroutine->{after};
          
          if ($deadline_base_timer) {
            
            $is_over_deadline = Go::Schedule->is_over_deadline($deadline_base_timer, $after);
            
            if ($is_over_deadline) {
              $coroutine->{deadline_base_timer} = undef;
            }
            else {
              $coroutines->push($coroutines->shift);
              
              if (Go->ENV_DEBUG) {
                Fn->say_stderr(Fn->sprintf("[Go Debug]Rotate timer goroutine (Callback:%p, QueueNum:%d)", [(object)$coroutine->{task}, $coroutines->length]));
              }
            }
          }
          else {
            $is_over_deadline = 1;
          }
          
          my $fd = $coroutine->{fd};
          if ($fd >= 0) {
            $coroutine->{disable} = 1;
            my $coroutine_address = Fn->to_address($coroutine);
            $schedule->{poll}->{coroutines_h}->set($coroutine_address, $coroutine);
            $coroutines->push($coroutines->shift);
            
            if (Go->ENV_DEBUG) {
              Fn->say_stderr(Fn->sprintf("[Go Debug]Rotate IO goroutine first time (Callback:%p, QueueNum:%d.)", [(object)$coroutine->{task}, $coroutines->length]));
            }
          }
          else {
            if ($is_over_deadline) {
              
              my $schedule_task_coroutine = $schedule->{schedule_task_coroutine};
              
              $coroutines->push($coroutines->shift);
              
              $coroutine->{return_back} = $schedule_task_coroutine;
              
              $schedule->{current_coroutine} = $coroutine;
              
              Go::Coroutine->transfer($schedule_task_coroutine, $coroutine);
              
              if (Go->ENV_DEBUG) {
                Fn->say_stderr(Fn->sprintf("[Go Debug]Start or resume goroutine (Callback:%p, QueueNum:%d.)", [(object)$coroutine->{task}, $coroutines->length]));
              }
            }
          }
        }
      }
      
      $loop_count++;
    }
  }
  
}



( run in 1.654 second using v1.01-cache-2.11-cpan-39bf76dae61 )