open fd management

open fd management

Post by Bowen Simmo » Thu, 03 Apr 2003 04:30:19



I'm working on a process that might need to maintain a very large
number of sockets, possibly so many as to endanger the rest of the
system and leave it without enough file descriptors to run.

To avoid such a calamity, I've added a code to keep count of the total
number of sockets this process has open. I have some questions, though
regarding the lifetime of socket file descriptors.

(1) When a connection is in the backlog state on a listen socket, does
it have an file descriptor associated with it or does it only get the
file descriptor when I accept() the connection?

(2) When I close() a connection, is the fd released right away, or
does the fd only get released once the linger period is over?

As an additional question, what is a reasonable number of fd's to
leave available for system use? I'm not expecting the systems I'm
running on to have any other descriptor-hungry processes running, but
I'd sure like to leave enough for the os and ordinary applications.
I'm thinking 500 - does that sound reasonable?

As a final note, does a socket descriptor (as opposed to an ordinary
file descriptor) take up a vnode so that I should be worrying about
those as well?

 
 
 

open fd management

Post by M?ns Rullg? » Thu, 03 Apr 2003 05:45:00



> I'm working on a process that might need to maintain a very large
> number of sockets, possibly so many as to endanger the rest of the
> system and leave it without enough file descriptors to run.

> To avoid such a calamity, I've added a code to keep count of the total
> number of sockets this process has open. I have some questions, though
> regarding the lifetime of socket file descriptors.

Why don't you use setrlimit() to limit the number of file descriptor
the process can use?

--
M?ns Rullg?rd


 
 
 

open fd management

Post by Barry Margoli » Thu, 03 Apr 2003 05:58:47




>I'm working on a process that might need to maintain a very large
>number of sockets, possibly so many as to endanger the rest of the
>system and leave it without enough file descriptors to run.

File descriptors are a per-process resource.  The system-wide resource is
the file table.  Which is it you're trying to protect?

Quote:>To avoid such a calamity, I've added a code to keep count of the total
>number of sockets this process has open. I have some questions, though
>regarding the lifetime of socket file descriptors.

>(1) When a connection is in the backlog state on a listen socket, does
>it have an file descriptor associated with it or does it only get the
>file descriptor when I accept() the connection?

It doesn't have a file descriptor associated with it, but I think it's
still taking up a slot in the system-wide file table.  The information
about the connection has to be stored somewhere; it's in a socket structure
that I expect is entered into the file table.  When you call accept(), an
entry is added to your process's file descriptor table to point to the
socket's entry in the file table.

Quote:>(2) When I close() a connection, is the fd released right away, or
>does the fd only get released once the linger period is over?

The file descriptor is released in your process immediately.  The file
table entry won't be released until the socket gets out of FIN-WAIT or
TIME-WAIT state.

Quote:>As an additional question, what is a reasonable number of fd's to
>leave available for system use? I'm not expecting the systems I'm
>running on to have any other descriptor-hungry processes running, but
>I'd sure like to leave enough for the os and ordinary applications.
>I'm thinking 500 - does that sound reasonable?

It depends on how many other processes there are on the system.  Every
process uses at least 3, although often these point to the same file table
entry (stdout and stderr are often dup'ed from stdin).  There are also file
table entries for each process's current directory.

Quote:>As a final note, does a socket descriptor (as opposed to an ordinary
>file descriptor) take up a vnode so that I should be worrying about
>those as well?

I'm not sure.

--

Genuity Managed Services, a Level(3) Company, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

 
 
 

open fd management

Post by Kurtis D. Rade » Thu, 03 Apr 2003 13:28:47



> I'm working on a process that might need to maintain a very large number
> of sockets, possibly so many as to endanger the rest of the system and
> leave it without enough file descriptors to run.

That can't happen (ignoring really obscure corner cases such as exhausting
kernel virtual address space or physical memory). That's because file
descriptors are a per process resource. Ignoring the ability some UNIXes
provide for sharing a file descriptor table among several processes each
process normally has its own private file descriptor table. When it calls
fork() that table is cloned (modulo fork() variants such as the DYNIX/ptx
shfork() call that inhibits the fd table clone operation).

However, each file descriptor entry will point to a file table entry. And
file table entries are global, and in some (most?) UNIX implementations are
a finite resource. Note that a file table entry may be pointed at by
multiple file descriptors, possibly from different processes.

