dk / Prima

prima.eu.org
Other
108 stars 27 forks source link

CPU spin using Prima::File on a socket #95

Closed haxmeister closed 1 year ago

haxmeister commented 1 year ago
#!/usr/bin/perl

use Prima qw(Application);
use IO::Socket::INET;

my $inbuff;
my @outbuff;

my $socket = IO::Socket::INET->new(
    PeerAddr => '111.11.111.11',
    PeerPort => 9765,
    Proto    => 'tcp',
    Blocking => 0,
)or die "Cannot create socket - $IO::Socket::errstr\n";

my $watcher = Prima::File-> new(
    file        => $socket,
    onRead      => sub($watcher, $socket){
                        my $raw_data;
                        $socket->recv($raw_data, 1024);
                        $inbuff .= $raw_data;
                        },
    onWrite     => sub($watcher, $socket){
                        while (@{ $self->{outbuff} }){
                            $socket->send(shift(@outbuff));
                        }
                    },
        #onException => sub($handle){ $self->_exception},
)or die "Cannot create Prima::File object\n";

Prima->run;

This code produces 100% cpu usage though it does otherwise function.

haxmeister commented 1 year ago

Machine is Operating System: openSUSE Tumbleweed 20230603 KDE Plasma Version: 5.27.5 KDE Frameworks Version: 5.106.0 Qt Version: 5.15.9 Kernel Version: 6.3.4-1-default (64-bit) Graphics Platform: X11 Processors: 6 × Intel® Core™ i5-8500 CPU @ 3.00GHz Memory: 15.4 GiB of RAM Graphics Processor: Mesa Intel® UHD Graphics 630 Manufacturer: HP Product Name: HP EliteDesk 800 G4 SFF

dk commented 1 year ago

I'm not sure what's the protocol or the service running on port 9765, but if the meaning was to demonstrate that this is on a unconnected socket, then this works as intended - onRead/onWrite are a direct map to select(2). If you check the recv()'s first result, it would be undef and $! is ECONNREFUSED and subsequent reads would yield 0 bytes:

pselect6(5, [3 4], [3], [], {tv_sec=0, tv_nsec=0}, NULL) = 2 (in [3], out [3], left {tv_sec=0, tv_nsec=0})
recvfrom(3, 0x5653bc4f95c0, 1024, 0, 0x7ffe6ffb30f0, [4096]) = -1 ECONNREFUSED (Connection refused)
pselect6(5, [3 4], [3], [], {tv_sec=0, tv_nsec=0}, NULL) = 2 (in [3], out [3], left {tv_sec=0, tv_nsec=0})
recvfrom(3, "", 1024, 0, 0x7ffe6ffb30f0, [4096 => 0]) = 0

select() apparently treats a socket in such state as readable, which results in the trashing observed.