eichin@apollo.com (10/27/90)
I'm using select to wait for a collection of file descriptors. I build
masks $rin and $win:
@fdnames=(F1,F2,F3,F4,F5,F6,F7,F8,F9,F10);
foreach(@fdnames) {
$tin = ''; vec($tin,fileno($_),1) = 1;
if($mode{$_} eq "writewait") { $win = $win | $tin; }
if($mode{$_} eq "readwait") { $rin = $rin | $tin; }
}
$nfound = select($rin,$win,undef,undef);
The question: how do I check which bits are set (ie which filehandles
are available for read or write)? I have a similar loop, which does
($win & $tin) and checks it, but what is the right way to check?
($win & $tin) is always true. In fact, I tried a few tests (setting
$xx=$foo & $bar), and found the following were *always* true:
if($xx)
if($xx == 0)
if($xx eq "")
if(defined($xx))
throwing in a ($vxx)=unpack("c",$xx) made
if($vxx)
true as long as the bit being masked was less than 8 (ie in the first
byte, which make sense...)
What I finally got to work was testing
if(($rin & $tin) eq $tin)
It seems to work even when vec($tin,$x,1)=1 for $x>8, so it isn't
bothered by intervening nulls. However, this behavior isn't hinted at
in the manual page (it should probably be mentioned in the select
example.)
_Mark_ <eichin@apollo.hp.com>
<eichin@athena.mit.edu>
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (10/27/90)
In article <1990Oct26.182652.13422@uvaarpa.Virginia.EDU> eichin@apollo.com writes:
: I'm using select to wait for a collection of file descriptors. I build
: masks $rin and $win:
: @fdnames=(F1,F2,F3,F4,F5,F6,F7,F8,F9,F10);
: foreach(@fdnames) {
: $tin = ''; vec($tin,fileno($_),1) = 1;
: if($mode{$_} eq "writewait") { $win = $win | $tin; }
: if($mode{$_} eq "readwait") { $rin = $rin | $tin; }
: }
: $nfound = select($rin,$win,undef,undef);
If I were doing this, I'd probably maintain my $rin and $win over
multiple calls, and just vec in and out the proper bits only when necessary.
: The question: how do I check which bits are set (ie which filehandles
: are available for read or write)? I have a similar loop, which does
: ($win & $tin) and checks it, but what is the right way to check?
: ($win & $tin) is always true. In fact, I tried a few tests (setting
: $xx=$foo & $bar), and found the following were *always* true:
: if($xx)
Since $xx is a string and not a number, this is equivalent to $xx ne "".
(Unless $xx is 1 byte long, and bits 32 and 16 are set, making "0"...)
: if($xx == 0)
This would have the unfortunate effect of turning $xx numeric. It's only
true occasionally, depending on the bit patterns--you'd have to have at
least 3 bits set to get a digit between 1 and 9.
: if($xx eq "")
I suspect that one was always false.
: if(defined($xx))
:
: throwing in a ($vxx)=unpack("c",$xx) made
: if($vxx)
: true as long as the bit being masked was less than 8 (ie in the first
: byte, which make sense...)
It should be true even if the bit is 8 or above--the null string is supposed
to be true. If it's not, it's a bug. When I say
$foo = "\0\1";
if ($foo) {print "True";}
it prints True.
: What I finally got to work was testing
: if(($rin & $tin) eq $tin)
That's reasonable, but why not just
if (vec($rin,fileno($_),1))
: It seems to work even when vec($tin,$x,1)=1 for $x>8, so it isn't
: bothered by intervening nulls. However, this behavior isn't hinted at
: in the manual page (it should probably be mentioned in the select
: example.)
Well, it's hinted at under vec(), but I'll agree it could be clearer.
A vec bitstring is just a string that has arbitrary bits set in it, the
first 8 bits in the first byte, the second 8 bits in the second byte,
and so on. So a bitstring of n 0 bits is going to consist of roughly n/8
null bytes. Thus, if you have lots of bits to scan, you can search for
the first non-zero bit like this:
$rin =~ /[^\0]/ && $minbit = length($`) * 8;
$minbit++ until vec($rin,$minbit,1);
Most applications won't have enough zero bits to worry about that, tho.
Larry