diff --git a/TODO b/TODO
new file mode 100644
--- /dev/null
+++ b/TODO
@@ -0,0 +1,7 @@
+* Return the error code specified by errno if select fails. API change, slated
+  for 0.5.
+* Replace Timeout datatype with Maybe CTimeval. API change, slated for 0.5.
+* Move the select EINTR retry code from C to Haskell. Separate out clock_gettime
+  into a package of its own. Slated for 0.5?
+* Reorder functions to make the documentation more logical.
+* Move CTimeval, probably into a package of its own.
diff --git a/example/TestStdin.hs b/example/TestStdin.hs
--- a/example/TestStdin.hs
+++ b/example/TestStdin.hs
@@ -9,7 +9,7 @@
 main :: IO ()
 main = do
   fd <- handleToFd stdin
-  n <- select'' [fd] [] [] (finite 0 500)
+  n <- select'' [fd] [] [] (finite 5 500000)
   case n of
     0 ->  print "timeout"
     -1 -> error "select failed"
diff --git a/example/build.sh b/example/build.sh
--- a/example/build.sh
+++ b/example/build.sh
@@ -6,14 +6,14 @@
 
 cd ../src/System/Posix/IO/Select/FdSet/
 hsc2hs Internal.hsc
-gcc -DNDEBUG -Wall -std=c99 -c cbits.c
+gcc -O2 -Wall -std=c99 -c cbits.c
 cd ..
-gcc -Wall -std=c99 -lrt -c cbits.c
+gcc -O2 -Wall -std=c99 -lrt -c cbits.c
 hsc2hs Types.hsc
 cd $p
 
-ghc -fforce-recomp -threaded -o stdin-test --make TestStdin.hs -i../src $cobjs
-ghc -fforce-recomp -threaded -o fdset-example --make FdSetExample.hs -i../src $cobjs
-ghc -fforce-recomp -threaded -o select-example --make SelectExample.hs -i../src $cobjs
-ghc -fforce-recomp -threaded -o select-example2 --make SelectExample2.hs -i../src $cobjs
+ghc -O2 -fforce-recomp -threaded -o stdin-test --make TestStdin.hs -i../src $cobjs
+ghc -O2 -fforce-recomp -threaded -o fdset-example --make FdSetExample.hs -i../src $cobjs
+ghc -O2 -fforce-recomp -threaded -o select-example --make SelectExample.hs -i../src $cobjs
+ghc -O2 -fforce-recomp -threaded -o select-example2 --make SelectExample2.hs -i../src $cobjs
 
diff --git a/select.cabal b/select.cabal
--- a/select.cabal
+++ b/select.cabal
@@ -1,5 +1,5 @@
 Name:                select
-Version:             0.4
+Version:             0.4.0.1
 Synopsis:            Wrap the select(2) POSIX function
 Homepage:            http://nonempty.org/software/haskell-select
 License:             BSD3
@@ -17,6 +17,12 @@
 Description:         While tinkering on a project, I frequently found myself
 		     having to make FFI calls to @select(2)@. This package provides an interface to that system call.
 		     .
+		     Changed in version 0.4.0.1:
+		     .
+		     * Minor internal cleanups.
+		     .
+		     * TODO moved to file.
+		     .
 		     Changes in version 0.4:
 		     .
 		     * Introduce an interface to @fd_set@.
@@ -34,16 +40,6 @@
 		       Feedback is welcome.
 		     .
 		     * This package is far from complete, and should be tested throughly before being relied upon.
-		     .
-		     TODO:
-		     .
-		     * Return the error code specified by errno if @select@ fails.
-		     .
-		     * Possibly move the select retry code from C to Haskell.
-		     .
-		     * Reorder functions to make the documentation more logical.
-		     .
-		     * Use hsc2hs's #const to get preprocessor constants (removes some of FdSet's cbits.c).
 		     .
 		     /NOTE/: I feel I'm occupying prime namespace realestate with a package name
 		     like select. I'll happily let myself be chased away if someone more qualified wants
diff --git a/src/System/Posix/IO/Select/FdSet.hs b/src/System/Posix/IO/Select/FdSet.hs
--- a/src/System/Posix/IO/Select/FdSet.hs
+++ b/src/System/Posix/IO/Select/FdSet.hs
@@ -24,7 +24,6 @@
 import Prelude hiding (elem)
 import qualified System.Posix.IO.Select.FdSet.Internal as I
 import Foreign
-import qualified System.IO.Unsafe as UNSAFE
 import System.Posix.Types
 import Misc
 import Control.Monad
@@ -82,10 +81,7 @@
 
 -- | Test if a file descriptor is in range (see introduction).
 inRange :: Fd -> Bool
-inRange fd = fd' >= 0 && fd' < limit
-    where
-      fd' = fromIntegral fd
-      limit = UNSAFE.unsafePerformIO I.c_fd_setsize_wrapper
+inRange fd = fd >= 0 && fd < I.c_FD_SETSIZE
 
 -- | This file descriptor is at least as large as the largest in the
 -- set. If no file descriptors have ever been removed from the set,
