2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-07 19:04:20 +00:00

SubProcess.pm: changes by zap (timeouts, one datagram at a time)

git-svn-id: https://svn.fhem.de/fhem/trunk@11128 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
borisneubert 2016-03-26 17:55:58 +00:00
parent 112cbc85d9
commit 23e1c696dc

View File

@ -49,6 +49,8 @@ sub new() {
$child->autoflush(1); $child->autoflush(1);
$parent->autoflush(1); $parent->autoflush(1);
# Buffers are not used in this version of SubProcess.pm
# Revision 8393 had it
my %childBuffer= (); my %childBuffer= ();
my %parentBuffer= (); my %parentBuffer= ();
@ -57,18 +59,41 @@ sub new() {
onRun => $args->{onRun}, onRun => $args->{onRun},
onExit => $args->{onExit}, onExit => $args->{onExit},
timeout => $args->{timeout}, timeout => $args->{timeout},
timeoutread => $args->{timeoutread},
timeoutwrite => $args->{timeoutwrite},
child => $child, child => $child,
parent => $parent, parent => $parent,
pid => undef, pid => undef,
childBufferRef => \%childBuffer, childBufferRef => \%childBuffer,
parentBufferRef => \%parentBuffer, parentBufferRef => \%parentBuffer,
lasterror => ''
}; # we are a hash reference }; # we are a hash reference
# Timeout must be defined and > 0
# 0 = Polling, undef = Block until data available
if(defined($self->{timeout})) {
$self->{timeout} = 0.001 if ($self->{timeout} <= 0.0);
}
else {
$self->{timeout} = 0.001;
}
if (!defined ($self->{timeoutread})) {
$self->{timeoutread} = $self->{timeout};
}
if (!defined ($self->{timeoutwrite})) {
$self->{timeoutwrite} = $self->{timeout};
}
return bless($self, $class); # make $self an object of class $class return bless($self, $class); # make $self an object of class $class
} }
sub lasterror() {
my $self = shift;
return exists ($self->{lasterror}) ? $self->{lasterror} : '';
}
# #
# returns the pid of the subprocess # returns the pid of the subprocess
# undef if subprocess not available # undef if subprocess not available
@ -150,52 +175,82 @@ sub parent() {
} }
# this is a helper function for reading # this is a helper function for reading
# returns 1 datagram or undef on error
# this version does not handle split transmissions that result in short datagrams
# Todo: buffer such datagrams
sub readFrom() { sub readFrom() {
my ($self, $fh, $bufferRef)= @_; my ($self, $fh) = @_;
my %buffer= %{$bufferRef};
my $rin= ''; my $header;
vec($rin, fileno($fh), 1)= 1;
return undef unless select($rin, undef, undef, 0.001);
my $result= undef;
my $data; my $data;
my $bytes= sysread($fh, $data, 1024);
return undef unless(defined($bytes) && $bytes);
#main::Debug "SUBPROCESS: read \"$data\"";
# prepend buffer if buffer is set # Check if data is available
$data= $buffer{data} . $data if(defined($buffer{data})); my $rin= '';
my $len= length($data); vec($rin, fileno($fh), 1) = 1;
#main::Debug "SUBPROCESS: data is now \"$data\" (length: $len)"; my $nfound = select($rin, undef, undef, $self->{timeoutread});
# get or set size (32bit unsigned integer in network byte order) if ($nfound < 0) {
my $size= defined($buffer{size}) ? $buffer{size} : undef; $self->{lasterror} = $!;
if(!defined($size) && $len>= 4) { return undef;
$size= unpack("N", $data);
$data= substr($data, 4);
$len-= 4;
#main::Debug "SUBPROCESS: got size: $size";
} }
# get the datagram if size is set and data length is at least size elsif ($nfound == 0) {
if(defined($size) && $len>= $size) { $self->{lasterror} = "read: no data";
$result= substr($data, 0, $size); return undef;
$size= undef;
#main::Debug "SUBPROCESS: data complete: \"$data\"";
} }
# set buffer
$buffer{data}= $data; # Read datagram size
$buffer{size}= $size; my $sbytes = sysread ($fh, $header, 4);
# return result if (!defined ($sbytes)) {
return $result; $self->{lasterror} = $!;
return undef;
}
elsif ($sbytes != 4) {
$self->{lasterror} = "read: short header";
return undef;
}
# Read datagram
my $size = unpack ('N', $header);
my $bytes = sysread ($fh, $data, $size);
if (!defined ($bytes)) {
$self->{lasterror} = $!;
return undef;
}
elsif ($bytes != $size) {
$self->{lasterror} = "read: incomplete data";
return undef;
}
return $data;
} }
# this is a helper function for writing # this is a helper function for writing
# writes 4 byte datagram size + datagram
sub writeTo() { sub writeTo() {
my ($self, $fh, $msg)= @_; my ($self, $fh, $msg) = @_;
my $win= ''; my $win= '';
vec($win, fileno($fh), 1)= 1; vec($win, fileno($fh), 1)= 1;
return undef unless select(undef, $win, undef, 0.001); my $nfound = select (undef, $win, undef, $self->{timeoutwrite});
if ($nfound < 0) {
$self->{lasterror} = $!;
return undef;
}
elsif ($nfound == 0) {
$self->{lasterror} = "write: no reader";
return undef;
}
my $size= pack("N", length($msg)); my $size= pack("N", length($msg));
my $bytes= syswrite($fh, $size . $msg); my $bytes= syswrite ($fh, $size . $msg);
if (!defined ($bytes)) {
$self->{lasterror} = $!;
return undef;
}
elsif ($bytes != length ($size.$msg)) {
$self->{lasterror} = "write: incomplete data";
return undef;
}
return $bytes; return $bytes;
} }
@ -207,7 +262,7 @@ sub readFromChild() {
my $self= shift; my $self= shift;
return $self->readFrom($self->child(), $self->{childBufferRef}); return $self->readFrom($self->child());
} }
@ -225,7 +280,7 @@ sub writeToChild() {
sub readFromParent() { sub readFromParent() {
my $self= shift; my $self= shift;
return $self->readFrom($self->parent(), $self->{parentBufferRef}); return $self->readFrom($self->parent());
} }