Mailing List Archive

Re: After doing a select check question.
The following message is a courtesy copy of an article
that has been posted as well.

>>>>> "Christopher" == Christopher J Farrell <farrllcj@cig.mot.com> writes:

Christopher> I was just wondering about this one.
Christopher> If a person does a select on multiple file handles and gets a results back
Christopher> saying 'yes someone is ready', is there an easy way to find out who of those
Christopher> handles are ready? Or is the only way to then do individual selects on each
Christopher> filehandle?

Christopher> I was trying to decode the $rout info but fileno() just kept coming back null.

Look at the code in chat2.pl (in the library) for &chat'select.

Briefly, I presume you understand that you *set* the bits of $rout
corresponding to the fd-numbers of the filehandles you are interested
in. When select returns, it will *clear* any bits of $rout that
aren't ready yet. What I did in &chat'select was build an assoc array
of filehandle => fd mapping, and use the mapping again to reexamine
the bits.

Also, remember that unless you use sysread() exclusively on those
filehandles, you will never get reliable select()'s, because the STDIO
buffering will get in the way.

This is why there are filehandles and there are "chathandles". I wish
it could have been better integrated, as it is in TCL/expect. <sigh>

[.note to Larry Wall and p5p: why can't 4-arg select fake up a probe
into stdio's buffers and diddle $rout appropriately? Then we could
eliminate chathandles! It would also solve a number of other paradigm
problems about read/sysread/select.]

print "Just another Perl hacker," # but not what the media calls "hacker!" :-)
# legal fund: $6493.99 collected, $112379.50 spent; email fund@stonehenge.com for details
Re: After doing a select check question. [ In reply to ]
> This is why there are filehandles and there are "chathandles". I wish
> it could have been better integrated, as it is in TCL/expect. <sigh>

Yes.

> [.note to Larry Wall and p5p: why can't 4-arg select fake up a probe
> into stdio's buffers and diddle $rout appropriately? Then we could
> eliminate chathandles! It would also solve a number of other paradigm
> problems about read/sysread/select.]

I agree again. We have an application which does a lot of work in parallel by
opening sockets to daemons running all over our network. I want to read back
a line at a time as the daemons send in their results.

I'd love to be able to select on the filehandle then jump straight into an
appropriate <$FH>. Instead I have to use sysread, do my own line buffering,
and call my own routine to get a line at a time from the buffer. Its done
now, but I wish I hadnt had to.
Re: After doing a select check question. [ In reply to ]
: > This is why there are filehandles and there are "chathandles". I wish
: > it could have been better integrated, as it is in TCL/expect. <sigh>
:
: Yes.
:
: > [.note to Larry Wall and p5p: why can't 4-arg select fake up a probe
: > into stdio's buffers and diddle $rout appropriately? Then we could
: > eliminate chathandles! It would also solve a number of other paradigm
: > problems about read/sysread/select.]
:
: I agree again.

Yes, but you guys don't agree enough to send in a patch for it. :-)

On a practical note, we've been putting off doing this until we switch
to sfio, which when compared to stdio has Known Characteristics. But
nobody's sent in a patch for that yet either...

Larry
Re: After doing a select check question. [ In reply to ]
> From: Peter Whaite <peta@athena.mcrcim.mcgill.edu>
>
> > This is why there are filehandles and there are "chathandles". I wish
> > it could have been better integrated, as it is in TCL/expect. <sigh>
>
> Yes.
>
> > [.note to Larry Wall and p5p: why can't 4-arg select fake up a probe
> > into stdio's buffers and diddle $rout appropriately? Then we could
> > eliminate chathandles! It would also solve a number of other paradigm
> > problems about read/sysread/select.]
>
> I agree again. We have an application which does a lot of work in parallel by
> opening sockets to daemons running all over our network. I want to read back
> a line at a time as the daemons send in their results.
>
> I'd love to be able to select on the filehandle then jump straight into an
> appropriate <$FH>. Instead I have to use sysread, do my own line buffering,
> and call my own routine to get a line at a time from the buffer. Its done
> now, but I wish I hadnt had to.
>
The trouble with 4-arg select is not just that it doesn't consider
stdio but that it's to expensive to setup and check the bit vectors.

Umm,

$fh1 = new FileHandle ...;
$fh2 = new FileHandle ...;

$handles = new FileHandle::Set $fh1, $fh2;

@readable = $handles->readable($timeout);
@writeable = $handles->writeable($timeout);
...

@handles = $handles->poll($timeout, POLLIN | POLLHUP);

Anyone fancy implementing FileHandle::Set or something similar? Let me
know. Could be perl code using select for now and be recoded to XS
using select or poll later.

