[comp.lang.perl] "comparing bitmasks"

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