diff --git a/src/System/Posix/IO/Select/FdSet/Internal.hsc b/src/System/Posix/IO/Select/FdSet/Internal.hsc
--- a/src/System/Posix/IO/Select/FdSet/Internal.hsc
+++ b/src/System/Posix/IO/Select/FdSet/Internal.hsc
@@ -1,8 +1,11 @@
 {-# LANGUAGE ForeignFunctionInterface #-}
 
+-- Primed functions work on ForeignPtrs, unprimed work on FdSets.
 module System.Posix.IO.Select.FdSet.Internal where
 
-import Foreign
+import Foreign.ForeignPtr.Safe
+import Foreign.Ptr
+import Foreign.Marshal.Utils
 import Foreign.C.Types
 import System.Posix.Types
 import Misc
@@ -35,6 +38,9 @@
                  withForeignPtr ptr (\ptr' -> withForeignPtr newPtr (\newPtr' -> copyBytes newPtr' ptr' #{size fd_set})) >>
                  return newPtr
 
+c_FD_SETSIZE :: Fd
+c_FD_SETSIZE = #{const FD_SETSIZE}
+
 foreign import ccall "cbits.h fd_zero_wrapper"
         c_fd_zero_wrapper :: Ptr () -> IO ()
 
@@ -46,6 +52,3 @@
 
 foreign import ccall "cbits.h fd_isset_wrapper"
         c_fd_isset_wrapper :: CInt -> Ptr () -> IO CInt
-
-foreign import ccall "cbits.h fd_setsize_wrapper"
-        c_fd_setsize_wrapper :: IO CInt
diff --git a/src/System/Posix/IO/Select/FdSet/cbits.c b/src/System/Posix/IO/Select/FdSet/cbits.c
--- a/src/System/Posix/IO/Select/FdSet/cbits.c
+++ b/src/System/Posix/IO/Select/FdSet/cbits.c
@@ -20,8 +20,3 @@
 {
   FD_ZERO(set);
 }
-
-int fd_setsize_wrapper()
-{
-  return FD_SETSIZE;
-}
diff --git a/src/System/Posix/IO/Select/FdSet/cbits.h b/src/System/Posix/IO/Select/FdSet/cbits.h
--- a/src/System/Posix/IO/Select/FdSet/cbits.h
+++ b/src/System/Posix/IO/Select/FdSet/cbits.h
@@ -6,4 +6,4 @@
 int fd_isset_wrapper(int fd, fd_set* set);
 void fd_set_wrapper(int fd, fd_set* set);
 void fd_zero_wrapper(fd_set* set);
-int fd_setsize_wrapper();
+
diff --git a/src/System/Posix/IO/Select/cbits.c b/src/System/Posix/IO/Select/cbits.c
--- a/src/System/Posix/IO/Select/cbits.c
+++ b/src/System/Posix/IO/Select/cbits.c
@@ -50,33 +50,33 @@
       #endif
       if (timeout != NULL) // Case of finite timeouts.
       {
-	clock_gettime(CLOCK_MONOTONIC, &current);
-	remaining.tv_sec = stop.tv_sec - current.tv_sec;
-	remaining.tv_nsec = stop.tv_nsec - current.tv_nsec;
+        clock_gettime(CLOCK_MONOTONIC, &current);
+        remaining.tv_sec = stop.tv_sec - current.tv_sec;
+        remaining.tv_nsec = stop.tv_nsec - current.tv_nsec;
 
-	while (remaining.tv_nsec > 1000000000)
-	{
-	  remaining.tv_sec++;
-	  remaining.tv_nsec -= 1000000000;
-	}
-	while (remaining.tv_nsec < 0)
-	{
-	  remaining.tv_sec--;
-	  remaining.tv_nsec += 1000000000;
-	}
-	if (remaining.tv_sec < 0)
-	{
-	  remaining.tv_sec = 0;
-	  remaining.tv_nsec = 0;
-	}
+        while (remaining.tv_nsec > 1000000000)
+        {
+          remaining.tv_sec++;
+          remaining.tv_nsec -= 1000000000;
+        }
+        while (remaining.tv_nsec < 0)
+        {
+          remaining.tv_sec--;
+          remaining.tv_nsec += 1000000000;
+        }
+        if (remaining.tv_sec < 0)
+        {
+          remaining.tv_sec = 0;
+          remaining.tv_nsec = 0;
+        }
 
         #ifndef NDEBUG
-	printf("C: Was interrupted with %ld s, %ld ns remaining\n", remaining.tv_sec, remaining.tv_nsec);
+        printf("C: Was interrupted with %ld s, %ld ns remaining\n", remaining.tv_sec, remaining.tv_nsec);
         #endif
 
-	// Set up for retry.
-	timeout->tv_sec = remaining.tv_sec;
-	timeout->tv_usec = remaining.tv_nsec/1000;
+        // Set up for retry.
+        timeout->tv_sec = remaining.tv_sec;
+        timeout->tv_usec = remaining.tv_nsec/1000;
       }
       // Set up for retry (also in infinite case).
       *readfds = readfds_orig;
