Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 17 Oct 95 00:26:42 -0700
From:      Bakul Shah <bakul@netcom.com>
To:        Terry Lambert <terry@lambert.org>
Cc:        hackers@freefall.freebsd.org, current@freefall.freebsd.org
Subject:   Re: getdtablesize() broken? 
Message-ID:  <199510170726.AAA00821@netcom17.netcom.com>
In-Reply-To: Your message of "Mon, 16 Oct 95 11:31:02 PDT." <199510161831.LAA25019@phaeton.artisoft.com> 

next in thread | previous in thread | raw e-mail | index | archive | help
> Using FD_SETSIZE or using RLIMIT_NOFILE, or getting the current open
> descriptor limit from the kernel (when the application has an explicit
> bitvector element limitation set at compile time, not because of a
> check for FD_SETSIZE by because declaration of a bit vector uses the
> FD_SETSIZE to declare the vector length) is equally stupid and equally
> succeptible to screwups.

> The "correct" way is to get rid of the interfaces which are succeptible
> to bad programming style.  The user *SHOULD* be using the highest open
> FD in the set of FD's being selected upon, *NOT* some arbitrary constant.

My mistake.  I didn't explicitly state that I was bitching about
an *in-kernel* limitation.  Granted that an application should use
what you suggest but the problem is that a {Free|Net}BSD _kernel_
restricts nfds that can be passed to select() to FD_SETSIZE.  I
can open, say, 1000 sockets, there is no way I can select on an fd
>= FD_SETSIZE.

Unshar the attached little program and try this test.

	% cc x.c
	% limit openefiles 500 # you may need to do `limit descriptors 500'
	% a.out 500 </dev/null

If you can select on fd 499, the program will terminate silently.
Instead, you will see

	select error Invalid argument when fd = 256

(BTW, If you don't change the limit, you will discover an off by
one bug: the default limit is 64 but you can only open 63 fds)

So I can do everything with fd > 255 except select().  This
happens because of this line in /sys/kern/sys_generic.c:select()

	if (uap->nd > FD_SETSIZE)

It should be replaced with

	if (uap->nd > p->fd->fd_nfiles)

It is this hardwired use of FD_SETSIZE *in* the kernel I am
bitching about.

There *are* scalability problems with select() and we can
use a more scalable interface but regardless, select() needs
to work with any valid file descriptor.

--bakul
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 10/17/1995 07:18 UTC by bakul@netcom17
# Source directory /u7/bakul
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    502 -rw-r--r-- x.c
#
# ============= x.c ==============
if test -f 'x.c' -a X"$1" != X"-c"; then
	echo 'x - skipping x.c (File already exists)'
else
echo 'x - extracting x.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'x.c' &&
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
X
int main(int argc, char**argv) {
X	int n = argc > 1 ? atoi(argv[1]) : 257;
X	int * bits = calloc((n+31)/32, sizeof(int));
X	int i;
X
X	for (i = 3; i < n; i++) {
X		int fd = dup(0);
X		if (fd < 0) {
X			fprintf(stderr, "Can only get %d descriptors\n", i);
X			exit(1);
X		}
X		bits[fd/32] |= 1<<(fd%32);
X		if (select(fd+1, bits, 0, 0, 0) < 0) {
X			fprintf(stderr, "select error %s when fd = %d\n",
X				strerror(errno), fd);
X			exit(1);
X		}
X	}
X	exit(0);
}
SHAR_EOF
chmod 0644 x.c ||
echo 'restore of x.c failed'
Wc_c="`wc -c < 'x.c'`"
test 502 -eq "$Wc_c" ||
	echo 'x.c: original size 502, current size' "$Wc_c"
fi
exit 0



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199510170726.AAA00821>