Patch from Tom Hughes: set VG_(max_fd) based on the current file
descriptor limit rather than assuming 1024.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2127 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index 179e41f..0ce9b13 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -108,14 +108,9 @@
    give finer interleaving but much increased scheduling overheads. */
 #define VG_SCHEDULING_QUANTUM   50000
 
-/* Maximum FD Valgrind can use for its internal file descriptors. */
-#define VG_MAX_SAFE_FD	1024	/* usual ulimit */
-
-/* Maximum allowed application-visible file descriptor.  Valgrind's
-   internal fds hide above this (starting at VG_MAX_FD+1).  This is
-   derived from the default fd limit (1024) minus the 2 fds per thread
-   and a small number of extra fds. */
-#define VG_MAX_FD	(VG_MAX_SAFE_FD - (VG_N_THREADS*2 + 4))
+/* Number of file descriptors that Valgrind tries to reserve for
+   it's own use - two per thread plues a small number of extras. */
+#define VG_N_RESERVED_FDS (VG_N_THREADS*2 + 4)
 
 /* Stack size for a thread.  We try and check that they do not go
    beyond it. */
@@ -182,6 +177,9 @@
 /* pgrp of process (global to all threads) */
 extern Int VG_(main_pgrp);
 
+/* Maximum allowed application-visible file descriptor */
+extern Int VG_(max_fd);
+
 /* Should we stop collecting errors if too many appear?  default: YES */
 extern Bool  VG_(clo_error_limit);
 /* Enquire about whether to attach to GDB at errors?   default: NO */
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 9222f2e..f007714 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -153,6 +153,9 @@
 /* PGRP of process */
 Int VG_(main_pgrp);
 
+/* Maximum allowed application-visible file descriptor */
+Int VG_(max_fd);
+
 /* Words. */
 static Int baB_off = 0;
 
@@ -1109,7 +1112,7 @@
    }
 
    /* Move logfile_fd into the safe range, so it doesn't conflict with any app fds */
-   eventually_logfile_fd = VG_(fcntl)(VG_(clo_logfile_fd), VKI_F_DUPFD, VG_MAX_FD+1);
+   eventually_logfile_fd = VG_(fcntl)(VG_(clo_logfile_fd), VKI_F_DUPFD, VG_(max_fd)+1);
    if (eventually_logfile_fd < 0)
       VG_(message)(Vg_UserMsg, "valgrind: failed to move logfile fd into safe range");
    else {
@@ -1364,6 +1367,7 @@
 void VG_(main) ( const KickstartParams *kp, void (*tool_init)(void), void *tool_dlhandle )
 {
    VgSchedReturnCode src;
+   struct vki_rlimit rl;
 
    /* initial state */
    if (0)
@@ -1414,6 +1418,25 @@
    VG_(atfork)(NULL, NULL, newpid);
    newpid(VG_INVALID_THREADID);
 
+   /* Get the current file descriptor limits. */
+   if (VG_(getrlimit)(VKI_RLIMIT_NOFILE, &rl) < 0) {
+      rl.rlim_cur = 1024;
+      rl.rlim_max = 1024;
+   }
+
+   /* Work out where to move the soft limit to. */
+   if (rl.rlim_cur + VG_N_RESERVED_FDS <= rl.rlim_max) {
+      rl.rlim_cur = rl.rlim_cur + VG_N_RESERVED_FDS;
+   } else {
+      rl.rlim_cur = rl.rlim_max;
+   }
+
+   /* Reserve some file descriptors for our use. */
+   VG_(max_fd) = rl.rlim_cur - VG_N_RESERVED_FDS;
+
+   /* Update the soft limit. */
+   VG_(setrlimit)(VKI_RLIMIT_NOFILE, &rl);
+
    /* Read /proc/self/maps into a buffer.  Must be before:
       - SK_(pre_clo_init)(): so that if it calls VG_(malloc)(), any mmap'd
         superblocks are not erroneously identified as being owned by the
diff --git a/coregrind/vg_mylibc.c b/coregrind/vg_mylibc.c
index dbf78eb..850e178 100644
--- a/coregrind/vg_mylibc.c
+++ b/coregrind/vg_mylibc.c
@@ -1203,13 +1203,13 @@
 {
    Int newfd;
 
-   newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_MAX_FD+1);
+   newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(max_fd)+1);
    if (newfd != -1)
       VG_(close)(oldfd);
 
    VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
 
-   vg_assert(newfd > VG_MAX_FD);
+   vg_assert(newfd > VG_(max_fd));
    return newfd;
 }
 
@@ -1429,6 +1429,17 @@
 }
 
 
+/* Support for setrlimit. */
+Int VG_(setrlimit) (Int resource, struct vki_rlimit *rlim)
+{
+   Int res;
+   /* res = setrlimit( resource, rlim ); */
+   res = VG_(do_syscall)(__NR_setrlimit, (UInt)resource, (UInt)rlim);
+   if(VG_(is_kerror)(res)) res = -1;
+   return res;
+}
+
+
 /* Support for getdents. */
 Int VG_(getdents) (UInt fd, struct vki_dirent *dirp, UInt count)
 {
diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c
index 0e5ffb0..a213adc 100644
--- a/coregrind/vg_syscalls.c
+++ b/coregrind/vg_syscalls.c
@@ -311,7 +311,7 @@
 {
    OpenFd *i = allocated_fds;
 
-   if (fd > VG_MAX_FD)
+   if (fd > VG_(max_fd))
       return;			/* Valgrind internal */
 
    while(i) {
@@ -344,7 +344,7 @@
 {
    OpenFd *i;
 
-   if (fd > VG_MAX_FD)
+   if (fd > VG_(max_fd))
       return;			/* Valgrind internal */
 
    /* Check to see if this fd is already open. */
@@ -889,7 +889,7 @@
 /* Return true if we're allowed to use or create this fd */
 static Bool fd_allowed(Int fd, const Char *syscall, ThreadId tid)
 {
-   if (fd < 0 || fd > VG_MAX_FD || fd == VG_(clo_logfile_fd)) {
+   if (fd < 0 || fd > VG_(max_fd) || fd == VG_(clo_logfile_fd)) {
       VG_(message)(Vg_UserMsg, 
          "Warning: invalid file descriptor %d in syscall %s()",
          fd, syscall);
@@ -4155,7 +4155,7 @@
    switch (arg1 /* request */) {
 
    case SYS_SOCKETPAIR:
-      /* XXX TODO: check return fd against VG_MAX_FD */
+      /* XXX TODO: check return fd against VG_(max_fd) */
       VG_TRACK( post_mem_write, ((UInt*)arg2)[3], 2*sizeof(int) );
       if(VG_(clo_track_fds)) {
          record_fd_open(tid, ((UInt*)((UInt*)arg2)[3])[0], NULL);
diff --git a/include/vg_skin.h.base b/include/vg_skin.h.base
index cfee479..e7ca38f 100644
--- a/include/vg_skin.h.base
+++ b/include/vg_skin.h.base
@@ -396,6 +396,9 @@
 /* Get client resource limit*/
 extern Int VG_(getrlimit) ( Int resource, struct vki_rlimit *rlim );
 
+/* Set client resource limit*/
+extern Int VG_(setrlimit) ( Int resource, struct vki_rlimit *rlim );
+
 /* Crude stand-in for the glibc system() call. */
 extern Int   VG_(system) ( Char* cmd );