Обсуждение: Proper use of select() parameter nfds?

Поиск
Список
Период
Сортировка

Proper use of select() parameter nfds?

От
Matthew Hagerty
Дата:
Greetings,

I am going over the use of select() for a server I'm writing and I 
*thought* I understood the man page's description for the use of the first 
parameter, nfds.
From MAN:

The first nfds descriptors are checked in each set; i.e., the descriptors 
from 0 through nfds-1 in the descriptor sets are examined.


I take this to mean that each descriptor set contains n descriptors and I 
am interested in examining the first nfds descriptors referenced in my 
sets.  I also understood it to mean that nfds has absolutely nothing to do 
with the actual *value* of a descriptor, i.e. the value returned by 
fopen(), socket(), etc..  Is this correct thinking?  What got me 
second-guessing myself was a use of select() that seems to indicate that 
you have to make sure nfds is larger than the value of the largest 
descriptor you want checked.  Here is the select() from the questionable 
code (I can provide the whole function if necessary, it's not very big):

if (select(conn->sock + 1, &input_mask, &output_mask, &except_mask,    (struct timeval *) NULL) < 0)


Is this improper use?  conn->sock is set like this:

/* Open a socket */
if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)


Any clarification on how nfds should be set would be greatly appreciated.

Thanks,
Matthew



Re: Proper use of select() parameter nfds?

От
Tom Lane
Дата:
Matthew Hagerty <mhagerty@voyager.net> writes:
> I take this to mean that each descriptor set contains n descriptors

No.  nfds is the length (in bits) of the bit arrays passed to select().
Therefore, it is possible to inquire about descriptors numbered between
0 and nfds-1.  One sets the bits corresponding to the interesting
descriptors before calling select, and then examines those bits to see
if they're still set on return.

The code you quoted is perfectly correct, for code that is only
interested in one descriptor.
        regards, tom lane


Re: Proper use of select() parameter nfds?

От
Doug McNaught
Дата:
Matthew Hagerty <mhagerty@voyager.net> writes:

>  From MAN:
> 
> The first nfds descriptors are checked in each set; i.e., the
> descriptors from 0 through nfds-1 in the descriptor sets are
> examined.
> 
> 
> 
> I take this to mean that each descriptor set contains n descriptors and I am
> interested in examining the first nfds descriptors referenced in my sets.  I
> also understood it to mean that nfds has absolutely nothing to do with the
> actual *value* of a descriptor, i.e. the value returned by fopen(), socket(),
> etc..  Is this correct thinking? 

No.  Unix always gives you the lowest available descriptor value
(unless you ask for a value explicitly with dup2(), which is rare).
Since by default stdin/out/err are 0,1,2, you will get new descriptors
starting at 3.  You keep track of the highest descriptor value that
you're interested in, and pass that value +1 to select().

The reason for this is that FD_SETSIZE is often large (1024 by defaukt
in glibc) and you save the system some work by telling select() how
much of each set it needs to scan.

> if (select(conn->sock + 1, &input_mask, &output_mask, &except_mask,
>      (struct timeval *) NULL) < 0)
> 
> 
> Is this improper use?  conn->sock is set like this:

As long as conn->sock is the highest descriptor value you have (last
descriptor opened) this looks right.

You might want to get hold of _Unix Network Programming, Vol 1_ by
Stevens if you're going to do a lot of this stuff.

-Doug
-- 
The rain man gave me two cures; he said jump right in,
The first was Texas medicine--the second was just railroad gin,
And like a fool I mixed them, and it strangled up my mind,
Now people just get uglier, and I got no sense of time...          --Dylan


Re: Proper use of select() parameter nfds?

От
Alex Pilosov
Дата:
On Fri, 6 Jul 2001, Matthew Hagerty wrote:

> I take this to mean that each descriptor set contains n descriptors and I 
> am interested in examining the first nfds descriptors referenced in my 
> sets.  I also understood it to mean that nfds has absolutely nothing to do 
> with the actual *value* of a descriptor, i.e. the value returned by 
> fopen(), socket(), etc..  Is this correct thinking?  What got me 
> second-guessing myself was a use of select() that seems to indicate that 
> you have to make sure nfds is larger than the value of the largest 
Correct.
<snip>