The key point about the interface described above is that you
have one object representing a set of file handles. That one
object can cache the select bit vector or pollfd struct and
so make polling much more efficient.

Tim.
Re: After doing a select check question. [ In reply to ]
On Fri, 6 Oct 1995, Peter Whaite wrote:

>
> > This is why there are filehandles and there are "chathandles". I wish
> > it could have been better integrated, as it is in TCL/expect. <sigh>
>
> Yes.
>
> > [.note to Larry Wall and p5p: why can't 4-arg select fake up a probe
> > into stdio's buffers and diddle $rout appropriately? Then we could
> > eliminate chathandles! It would also solve a number of other paradigm
> > problems about read/sysread/select.]
>
> I agree again. We have an application which does a lot of work in parallel by
> opening sockets to daemons running all over our network. I want to read back
> a line at a time as the daemons send in their results.
>
> I'd love to be able to select on the filehandle then jump straight into an
> appropriate <$FH>. Instead I have to use sysread, do my own line buffering,
> and call my own routine to get a line at a time from the buffer. Its done
> now, but I wish I hadnt had to.

Term::ReadKey contains this exact code (diddling with stdio, I mean).
Here's an extract:


/* Make use of a recent addition to Configure, if possible */
#ifdef USE_STDIO_PTR
# define FCOUNT(f) FILE_cnt(f)
#else

/* This bit borrowed from pp_sys.c. Complain to Larry if it's broken. */

# if defined(USE_STD_STDIO) || defined(atarist) /* this will work with
atariST */
# define FBASE(f) ((f)->_base)
# define FSIZE(f) ((f)->_cnt + ((f)->_ptr - (f)->_base))
# define FPTR(f) ((f)->_ptr)
# define FCOUNT(f) ((f)->_cnt)
# else
# if defined(USE_LINUX_STDIO)
# define FBASE(f) ((f)->_IO_read_base)
# define FSIZE(f) ((f)->_IO_read_end - FBASE(f))
# define FPTR(f) ((f)->_IO_read_ptr)
# define FCOUNT(f) ((f)->_IO_read_end - FPTR(f))
# endif
# endif
#endif

/* This is for the best, I'm afraid. */
#if !defined(FCOUNT)
# ifdef Have_select
# undef Have_select
# endif
# ifdef Have_poll
# undef Have_poll
# endif
#endif

#ifdef Have_select
int selectfile(file,delay)
FILE * file;
double delay;
{
struct timeval t;
int handle=fileno(file);

/*char buf[32];
Select_fd_set_t fd=(Select_fd_set_t)&buf[0];*/

fd_set fd;
# ifdef FCOUNT
if( FCOUNT(file)>0 )
return 1;
# endif

/*t.tv_sec=t.tv_usec=0;*/

if (delay < 0.0)
delay = 0.0;
t.tv_sec = (long)delay;
delay -= (double)t.tv_sec;
t.tv_usec = (long)(delay * 1000000.0);

FD_ZERO(&fd);
FD_SET(handle,&fd);
if(select(handle+1,(Select_fd_set_t)&fd,
(Select_fd_set_t)0,
(Select_fd_set_t)&fd, &t)) return -1;
else return 0;
}

#else
int selectfile(file, delay)
FILE * file;
double delay;
{
croak("select is not supported on this architecture");
return 0;
}
#endif



--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
It doesn't seem good to disallow select just because we don't know how
to cheat on the stdio buffer. Making select behave one way on some
machines and a different way on other machines is also problematical.

Larry
Re: After doing a select check question. [ In reply to ]
On Fri, 6 Oct 1995, Larry Wall wrote:

> It doesn't seem good to disallow select just because we don't know how
> to cheat on the stdio buffer. Making select behave one way on some
> machines and a different way on other machines is also problematical.

Yes, I'll agree, this is very important. But on the other hand, allowing
select() to understand STDIO would be a major improvement.

Considering the fact that select() currently only uses file numbers, and
thus couldn't deal with STDIO at all, perhaps the solution is a second
select() style function call that takes arguments something like this:

($handle,$readwriteorerror) = waitfiles( [STDIN, CONTROLFIFO], [STDOUT,
CONTROLFIFO], [], $delay);

On systems which can't cope with this, it'll die() like any unsupported
function. sfio would of course let it be used anywhere.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
Ken said:

> Considering the fact that select() currently only uses file numbers, and
> thus couldn't deal with STDIO at all, perhaps the solution is a second
> select() style function call that takes arguments something like this:
>
> ($handle,$readwriteorerror)
> = waitfiles([STDIN, CONTROLFIFO],[STDOUT,CONTROLFIFO],[],$delay);
>
> On systems which can't cope with this, it'll die() like any unsupported
> function. sfio would of course let it be used anywhere.

