SPVM-Go
view release on metacpan or search on metacpan
lib/SPVM/Go/Poll.spvm view on Meta::CPAN
# Copyright (c) 2023 Yuki Kimoto
# MIT License
class Go::Poll {
allow Go::Schedule;
allow Go::Schedule::Task;
use Go::Coroutine;
use List;
use Sys::Poll::PollfdArray;
use Sys::Poll::Constant as POLL;
use Sys::Poll;
has coroutines_h : Hash of Go::Coroutine;
static method new : Go::Poll () {
my $self = new Go::Poll;
$self->{coroutines_h} = Hash->new;
return $self;
}
private method check : void () {
my $poll_coroutines_h = $self->{coroutines_h};
my $poll_coroutines_length = $poll_coroutines_h->keys_length;
if ($poll_coroutines_length > 0) {
my $poll_fd_array = Sys::Poll::PollfdArray->new($poll_coroutines_length);
my $poll_coroutine_addresses = $poll_coroutines_h->keys;
my $poll_index = 0;
for my $address (@$poll_coroutine_addresses) {
my $poll_coroutine = (Go::Coroutine)$poll_coroutines_h->get($address);
my $fd = $poll_coroutine->{fd};
$poll_fd_array->set_fd($poll_index, $fd);
my $is_write = $poll_coroutine->{is_write};
if ($is_write) {
$poll_fd_array->set_events($poll_index, POLL->POLLOUT);
}
else {
$poll_fd_array->set_events($poll_index, POLL->POLLIN);
}
$poll_coroutine->{poll_index} = $poll_index;
$poll_index++;
}
my $status = Sys::Poll->poll($poll_fd_array, $poll_coroutines_length, 0);
for my $address (@$poll_coroutine_addresses) {
my $poll_coroutine = (Go::Coroutine)$poll_coroutines_h->get($address);
my $poll_index = $poll_coroutine->{poll_index};
my $revent = $poll_fd_array->revents($poll_index);
my $io_ready = 0;
if ($poll_coroutine->{is_write}) {
if ($revent & POLL->POLLOUT) {
$io_ready = 1;
}
}
else {
if ($revent & POLL->POLLIN) {
$io_ready = 1;
}
}
my $io_timeout_occur = 0;
unless ($io_ready) {
my $deadline_base_io_timeout = $poll_coroutine->{deadline_base_io_timeout};
if ($deadline_base_io_timeout) {
my $io_timeout = $poll_coroutine->{io_timeout};
$io_timeout_occur = &check_io_timeout($deadline_base_io_timeout, $io_timeout);
$poll_coroutine->{io_timeout_occur} = (byte)$io_timeout_occur;
}
}
if ($io_ready || $io_timeout_occur) {
my $ready_coroutine = (Go::Coroutine)$poll_coroutines_h->delete($address);
$ready_coroutine->{disable} = 0;
$ready_coroutine->{fd} = -1;
$ready_coroutine->{deadline_base_io_timeout} = undef;
}
}
}
}
private static method check_io_timeout : int ($deadline_base : Sys::Time::Timespec, $timeout : double) {
my $deadline_now = Go::Schedule->clock_gettime;
my $interval = Sys::Time::Util->timespec_interval($deadline_base, $deadline_now);
my $timeout_occur = $timeout - $interval < 0;
if (Go->ENV_DEBUG) {
Fn->say_stderr(Fn->sprintf("[Go Debug]Check IO timeout(Timeout:%f, ElapsedTime:%f, TimeoutOccur:%d).", [(object)$timeout, $interval, $timeout_occur]));
}
return $timeout_occur;
}
method DESTROY : void () {
my $poll_coroutines_h = $self->{coroutines_h};
my $poll_coroutniens_length = $poll_coroutines_h->keys_length;
unless ($poll_coroutniens_length == 0) {
die "[Unexpected Error]The number of goroutines for IO must be 0 in DESTROY.";
}
}
}
( run in 1.466 second using v1.01-cache-2.11-cpan-39bf76dae61 )