Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!mcgill-vision!bloom-beacon!snorkelwacker!usc!henry.jpl.nasa.gov!elroy.jpl.nasa.gov!jpl-devvax!lwall From: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Newsgroups: comp.lang.perl Subject: Re: do_select() bug Message-ID: <6631@jpl-devvax.JPL.NASA.GOV> Date: 19 Dec 89 07:04:01 GMT References: <1989Dec16.044106.7924@fxgrp.fx.com> Reply-To: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Organization: Jet Propulsion Laboratory, Pasadena, CA Lines: 113 In article <1989Dec16.044106.7924@fxgrp.fx.com> grady@fxgrp.fx.com (Steven Grady) writes: : do_select(), the function that implements UNIX select(), does not work : properly. There are two problems. First, it uses the length of the : vector (represented as a string internally) as the width of the bit : field passed to select(). Unfortunately, it is including the '\0' : terminator of the string as part of the length. With the width off by : 8, the file descriptors examined are 8 higher than they should be. This is slightly misleading. The problem is that it was basing the length of the vector on the allocated length of the string rather than the current length of the string. There's nothing to prevent the allocated length from being any old number greater than the current length. The correct patch for this is not to subtract 8 bits from the length, but to base the length on str_cur rather than str_len. : Second and more important, it does not work on suns. It does not use : the FD_* macros. The representation it uses for the file descriptor : bits, namely, a simple string, does not work at all (because the width : on a sun must be a multiple of 32 bits). Yes, it's basically a byte reordering problem. : Here is a patch to fix do_select(). It is not very pretty, but it gets : the job done. There is no compile flag to enable it, since it is not a : complete patch anyway. This version will work on suns, but it won't : work, for instance, on AIX (which uses "sellist" structures). I've got a do_select for patch 7 that should work everwhere that uses bitmaps composed of ints or longs. Even places that don't have FD_SET(), etc. (if there are any such). Someone will have to tell me about "sellist" structures, though. Patch 7 should be out later this week. : The : "correct" way to do things would be to avoid explicitly using perl : vecs. I'd like to see a different interface to select() anyway. : Perhaps something like: : : (@readready, @writeready, @exceptready, $timeleft) = : select(@readhandles, @writehandles, @excepthandles, $timeout); : : where each of the arrays would be an array of expressions evaluating to : file handles. The vec interface is pretty bogus (and doesn't work, : under the current implementation). I respectfully disagree. The proposed interface would be very difficult to make efficient. Several net.people will attest that I thought long and hard about the interface to select (pun not intended). I considered and rejected quite a few interfaces. On top of which, your arguments are inconsistent with the way LISTs work. And the assignment to multiple arrays would cause all the array values to be assigned to the first array, or I'd have to special case assignments that come from select, yech. And I also disagree that vec() interface is "pretty bogus". I basically get to still two kurds with one bone: first, I get a representation of an fd set that is easy to pass to the system call select() without much processing; second, I get a general facility for doing bitmaps, which I want for other reasons (like article sets in a newsreader :-). If you want to do it the "correct" but slow way, here's a subroutine that has approximately the interface you desire. It differs in that the ready filehandles are returned in the associative array of the same name. ;# Usage: ;# @readmap = ('STDIN','FOO','BAR'); ;# @writemap = ('STDOUT','STDERR'); ;# @exceptmap = (@readmap,@writemap); ;# ;# $nfound = &select(*readmap,*writemap,*exceptmap,$timeout); ;# or ;# ($nfound,$timeleft) = &select(*readmap,*writemap,*exceptmap,$timeout); ;# ;# if ($nfound) { ;# if ($readmap{'stdin'}) { sub select { local(*r,*w,*e,$timeout) = @_; local($nfound,$rmap,$wmap,$emap); foreach $handle (@r) { vec($rmap,fileno($handle),1) = 1; } foreach $handle (@w) { vec($wmap,fileno($handle),1) = 1; } foreach $handle (@e) { vec($emap,fileno($handle),1) = 1; } ($nfound,$timeout) = select($rmap,$wmap,$emap,$timeout); %r = (); %w = (); %e = (); foreach $handle (@r) { $r{$handle} = 1 if vec($rmap,fileno($handle),1); } foreach $handle (@w) { $w{$handle} = 1 if vec($wmap,fileno($handle),1); } foreach $handle (@e) { $e{$handle} = 1 if vec($emap,fileno($handle),1); } if (wantarray) { return $nfound,$timeout; } else { return $nfound; } } Or some such. I haven't tested it. By the by, I don't know of any systems that DO implement $timeleft yet. Larry