That would be good though I'd prefer the name selectfile. I always thought
`select' should have been called `sysselect' but I guess there were good
reasons why not, and its too late now. It seems a SelectFile module using
Ken's ReadKey selectfile code be a good way to start?

My main complaint about select is that the perlfunc(1) suggests it does work
on filehandles.

select RBITS,WBITS,EBITS,TIMEOUT
This calls the select system(2) call with the
bitmasks specified, which can be constructed using
fileno() and vec(), along these lines:
.......
If you want to select on many filehandles you might
^^^^^^^^^^^^^^^^^^^^^^^^^^
wish to write a subroutine:...

When I first read this I assumed that yes of course it uses select(2), but yes
there's extra stuff so it does work with filehandles. My code even worked as
expected, till I had lots of sockets open and then it just hung. Eventually
the penny dropped but after more time than I'd care to admit. Maybe there
should be a warning something along the lines of...

Be careful though. Select only monitors the system file descriptors.
It cannot tell you if there is data pending in the filehandle buffers.
Re: After doing a select check question. [ In reply to ]
On Fri, 6 Oct 1995, Peter Whaite wrote:

> That would be good though I'd prefer the name selectfile. I always thought
> `select' should have been called `sysselect' but I guess there were good
> reasons why not, and its too late now. It seems a SelectFile module using
> Ken's ReadKey selectfile code be a good way to start?

The idea of renaming select() to sysselect(), and giving select() STDIO
semantics is very attractive. I'm tempted to suggest that a program that
includes C<use x;>, where "x" is >= 5.002 should get select renamed.

However, a module that replaces CORE::select shouldn't be a problem.
C<use goodselect;> should do for now.

So does the syntax:

selectfile([READHANDLES,...], [WRITEHANDLES,...], [ERRORHANDLES,...],
timeout);

seem acceptable? Next we need to return arguments. There are several
possibilities.

First, some preparation:

@in = (READHANDLE,STDIN);
@out = (WRITEHANDLE,STDOUT);
@err = (ERRHANDLE,STDIN,STDOUT);

$in = \@in;
$out = \@out;
$err = \@err;

1. Modify passed lists. This would remove all entries from the list
except those that matched, and will return the number that matched.

($matched,$timeout) = selectfiles($in,$out,$err,$timeout);

2. Modify arrays passed by-name. This requires prototype support, but
looks identical to select().

($matched,$timeout) = selectfiles(@in,@out,@err,$timeout);

3. Return match triad:

@matched = selectfiles($in,$out,$err,$timeout);

where @matched might contain:

([STDIN],[],[],0);

In other words, the output is an array containing three nested lists,
and the timeout value. The three lists are handles that matched read,
write, and error, respectively.


Personally, I dislike select()'s rewriting style, and I like #3 the best.
Comments?

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
On Fri, 6 Oct 1995, Tim Bunce wrote:

> Umm,
>
> $fh1 = new FileHandle ...;
> $fh2 = new FileHandle ...;
>
> $handles = new FileHandle::Set $fh1, $fh2;
>
> @readable = $handles->readable($timeout);
> @writeable = $handles->writeable($timeout);
> ...
>
> @handles = $handles->poll($timeout, POLLIN | POLLHUP);

I'm not sure I like this, because it loses select() capability of
mathing on read, write, _or_ error.

Unless we make a select() clone that understands Set's... but then how do
tell what handles got selected, and what for? By modifying the incoming
Sets? Or by returning three Sets?

> The key point about the interface described above is that you
> have one object representing a set of file handles. That one
> object can cache the select bit vector or pollfd struct and
> so make polling much more efficient.

Yes-ish. Currently the file numbers are cached in a string, and that's
very efficient. (It has to be copied over each time, and is a bear to
create, but that's separate.)

> Tim.

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
On Fri, 6 Oct 1995, Tim Bunce wrote:

> $fh1 = new FileHandle ...;
> $fh2 = new FileHandle ...;
>
> $handles = new FileHandle::Set $fh1, $fh2;
>
> @readable = $handles->readable($timeout);
> @writeable = $handles->writeable($timeout);
> ...
>
> @handles = $handles->poll($timeout, POLLIN | POLLHUP);

To amend what I said in the last message, if you are using more then one
FileHandle::Set in a single call, (like the triad that select() gets)
then you need some really groovy caching to be able to invalidate the
cached pollfd or fdset whenever any of the three change, keeping in mind
that all of the three may be used with other triad sets. And I still
can't see any nice way of doing output.

I've just started playing with a selectfile() (it being a straightforward
hack of Term::ReadKey) and see that caching and Sets _would_ be a major
improvement. I'm thinking of something like this:

$fh1 = new FileHandle ...;
$fh2 = new FileHandle ...;