> Any clarification on how nfds should be set would be greatly appreciated.

Just like you said:
"you have to make sure nfds is larger than the value of the largest
filedescriptor". 


Reason being: kernel has to know how large is the mask passed to it, and
how far does it need to look.

-alex





Re: Proper use of select() parameter nfds?

От
Matthew Hagerty
Дата:
Well, it proves that it was to late for me when I wrote this.  I apologize, 
this was supposed to go to FreeBSD hackers, not pgHackers.  It does kind of 
relate however, because the code snip-it is from the pgWait function in the 
fe-misc.c file of the pqlib interface.

I appreciate the response.  I had initially understood the correct behavior 
but the man page is a bit confusing.  I suppose digging into the kernel's 
select() would have resolved my suspicions as well, but it is more fun to 
talk to all of you! :)

What erks me about this call is that I have to know what file descriptors 
are and what the largest one I want to use is.  "Technically", for 
in/out/err your are supposed to use defines from a lib supplied with your 
OS, and for other files you make a var of type FILE and assign the return 
result from fopen() (or socket, etc.) to that.  I guess my point is that by 
having to pass a parameter like nfds, it completely removes all abstraction 
and forces me to know something about the kernel internals.  This is not a 
problem for me, but makes for possibly *very* un-portable code.  What if a 
file descriptor is a structure on anther OS?  I read somewhere once that 
the use of 0,1,2 for the in/out/err was something being frowned on since 
that could change one day, but select() is not helping things 
either.  Also, I know of no function that returns the highest file 
descriptor I have open for my process.

Thanks for the clarification.

Matthew



At 09:45 AM 7/6/2001 -0400, Alex Pilosov wrote:
>On Fri, 6 Jul 2001, Matthew Hagerty wrote:
>
> > I take this to mean that each descriptor set contains n descriptors and I
> > am interested in examining the first nfds descriptors referenced in my
> > sets.  I also understood it to mean that nfds has absolutely nothing to do
> > with the actual *value* of a descriptor, i.e. the value returned by
> > fopen(), socket(), etc..  Is this correct thinking?  What got me
> > second-guessing myself was a use of select() that seems to indicate that
> > you have to make sure nfds is larger than the value of the largest
>Correct.
><snip>
>
> > Any clarification on how nfds should be set would be greatly appreciated.
>
>Just like you said:
>"you have to make sure nfds is larger than the value of the largest
>filedescriptor".
>
>
>Reason being: kernel has to know how large is the mask passed to it, and
>how far does it need to look.
>
>-alex



Re: Proper use of select() parameter nfds?

От
Doug McNaught
Дата:
Matthew Hagerty <mhagerty@voyager.net> writes:

> What erks me about this call is that I have to know what file descriptors are
> and what the largest one I want to use is.  "Technically", for in/out/err your
> are supposed to use defines from a lib supplied with your OS, and for other
> files you make a var of type FILE and assign the return result from fopen()
> (or socket, etc.) to that.

You are confused.  fopen() returns a FILE *, while socket() returns a
descriptor.  

Don't use any stdio calls (fopen(), fprintf(), etc) with select() as
the stdio buffering can screw you up.  

>                            I guess my point is that by having to pass a
> parameter like nfds, it completely removes all abstraction and forces me to
> know something about the kernel internals.

File descriptors are not "kernel internals".  They are part of the
Unix/POSIX API and will not go away.  They're simply a but lower level 
thatn the stdio FILE * interface.

>                                   This is not a problem for me, but
> makes for possibly *very* un-portable code.  What if a file
> descriptor is a structure on anther OS?  I read somewhere once that
> the use of 0,1,2 for the in/out/err was something being frowned on
> since that could change one day, but select() is not helping things
> either.  

I consider it extremely unlikely that the 0,1,2 convention will ever
change, as it would break almost every Unix program out there.

>                Also, I know of no function that returns the highest file
> descriptor I have open for my process.

Yes, you have to keep track of it yourself.  It's a bit annoying.

-Doug
-- 
The rain man gave me two cures; he said jump right in,
The first was Texas medicine--the second was just railroad gin,
And like a fool I mixed them, and it strangled up my mind,
Now people just get uglier, and I got no sense of time...          --Dylan