Quote:> To avoid such a calamity, I've added a code to keep count of the total
> number of sockets this process has open. I have some questions, though
> regarding the lifetime of socket file descriptors.

> (1) When a connection is in the backlog state on a listen socket, does it
> have an file descriptor associated with it or does it only get the file
> descriptor when I accept() the connection?

A file descriptor is allocated when accept() is called in the UNIX
implementations I'm familiar with. Given the semantics of the various UNIX
APIs I don't see how any other implementation is possible. Note that the
accept() can fail with errno == EMFILE if the per-process file descriptor
table is full or, equivalently, the RLIMIT_NOFILE threshold has been
reached (see setrlimit(2)).

Quote:> (2) When I close() a connection, is the fd released right away, or does
> the fd only get released once the linger period is over?

I don't know if any standard (e.g., SUS, POSIX, XPG4) specifies this. I do
know that three implementations for which I have source code code access
(two proprietary plus Linux) free the file descriptor immediately.

Quote:> As an additional question, what is a reasonable number of fd's to leave
> available for system use? I'm not expecting the systems I'm running on to
> have any other descriptor-hungry processes running, but I'd sure like to
> leave enough for the os and ordinary applications. I'm thinking 500 -
> does that sound reasonable?

Again, the question as posed doesn't make any sense. Assuming you meant
file table entries the answer is: it depends. On systems where the file
table is a fixed size array allocated at boot time 500 may be a significant
fraction of the file table. Even on systems where the "file table" is
allowed to grow dynamically (i.e., it isn't a table in the traditional
sense) you might still need to be concerned with the memory consumed and
performance as the number of entries increases. Also, since there are other
resources associated with a TCP/IP endpoint (i.e., a "socket") focusing
solely on the number of file table entries consumed is unlikely to keep the
system out of trouble.

The bad news is that I know of now portable method for determining at run
time, without the sysadmin specifying limits via a config file, what a safe
value is for the number of open sockets. Note carefully the phrase "open
sockets". Even after closing a socket some resources may be consumed (e.g.,
a PCB or protocol control block) for a finite, or even infinite, amount of
time.  It may not be sufficient to track the number of sockets your process
currently has open.

Whether or not such possibilities are of concern depends on a variety of
factors including, but not limited to, the consequences of exhausting an
operating resource. Welcome to software engineering as opposed to simple
programming :-)

Quote:> As a final note, does a socket descriptor (as opposed to an ordinary file
> descriptor) take up a vnode so that I should be worrying about those as
> well?

This is implementation dependent but every modern UNIX implementation I'm
familiar with has the file descriptor associated with a file table entry
which in turn is associated with a vnode which in turn is associated with
(or encapsulates) a TCP specific structure(s).
 
 
 

open fd management

Post by Valentin Nechaye » Thu, 03 Apr 2003 14:39:14


BS> (1) When a connection is in the backlog state on a listen socket, does
BS> it have an file descriptor associated with it or does it only get the
BS> file descriptor when I accept() the connection?