$readhandles = new FileHandle::Set $fh1, $fh2;
$writehandles = new FileHandle::Set $fh1;

$waiter = new FileHandler::Waiter $readhandles, $writehandles;

@results = $waiter->wait($timeout);


Now, should $results[0] be a new FileHandle::Set containing any
filehandles that matched for reading? This makes some sense, but also
implies that FileHandle::Set should inherit from a generic Set, and
should allow $handles->contains(STDIN), remove(), add(), and all the
other Set operations you can think of.

In C++, this would be a straightforward application of inheritance. Do you
think Perl is up to this, efficiency-wise? I mean, if the amount of
processing needed to do C<if( $results[0]->contains(STDOUT) ) { ... }>
outweighs the gains in using FileHandle::Set's, what's the point?

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
Excerpts from the mail message of Kenneth Albanowski:
) So does the syntax:
)
) selectfile([READHANDLES,...], [WRITEHANDLES,...], [ERRORHANDLES,...],
) timeout);
)
) seem acceptable?

No. You could allow any number of lists, each with any combo of
read/write/error and any number of file handles:

select( $timeout, ["R",\*STDIN], ["WE",\*STDOUT,\*STDERR], [...] );

But return

("TIMEOUT"=>$remain,STDIN=>"R",STDOUT=>"W",STDERR=>"WE")

Well, for consistancy, use this same format when calling select().
You could make a blessed hash that holds this information so that
the bit vectors could be cached as suggested elsewhere. Then you
could have these methods:

$sel= File::Select->new_list(["R",STDIN],["WE",STDOUT,STDERR]);
$sel= File::Select->new(STDIN=>"R",STDOUT=>"W",STDERR=>"WE");
$sel->watch(STDIN=>"E");
$sel->ignore(STDERR=>"W");

($timeout,$timeout,@ready)= $sel->select;
while( @ready ) {
($handle,$ops)= splice(@ready,0,2);
...
}
or
@handle=(\*STDIN,\*STDOUT,\*STDERR); @handle{@handle}= @handle;
%ready= $sel->select;
$rec= <STDIN> if $ready{\*STDIN} =~ /R/;
foreach ( keys(%ready) ) {
print {$handle{$_}} $data if $ready{$_} =~ /W/;
}

But caching the input bit vectors doesn't prevent you from having
to translate the output bit vectors to file handles, which may
be more expensive anyway. Or maybe not.
--
Tye McQueen tye@metronet.com || tye@doober.usu.edu
Nothing is obvious unless you are overlooking something
http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
Re: After doing a select check question. [ In reply to ]
On Sat, 7 Oct 1995, Tye McQueen wrote:

> No. You could allow any number of lists, each with any combo of
> read/write/error and any number of file handles:
>
> select( $timeout, ["R",\*STDIN], ["WE",\*STDOUT,\*STDERR], [...] );
>
> But return
>
> ("TIMEOUT"=>$remain,STDIN=>"R",STDOUT=>"W",STDERR=>"WE")

Real nice, just one flaw. Hash keys are strings. So this implies a
string-to-glob conversion each time they are used, which can get mildly
expensive if you have to add package defaults.

But please tell me I'm wrong. I came up with this style too, and liked it,
but rejected it for this reason.

> Well, for consistancy, use this same format when calling select().
> You could make a blessed hash that holds this information so that
> the bit vectors could be cached as suggested elsewhere. Then you
> could have these methods:
>
> $sel= File::Select->new_list(["R",STDIN],["WE",STDOUT,STDERR]);

This is directly feasible. For now, this seems a good compromise. And
since we don't have separate Sets, this gets rid of the caching problems.

> $sel= File::Select->new(STDIN=>"R",STDOUT=>"W",STDERR=>"WE");
> $sel->watch(STDIN=>"E");
> $sel->ignore(STDERR=>"W");
>
> ($timeout,$timeout,@ready)= $sel->select;
> while( @ready ) {
> ($handle,$ops)= splice(@ready,0,2);
> ...
> }

Mildly expensive to build the list, but only a single list... Yes, this
seems decent too.

> or
> @handle=(\*STDIN,\*STDOUT,\*STDERR); @handle{@handle}= @handle;
> %ready= $sel->select;
> $rec= <STDIN> if $ready{\*STDIN} =~ /R/;
> foreach ( keys(%ready) ) {
> print {$handle{$_}} $data if $ready{$_} =~ /W/;
> }

Same problem with hash keys. Possibly feasible, but it seems a little
ugly.

> But caching the input bit vectors doesn't prevent you from having
> to translate the output bit vectors to file handles, which may
> be more expensive anyway. Or maybe not.

And the cache will have to be copied each time, and then you do need to
backtranslate... well, we'll see.

