# Copyright (c) 2023 Yuki Kimoto
# MIT License
class Go::OS::Signal {
version_from Go;
use Go;
use Go::Channel;
use Sys::Signal;
use Sys::IO::Constant as IO;
use Sys;
use Errno;
use Thread;
use Go::Sync::WaitGroup;
INIT {
my $read_fd = -1;
my $write_fd = -1;
Sys->pipe(\$read_fd, \$write_fd);
$READ_FD = $read_fd;
unless (Sys::OS->is_windows) {
Sys->fcntl($READ_FD, IO->F_SETFL, IO->O_NONBLOCK);
}
Sys::Signal->SET_SIG_GO_WRITE_FD($write_fd);
}
our $READ_FD : int;
static method ignore : void ($signal : int) {
Sys::Signal->signal($signal, Sys::Signal->SIG_IGN);
}
static method notify : void ($channel : Go::Channel, $signal : int) {
unless ($channel) {
die "\$channel must be defined.";
}
Sys::Signal->signal($signal, Sys::Signal->SIG_GO);
Go->go([$channel : Go::Channel] method : void () {
my $buffer = (mutable string)new_string_len 4;
my $use_thread = 0;
if (Sys::OS->is_windows) {
$use_thread = 1;
}
if ($use_thread) {
my $wg = Go::Sync::WaitGroup->new;
$wg->add(1);
my $thread = Thread->new([$wg : Go::Sync::WaitGroup, $buffer : mutable string] method : void () {
Fn->defer([$wg : Go::Sync::WaitGroup] method : void () {
$wg->done;
});
Sys::IO->read($READ_FD, $buffer, 4);
});
$wg->wait;
$thread->join;
}
else {
while (1) {
eval { Sys::IO->read($READ_FD, $buffer, 4); }
if ($@) {
if (Errno->errno == Errno->EWOULDBLOCK || Errno->errno == Errno->EINTR) {
Go->gosched_io_read($READ_FD);
}
else {
die $@;
}
}
else {
last;
}
}
}
my $numbers = new int [1];
Fn->memcpy($numbers, 0, $buffer, 0, 4);
my $got_signal = $numbers->[0];
$channel->write($got_signal);
});
}
use Sys::Process;
use Sys::IO;
use Sys;
}