Of course it doesn't have a descriptor in descriptor space of any process.
(Kernel doesn't know what process will call accept() on listening socket.)
If you ask for kernel structure for opened socket, which is pointed by
file descriptor structure in kernel, it may be created in some implementation,
but all implementations known to me put description for fully-prepared
connection in special queue, bounded to the listening socket.
Length of this queue depends on implementation and tunables. On accept(),
kernel structures for socket and descriptor are prepared and descriptor
returned to process which called accept().

BS> (2) When I close() a connection, is the fd released right away, or
BS> does the fd only get released once the linger period is over?

One should suppose descriptor is unavailable on beginning of close()
execution, but kernel may ask close to sleep() the whole time specified
in linger data. fd can be released in any moment of this sleeping.

BS> As an additional question, what is a reasonable number of fd's to
BS> leave available for system use? I'm not expecting the systems I'm
BS> running on to have any other descriptor-hungry processes running, but
BS> I'd sure like to leave enough for the os and ordinary applications.
BS> I'm thinking 500 - does that sound reasonable?

It is highly dependable of system load specifics.

BS> As a final note, does a socket descriptor (as opposed to an ordinary
BS> file descriptor) take up a vnode so that I should be worrying about
BS> those as well?

For all known to me implementations it isn't vnode, because vnode is file
tree object, but "socket node" (really, struct socket or similar).

-netch-

 
 
 

open fd management

Post by Bowen Simmo » Fri, 04 Apr 2003 06:52:17




> > I'm working on a process that might need to maintain a very large
> > number of sockets, possibly so many as to endanger the rest of the
> > system and leave it without enough file descriptors to run.

> > To avoid such a calamity, I've added a code to keep count of the total
> > number of sockets this process has open. I have some questions, though
> > regarding the lifetime of socket file descriptors.

> Why don't you use setrlimit() to limit the number of file descriptor
> the process can use?

First, thanks to the respondents. I was not as clear as I should have
been with terminology, which caused some confusion. For that I
apologize and will try to be clearer.

The particular limit that worries me is this one from sysctl():

#define KERN_MAXFILES            7      /* int: max open files */

On my system, this has a value of 12288.

According to the man page for the open() command, it can return the
following error:

[ENFILE]           The system file table is full.

I infer that this means that the limit specified in KERN_MAXFILES has
been met, and so if I use up the file table in my process, then any
process running might get this error, and that many processes may not
be ready for it since the operation they might be engaged in would
ordinarily seem safe and innocuous. If it was gotten in a really bad
place, it could even potentially cause a kernel panic, for all I know.


Quote:

> > (1) When a connection is in the backlog state on a listen socket, does it
> > have an file descriptor associated with it or does it only get the file
> > descriptor when I accept() the connection?

> A file descriptor is allocated when accept() is called in the UNIX
> implementations I'm familiar with.

Thanks.

Quote:> > (2) When I close() a connection, is the fd released right away, or does
> > the fd only get released once the linger period is over?

> I don't know if any standard (e.g., SUS, POSIX, XPG4) specifies this. I do
> know that three implementations for which I have source code code access
> (two proprietary plus Linux) free the file descriptor immediately.

Thanks again.

Quote:> > As an additional question, what is a reasonable number of fd's to leave
> > available for system use? I'm not expecting the systems I'm running on to
> > have any other descriptor-hungry processes running, but I'd sure like to
> > leave enough for the os and ordinary applications. I'm thinking 500 -
> > does that sound reasonable?

> Again, the question as posed doesn't make any sense. Assuming you meant
> file table entries the answer is: it depends. On systems where the file
> table is a fixed size array allocated at boot time 500 may be a significant
> fraction of the file table.

The development platfrom is a MacOS X box. In a technical q&a on their
developer site, they write:

"By default, there is a global limit for the total number of open
files:  this limit is set to the value 12288.  Also, each unique open
file consumes a vnode in the Virtual-Filesystem Interface layer.      
          The number of available vnodes is a function of installed
RAM (on a 128M system, there will be approximately 2864 vnodes
available). During normal system operation, the system will maintain
between 300 and 400 open files. ... Advanced applications can override
global open file limit and the global vnode quota at runtime using the
sysctl routine."

The note was none too helpful as to exactly what counted against the
open file limit or with regard to any adverse consequences of raising
it: why does it exist at all? What might happen if I increased it to
2^31?

Quote:> Even on systems where the "file table" is
> allowed to grow dynamically (i.e., it isn't a table in the traditional
> sense) you might still need to be concerned with the memory consumed and
> performance as the number of entries increases.

Memory is more manageable - I can readily detect my app's own
footprint, the amount of logical and physical memory, free disk space,
and how much page swapping my app is doing. Given this, I should be
able to manage memory with some reasonable effort. If performance
becomes a problem, well, it becomes a problem. The user will need to
upgrade his hardware in some appropriate way if he can't get the
performance he wants with the hardware he has. Performance problems
also happily tend to manifest themselves in an obvious way - the
system gets slower as the load increases, and the user can peek in to
figure out what's wrong. On the other hand, exhausting the file table
could cause system death without warning. Everything might be just
peachy one second, dead as a doornail the next. What really
complicates matters is that I know of no way to find out how many
entries at any given time are in use, which makes managing that number
difficult.

Quote:> Also, since there are other
> resources associated with a TCP/IP endpoint (i.e., a "socket") focusing
> solely on the number of file table entries consumed is unlikely to keep the
> system out of trouble.

Umm, apart from obvious system resources like memory, cpu and swap
space, and cpu bandwidth, like what?

Quote:>  Welcome to software engineering as opposed to simple programming :-)