> --
> Tye McQueen tye@metronet.com || tye@doober.usu.edu
> Nothing is obvious unless you are overlooking something
> http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
Excerpts from the mail message of Kenneth Albanowski:
)
) On Sat, 7 Oct 1995, Tye McQueen wrote:
) > ("TIMEOUT"=>$remain,STDIN=>"R",STDOUT=>"W",STDERR=>"WE")
)
) Real nice, just one flaw. Hash keys are strings.

Who said that was a hash? ;> It's a list value made to look
like a hash and that you can put into a hash provided you take
the proper steps beforehand...

) > @handle=(\*STDIN,\*STDOUT,\*STDERR); @handle{@handle}= @handle;
) > %ready= $sel->select;
) > $rec= <STDIN> if $ready{\*STDIN} =~ /R/;
) > foreach ( keys(%ready) ) {
) > print {$handle{$_}} $data if $ready{$_} =~ /W/;
) > }
)
) Same problem with hash keys. Possibly feasible, but it seems a little
) ugly.

That was thrown in to show how you can use it as a hash if you
want to. Making hash keys SVs would of course clean this up
(not that I'm saying this should happen).

There is also the option to create a tied hash that is implemented
as two internal hashes, both with the same keys:

$tied{$key}= $val;
does
$r= ref($key) ? '\\': '"';
$key{"$r$key"}= $key;
$value{"$r$key"}= $value;

which gives you the same thing as a hash with SVs as keys. Then
you could inherit from the fine "sorted hash" class and have "the
perfect hash"!
--
Tye McQueen tye@metronet.com || tye@doober.usu.edu
Nothing is obvious unless you are overlooking something
http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
Re: After doing a select check question. [ In reply to ]
On Sat, 7 Oct 1995, Tye McQueen wrote:

> Excerpts from the mail message of Kenneth Albanowski:
> )
> ) On Sat, 7 Oct 1995, Tye McQueen wrote:
> ) > ("TIMEOUT"=>$remain,STDIN=>"R",STDOUT=>"W",STDERR=>"WE")
> )
> ) Real nice, just one flaw. Hash keys are strings.
>
> Who said that was a hash? ;> It's a list value made to look
> like a hash and that you can put into a hash provided you take
> the proper steps beforehand...

Heh. OK, I see what you mean. But it's so close to a hash that it might
tend to be, um, hashed, by accident.

> ) > @handle=(\*STDIN,\*STDOUT,\*STDERR); @handle{@handle}= @handle;
> ) > %ready= $sel->select;
> ) > $rec= <STDIN> if $ready{\*STDIN} =~ /R/;
> ) > foreach ( keys(%ready) ) {
> ) > print {$handle{$_}} $data if $ready{$_} =~ /W/;
> ) > }
> )
> ) Same problem with hash keys. Possibly feasible, but it seems a little
> ) ugly.
>
> That was thrown in to show how you can use it as a hash if you
> want to. Making hash keys SVs would of course clean this up
> (not that I'm saying this should happen).

Good reasons why it shouldn't, in fact. But yes, if you use references all
over the place, and keep a shadow hash, things are cool. Still a lot of
work, though.

> There is also the option to create a tied hash that is implemented
> as two internal hashes, both with the same keys:
>
> $tied{$key}= $val;
> does
> $r= ref($key) ? '\\': '"';
> $key{"$r$key"}= $key;
> $value{"$r$key"}= $value;
>
> which gives you the same thing as a hash with SVs as keys. Then
> you could inherit from the fine "sorted hash" class and have "the
> perfect hash"!

Yes, but now to do go from a fileno to a filehandle, we need to go
through one hash to get the stringized filehandle, and then the second
hash to retrive the actual handle. And you have to be careful about
stringizing your handles from different packages so they don't collide.

Definitely feasible, but is it worth the bother? I'll admit though that
returning a hash of the matched handles looks easier to use then some
other styles.

> --
> Tye McQueen tye@metronet.com || tye@doober.usu.edu
> Nothing is obvious unless you are overlooking something
> http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
Ken said:

> Definitely feasible, but is it worth the bother? I'll admit though that
> returning a hash of the matched handles looks easier to use then some
> other styles.

Returning a hash of matched handles looks really good to me -- makes for very
simple dispatching code when handling multiple socket connections...

while ($daemons->running)
{
%ready = $daemons->select;
while (($connection,$events) = each %ready)
{
$done = $connection->doevent($events);
$daemons->ignore{$connection} if $done;
}
}

I'm not concerned about efficiency though. Handling is my big overhead.

Definitely worth the bother from my perspective.
Re: After doing a select check question. [ In reply to ]
On Sat, 7 Oct 1995, Peter Whaite wrote:

> Returning a hash of matched handles looks really good to me -- makes for very
> simple dispatching code when handling multiple socket connections...
>
> while ($daemons->running)
> {
> %ready = $daemons->select;
> while (($connection,$events) = each %ready)
> {
> $done = $connection->doevent($events);
> $daemons->ignore{$connection} if $done;
> }
> }
>
> I'm not concerned about efficiency though. Handling is my big overhead.
>
> Definitely worth the bother from my perspective.

Yes, I agree this looks nice. But we still have the problem that hash
keys only hold strings, so $connection isn't even a FileHandle at this
point. This can be worked around in moderately ugly ways, like this:

$done = ($deamons->handle($connection))->doevent($events);

if that is even legal code, which I'm not sure about. It certainly isn't
elegant.

Changing to an array gives similar semantics without the pain:

while ($daemons->running)
{
@ready = $daemons->select;
shift @ready; #skip timeout
while (@ready)
{
$connection = shift @ready;
$events = shift @ready;
$done = $connection->doevent($events);
$daemons->ignore{$connection} if $done;
}
}

Hmm. A wishlist entry here: let shift take a second argument, so that
this could be rewritten:

while( ($connection,$events) = shift @ready,2) ...


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
Excerpts from the mail message of Peter Whaite:
) Returning a hash of matched handles looks really good to me -- makes for very
) simple dispatching code when handling multiple socket connections...
)
) while ($daemons->running)
) {
) %ready = $daemons->select;
) while (($connection,$events) = each %ready)
) {
) $done = $connection->doevent($events);
) $daemons->ignore{$connection} if $done;
) }
) }

