Merge with git+ssh://master.kernel.org/pub/scm/libs/klibc/klibc.git
diff --git a/usr/include/sys/time.h b/usr/include/sys/time.h
index 65115b5..7a2f8b9 100644
--- a/usr/include/sys/time.h
+++ b/usr/include/sys/time.h
@@ -6,9 +6,45 @@
 #define _SYS_TIME_H
 
 #include <klibc/extern.h>
+#include <stddef.h>
 #include <sys/types.h>
 #include <linux/time.h>
 
+/* The 2.6.20 Linux headers always #define FD_ZERO __FD_ZERO, etc, in
+   <linux/time.h> but not all architectures define the
+   double-underscore ones, except __NFDBITS, __FD_SETSIZE and
+   __FDSET_LONGS which are defined in <linux/posix_types.h>.
+
+   Unfortunately, some architectures define the double-underscore ones
+   as inlines, so we can't use a simple #ifdef test.  Thus, the only
+   safe option remaining is to #undef the top-level macros. */
+
+#undef FD_ZERO
+#undef FD_SET
+#undef FD_CLR
+#undef FD_ISSET
+
+__extern void *memset(void *, int, size_t);
+static inline void FD_ZERO(fd_set *__fdsetp)
+{
+	memset(__fdsetp, 0, sizeof(fd_set));
+}
+static inline void FD_SET(int __fd, fd_set *__fdsetp)
+{
+	__fdsetp->fds_bits[__fd/BITS_PER_LONG] |=
+		(1UL << (__fd % BITS_PER_LONG));
+}
+static inline void FD_CLR(int __fd, fd_set *__fdsetp)
+{
+	__fdsetp->fds_bits[__fd/BITS_PER_LONG] &=
+		~(1UL << (__fd % BITS_PER_LONG));
+}
+static inline int FD_ISSET(int __fd, fd_set *__fdsetp)
+{
+	return (__fdsetp->fds_bits[__fd/BITS_PER_LONG] >>
+		(__fd % BITS_PER_LONG)) & 1;
+}
+
 __extern int gettimeofday(struct timeval *, struct timezone *);
 __extern int settimeofday(const struct timeval *, const struct timezone *);
 __extern int getitimer(int, struct itimerval *);
diff --git a/usr/klibc/tests/Kbuild b/usr/klibc/tests/Kbuild
index 75d8bb3..07e8d64 100644
--- a/usr/klibc/tests/Kbuild
+++ b/usr/klibc/tests/Kbuild
@@ -31,6 +31,7 @@
 opentest.shared-y	:= opentest.o
 pipetest.shared-y	:= pipetest.o
 rtsig.shared-y		:= rtsig.o
+select.shared-y		:= select.o
 setenvtest.shared-y	:= setenvtest.o
 setjmptest.shared-y	:= setjmptest.o
 sigint.shared-y		:= sigint.o
diff --git a/usr/klibc/tests/select.c b/usr/klibc/tests/select.c
new file mode 100644
index 0000000..db75c55
--- /dev/null
+++ b/usr/klibc/tests/select.c
@@ -0,0 +1,55 @@
+/*
+ * Simple test of select()
+ */
+
+#include <sys/select.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+	int fdn, fdz, pfd[2], rv;
+	fd_set readset;
+	struct timeval timeout;
+	int err = 0;
+
+	/* We can always read from /dev/zero; open a pipe that is never
+	   ready for a "never readable" file descriptor */
+	fdz = open("/dev/zero", O_RDONLY);
+	pipe(pfd);
+	fdn = pfd[0];
+
+	FD_ZERO(&readset);
+	FD_SET(fdn, &readset);
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 100000;
+
+	rv = select(FD_SETSIZE, &readset, NULL, NULL, &timeout);
+
+	if (rv != 0) {
+		fprintf(stderr,
+			"select with timeout failed (rv = %d, errno = %s)\n",
+			rv, strerror(errno));
+		err++;
+	}
+
+	FD_ZERO(&readset);
+	FD_SET(fdn, &readset);
+	FD_SET(fdz, &readset);
+
+	rv = select(FD_SETSIZE, &readset, NULL, NULL, &timeout);
+	
+	if (rv != 1 || !FD_ISSET(fdz, &readset) ||
+	    FD_ISSET(fdn, &readset)) {
+		fprintf(stderr,
+			"select with /dev/zero failed (rv = %d, errno = %s)\n",
+			rv, strerror(errno));
+		err++;
+	}
+
+	return err;
+}