Thanks. I've been programming against various limits for a long time.
My first was trying to figure out how to use the weird memory swap
areas on an Apple II. Modern systems are easy - you only run into
their limits at the edges, rather than all the damn time.
 
 
 

open fd management

Post by Kurtis D. Rade » Fri, 04 Apr 2003 11:57:20



> The particular limit that worries me is this one from sysctl():

> #define    KERN_MAXFILES            7      /* int: max open files */

> On my system, this has a value of 12288.

> According to the man page for the open() command, it can return the
> following error:

> [ENFILE]           The system file table is full.

Those pertain to the global file table, not the per-process file descriptor
table.

Quote:> I infer that this means that the limit specified in KERN_MAXFILES has
> been met, and so if I use up the file table in my process, then any
> process running might get this error, and that many processes may not be
> ready for it since the operation they might be engaged in would
> ordinarily seem safe and innocuous. If it was gotten in a really bad
> place, it could even potentially cause a kernel panic, for all I know.

Any process that executes a system call which requires the allocation of a
file table entry will fail with ENFILE if all entries are in use. This
normally includes the open(2) and accept(2) system calls among others. It
does not include dup(2) or dup(2) since those calls only affect the process
file descriptor table.

Exhausting the file table shouldn't directly cause a kernel panic. However,
the system could fail because a kernel related process was unable to open a
file (e.g., to dynamically load a kernel module).

Quote:> The development platfrom is a MacOS X box. In a technical q&a on their
> developer site, they write:

> "By default, there is a global limit for the total number of open files:
> this limit is set to the value 12288.  Also, each unique open file
> consumes a vnode in the Virtual-Filesystem Interface layer.  The number
> of available vnodes is a function of installed RAM (on a 128M system,
> there will be approximately 2864 vnodes available).  During normal system
> operation, the system will maintain between 300 and 400 open files. ...
> Advanced applications can override global open file limit and the global
> vnode quota at runtime using the sysctl routine."

> The note was none too helpful as to exactly what counted against the open
> file limit or with regard to any adverse consequences of raising it: why
> does it exist at all? What might happen if I increased it to 2^31?

If you are truly interested in the*details I would recommend a good
book on UNIX kernel internals (e.g., "The Magic Garden Explained"). The
short answer is that classic UNIX allocated the "file" structures it needed
at boot time as a fixed size array. This allowed the algorithms which
manipulate those structures to be simpler and faster. Something extremely
important given the capabilities of the systems available 20+ years ago and
still fairly important for a broad class of systems today.

Since the structures are allocated at boot time you can't arbitrarily
increase the limit. The system will either exhaust its physical memory or,
more likely, its kernel virtual address space. That concern does not apply
to all limits. Some, such as the maximum size of a shared memory segment
(traditionally controlled by the SHMMAX parameter) impose limits on what
processes can do but do not directly influence how much memory or KVA the
kernel consumes.