Note that this code won't work because, as Ken pointed out,
$connection will no longer be a reference, but a stringification
of a reference so "$connection->" won't know what to do. However,
like the example code I included before, this avoids the problem:

while ($daemons->running)
{
($timeout,$timeout,@ready) = $daemons->select;
while (($connection,$events) = splice(@ready,0,2))
{
$done = $connection->doevent($events);
$daemons->ignore{$connection} if $done;
}
}

The first "$timeout," is just there to eat the first key which is
just a placeholder for the amount of timeout remaining which is
caught by the second "$timeout,". (It'd probably be easy to make
this processing optional if you don't care about the amount of
timeout remaining.)

I guess this adds strength to Ken's argument that returning an
array that looks like a hash can lead to people using it as a
hash without the required extra precautions involved.

I think this could be solved by having "use File::Select" create
a tied hash for passing into and returning out of selectfile().
I think this certainly makes a simple and versatile interface,
but it may indeed be of limited practical value if the overheads
are much too great (and I have no real idea what the overheads
would be).
--
Tye McQueen tye@metronet.com || tye@doober.usu.edu
Nothing is obvious unless you are overlooking something
http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
Re: After doing a select check question. [ In reply to ]
On Sat, 7 Oct 1995, Tye McQueen wrote:

> I guess this adds strength to Ken's argument that returning an
> array that looks like a hash can lead to people using it as a
> hash without the required extra precautions involved.

Yes. This makes me feel that returning an array consisting of the timeout,
and then the filehandle and op for each event would be best. This is
_without_ a "timeout" at the beginning, so it is an invalid hash. I think
this would be for the best.

> I think this could be solved by having "use File::Select" create
> a tied hash for passing into and returning out of selectfile().
> I think this certainly makes a simple and versatile interface,
> but it may indeed be of limited practical value if the overheads
> are much too great (and I have no real idea what the overheads
> would be).

Most importantly, I think, is that it is a lot of work for gain only if
you are watching multiple handles and need to know if a specific handle
has answered.

Hmm. Two thoughts here: first, it might make sense to let File::Select
have different levels of desire for particular handles. So it would use
select() to scan the most important ones first, then the next most
important, etc. Secondly, how does one compare file handles? Do you use
C<eq>, or should you use more complex incantations?

> --
> Tye McQueen tye@metronet.com || tye@doober.usu.edu
> Nothing is obvious unless you are overlooking something
> http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
I see this debate has been moving along. Commenting on my dispatch code Ken
said:

> Yes, I agree this looks nice. But we still have the problem that hash keys
> only hold strings, so $connection isn't even a FileHandle at this point.

Oh yes of course. One looses blessedness in hash keys.

> This can be worked around in moderately ugly ways, like this:
>
> $done = ($deamons->handle($connection))->doevent($events);
>
> if that is even legal code, which I'm not sure about. It certainly isn't
> elegant.

Its not that bad but there is loss of clarity. Originally I had the event
handlers in a hash keyed by the (stringified) filehandle. So the call would
have been something like...

$done = &{$doevent{$connection}}($events);

but it looked so nice the other way I couldnt help myself.

Both Ken and Tye have proposed alternatives in which select returns a flat
list with the implicit pairwise FILEn,EVENTn structure implemented in code.
That looks good but wouldnt it be better if the pair wise structure were
explicit:

(TIMEOUT, [FILE1,EVENTS1], [FILE2,EVENTS2],...)

Then...

($timeout,@ready) = $daemons->select;
foreach $hit ( @ready )
{
my($file,$events) = @$hit;
$done = $file->doevent($events);
$connection->ignore($file) if $done;
}

Later my misuse of the stringified filehandle prompts Tye and Ken to worry:
> Tye:
> I guess this adds strength to Ken's argument that returning an array that
> looks like a hash can lead to people using it as a hash without the required
> extra precautions involved.
>
>> Yes. This makes me feel that returning an array consisting of the timeout,
>> and then the filehandle and op for each event would be best. This is
>> _without_ a "timeout" at the beginning, so it is an invalid hash. I think
>> this would be for the best.

Wouldnt it still be easy to convert to hash with

($timeout,%ready) = $daemons->select

or am I missing another subtly here? In any case I dont think its a big deal.
It is perl, and its good to have the rope.

On a more general note regarding the use of tied hashes, Ken continues:

> Most importantly, I think, is that it is a lot of work for gain only if
> you are watching multiple handles and need to know if a specific handle
> has answered.

I agree, but it does highlight the need to first decide what kind of scenarios
select is going to be used in. I've put forward a general dispatching
mechanism that I certainly have use for, but it might help the design process
to consider a few others as well.

> Hmm. Two thoughts here: first, it might make sense to let File::Select have
> different levels of desire for particular handles. So it would use select()
> to scan the most important ones first, then the next most important,
> etc. Secondly, how does one compare file handles? Do you use C<eq>, or
> should you use more complex incantations?

This crossed my mind too. It could be handled by sorting the `@ready' files
before handling them. If efficiency is a concern, then maybe

$daemon->priority(FILE1,FILE2,...)

can be used to specify the order in which the select bit vectors are tested
and converted to @ready output. priority() could cache bit masks.

Maybe this is getting a little bottom heavy with unneeded functionality.
Pretty soon we'll be talking about priority scheduling. Might be better to
shove it upstairs into a File::PrioritySelect that @ISA File::Select.
Re: After doing a select check question. [ In reply to ]
On Sun, 8 Oct 1995, Peter Whaite wrote:

> > Yes, I agree this looks nice. But we still have the problem that hash keys
> > only hold strings, so $connection isn't even a FileHandle at this point.
>
> Oh yes of course. One looses blessedness in hash keys.

Not just blessedness. They are strings, so they can't even be references
or globs. It's possible to flatten filehandles into strings portable
between packages, but it's uglier and slower then I'd like.

> > This can be worked around in moderately ugly ways, like this:
> >
> > $done = ($deamons->handle($connection))->doevent($events);
> >
> > if that is even legal code, which I'm not sure about. It certainly isn't
> > elegant.
>
> Its not that bad but there is loss of clarity. Originally I had the event
> handlers in a hash keyed by the (stringified) filehandle. So the call would
> have been something like...
>
> $done = &{$doevent{$connection}}($events);
>
> but it looked so nice the other way I couldnt help myself.

Actually, this isn't bad. Well, I'm half-way used to that style by now.
But you still are basing things on stringified handles.

> Both Ken and Tye have proposed alternatives in which select returns a flat
> list with the implicit pairwise FILEn,EVENTn structure implemented in code.
> That looks good but wouldnt it be better if the pair wise structure were
> explicit:
>
> (TIMEOUT, [FILE1,EVENTS1], [FILE2,EVENTS2],...)

Yes, this is much cleaner to extract from. Only efficiency is in question.
This requires a new AV to be allocated for each returned handle, and then
deallocated on loop recycle. But there isn't any reason this can't be
done.

> Then...
>
> ($timeout,@ready) = $daemons->select;
> foreach $hit ( @ready )
> {
> my($file,$events) = @$hit;
> $done = $file->doevent($events);
> $connection->ignore($file) if $done;
> }
>
> Later my misuse of the stringified filehandle prompts Tye and Ken to worry:
> > Tye:
> > I guess this adds strength to Ken's argument that returning an array that
> > looks like a hash can lead to people using it as a hash without the required
> > extra precautions involved.
> >
> >> Yes. This makes me feel that returning an array consisting of the timeout,
> >> and then the filehandle and op for each event would be best. This is
> >> _without_ a "timeout" at the beginning, so it is an invalid hash. I think
> >> this would be for the best.
>
> Wouldnt it still be easy to convert to hash with
>
> ($timeout,%ready) = $daemons->select
>
> or am I missing another subtly here? In any case I dont think its a big deal.
> It is perl, and its good to have the rope.

Yes, it is still easy that way. I'm just worried about someone doing:

%ready = $deamons->select;

just because it looks like you can do it. The trouble is that the damage
done (stringizing filehandles) is practically invisible if you aren't
famiilar with whats going on. Rope, sure, but invisible rope?

> On a more general note regarding the use of tied hashes, Ken continues:
>
> > Most importantly, I think, is that it is a lot of work for gain only if
> > you are watching multiple handles and need to know if a specific handle
> > has answered.
>
> I agree, but it does highlight the need to first decide what kind of scenarios
> select is going to be used in. I've put forward a general dispatching
> mechanism that I certainly have use for, but it might help the design process
> to consider a few others as well.

Yes, here are some I've thought about:

1. Wait only for readable STDIN, with or without a timeout. This
one actually doesn't need to see the file handle at all.

2. Wait for one of a small, fixed set of handles to become
readable. This begs for an if-ifelse or case structure, and implies the
need to compare filehandles. (If $outhandle eq "STDIN", ...)

3. Wait for any number of any number of handles to become any
state. This is best handled with object orientation, or the aforemention
case structure. If all of the files are handled in exactly the same way, then
no specialization is needed.

Really, the worst problem I see is that seeing whether two filehandles
match is rather inefficient compare to select(). In select(), you just
test for a bit in the vector. (Heck, even in C it's just a pointer or
integer comparison.)

> > Hmm. Two thoughts here: first, it might make sense to let File::Select have
> > different levels of desire for particular handles. So it would use select()
> > to scan the most important ones first, then the next most important,
> > etc. Secondly, how does one compare file handles? Do you use C<eq>, or
> > should you use more complex incantations?
>
> This crossed my mind too. It could be handled by sorting the `@ready' files
> before handling them. If efficiency is a concern, then maybe
>
> $daemon->priority(FILE1,FILE2,...)
>
> can be used to specify the order in which the select bit vectors are tested
> and converted to @ready output. priority() could cache bit masks.