Quote:>> Even on systems where the "file table" is allowed to grow dynamically
>> (i.e., it isn't a table in the traditional sense) you might still need
>> to be concerned with the memory consumed and performance as the number
>> of entries increases.

> Memory is more manageable - I can readily detect my app's own footprint,
> the amount of logical and physical memory, free disk space, and how much
> page swapping my app is doing. Given this, I should be able to manage
> memory with some reasonable effort.

That is not the memory I was talking about. I was referring to the memory,
and kernel virtual address space, consumed by the structures associated
with such things as the network endpoints (i.e., sockets) owned by your
process.

Quote:> If performance becomes a problem, well, it becomes a problem. The user
> will need to upgrade his hardware in some appropriate way if he can't get
> the performance he wants with the hardware he has. Performance problems
> also happily tend to manifest themselves in an obvious way - the system
> gets slower as the load increases, and the user can peek in to figure out
> what's wrong.

One of my areas of expertise is tuning UNIX kernels. And after doing that
for twelve years, including being flown halfway around the world many times
to assist in performance problem determination, I can assure you that
performance problems rarely "manifest themselves in an obvious way." My
biggest headaches as a software support engineer come from customers whose
programming staff think machine resources are infinite. Typically because
they've learned to program on single-user PCs with amounts of memory and
CPU processing power that was unheard of even on a mainframe twenty years
ago.

With respect to having a large number of network endpoints open one concern
is how efficiently the kernel can map incoming packets to the appropriate
network endpoint so the correct process can read the data. You may find
that the amount of kernel time spent processing inbound TCP/IP packets
increases non-linearly with the number of open connections.

Quote:> On the other hand, exhausting the file table could cause system death
> without warning. Everything might be just peachy one second, dead as a
> doornail the next. What really complicates matters is that I know of no
> way to find out how many entries at any given time are in use, which
> makes managing that number difficult.

Actually, you should be able to determine how many file table entries are
in use at any given instant. On many UNIX implementations "sar -v" will
tell you. Obviously you would want to obtain that information without the
cost of spawning a sar(1) command. I've never worked with Mac OS X so I
have no idea how to go about it on that OS. Also, obviously even if the
file table has x free entries at some point in time doesn't mean that a
microsecond later those entries will not have been allocated for some
purpose.

Quote:>> Also, since there are other resources associated with a TCP/IP endpoint
>> (i.e., a "socket") focusing solely on the number of file table entries
>> consumed is unlikely to keep the system out of trouble.

> Umm, apart from obvious system resources like memory, cpu and swap space,
> and cpu bandwidth, like what?

Does your program use SysV IPC semaphores? Then you have to worry about
that resource. Does your program open any files? Then you have to worry
about the number of inodes the kernel can cache. Does your program use
advisory locks (e.g., flock() or fcntl(F_SETLK))? Then that might be a
finite resource you have to worry about. Do you use shmat() or mmap()?
There might be limits on the number of such objects. Etcetera.

Basically, anything your program does which involves interaction with the
outside world (including interacting with other processes) will require
kernel data structures to manage that interaction. Those structures consume
both physical memory as well as kernel virtual address space. So you need
to consider whether that is a significant factor in the resource
requirements of your application.

Also, if the structures are statically allocated or there is a hard limit
on the number of instances of a given structure that can be instantiated
then you have to worry about that limit. The good news is that modern UNIX
implemenations have moved away from using statically allocated arrays of
structures. So there shouldn't be too many you have to worry about.

 
 
 

open fd management

Post by Casper H.S. Di » Fri, 04 Apr 2003 17:37:58



Quote:>Those pertain to the global file table, not the per-process file descriptor
>table.

Some Unix OSes do not have a global file table whch has a limited size
and allow you to allocate until the OSes memory runs out.  (So the
number will vary depending on the system load)

Casper
--
Expressed in this posting are my opinions.  They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.

 
 
 

open fd management

Post by Kurtis D. Rade » Sat, 05 Apr 2003 12:37:07



Quote:> Some Unix OSes do not have a global file table whch has a limited size
> and allow you to allocate until the OSes memory runs out.  (So the number
> will vary depending on the system load)

Very true. Perhaps I didn't make that as clear as I could have in my prior
messages. The trend has certainly been to move away from fixed size tables
wherever it is practical to do so. On many modern UNIX implementations
you're likely to find relatively few resources that are statically
allocated as arrays of structures at boot time. Of course, there may still
be limits imposed on the maximum number of instances of a given structure
that can be instantiated at any given instant, but since the structures are
dynamically allocated the limit can often be changed "on the fly."

The challenge for the O.P. will be in dynamically adapting the behavior of
his program to the available resources. In some ways having kernel
structures such as the file table be dynamically allocated can make that
more difficult, not less, since it becomes difficult (if not impossible) to
determine how close the system is to being unable to allocate another
instance of the structure.

 
 
 

1. Meaning of: "Cannot open mouse fd" ?????

Hello everyone,
        I have X working fine. But my mouse is jumpy <mouse problem
        again>. So when I do Ctrl-Alt Backspace to quit X, I receive
        the messagge "Cannot open mouse fd". Does anyone know what
        "fd" stands for or how to fix the mouse problem? My system
        is Compaq Presario 860 CDS. I would also appreciate any info
        regarding Compaq's mouse. Thanks for any help anyone can
        provide!

                                        Vinh.

2. Apology - libtermcap.so.2

3. open fd's and an strace

4. "Cannot load Solaris boot block"

5. How do I re-open a closed fd?

6. Portforwarding

7. pppd & get fd opened by chat script ?

8. KERNEL PANIC ! Need Help

9. How many fd's is process 1234 able to open?

10. Passing open fd's between processes

11. Getting pid's of open fd

12. read(fd, buf, size) after shutdown(fd, SHUT_RD) implementation-defined

13. how to detect if stderr (fd 2) is open