I'm thinking of something more general then this. Since any one call to
select() can only demonstrate a single priority level, you'd need someway
to say that "R1" files have higher priority then "R2" files, and they'd
be collected into a seperate select bit vector, and tested first.

This is for the future, however. It's an obvious extension, though.

> Maybe this is getting a little bottom heavy with unneeded functionality.
> Pretty soon we'll be talking about priority scheduling. Might be better to
> shove it upstairs into a File::PrioritySelect that @ISA File::Select.

That's the sort of thing that needs some thought once File::Select is done
and obviously useful.

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
On Sun, 8 Oct 1995, Kenneth Albanowski wrote:

> Really, the worst problem I see is that seeing whether two filehandles
> match is rather inefficient compare to select(). In select(), you just
> test for a bit in the vector. (Heck, even in C it's just a pointer or
> integer comparison.)

And here's a solution for now. File::Select will export this XSUB:

int
filecmp(one,two)
FILE * one
FILE * two
CODE:
{
RETVAL=(one==two);
}


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: After doing a select check question. [ In reply to ]
> From: Kenneth Albanowski <kjahds@kjahds.com>
>
> On Sun, 8 Oct 1995, Kenneth Albanowski wrote:
>
> > Really, the worst problem I see is that seeing whether two filehandles
> > match is rather inefficient compare to select(). In select(), you just
> > test for a bit in the vector. (Heck, even in C it's just a pointer or
> > integer comparison.)
>
> And here's a solution for now. File::Select will export this XSUB:
>
> int
> filecmp(one,two)
> FILE * one
> FILE * two
> CODE:
> {
> RETVAL=(one==two);
> }

I think that should be in FileHandle as a method (maybe with Overload'ing :)

A file handle compare function doesn't belong in File::Select IMHO.

Tim.

p.s. Hopefully I'l have time to read through all the messages this evening.
Re: After doing a select check question. [ In reply to ]
On Mon, 9 Oct 1995, Tim Bunce wrote:

> > int
> > filecmp(one,two)
> > FILE * one
> > FILE * two
> > CODE:
> > {
> > RETVAL=(one==two);
> > }
>
> I think that should be in FileHandle as a method (maybe with Overload'ing :)
>
> A file handle compare function doesn't belong in File::Select IMHO.

Excellent point. Especially since if FileHandle contains it, then you can
use it either as a method or a function. The only problem is lack of an
XSUB to tuck it into in the dist. (And no, I am _not_ going to stuff it
in POSIX.)

But I'll change File::Select over to export this from FileHandle.
C<fileeq(one,two)> will return non-zero if the filehandles are identical,
and C<filecmp(one,two)> will return an <=> style ordering.

> Tim.

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)