< prev index next >

src/java.base/linux/native/libnet/linux_close.c

Print this page
rev 13764 : 8150460: (linux|bsd|aix)_close.c: file descriptor table may become large or may not work at all
Reviewed-by:

@@ -57,14 +57,26 @@
  * Signal to unblock thread
  */
 static int sigWakeup = (__SIGRTMAX - 2);
 
 /*
- * The fd table and the number of file descriptors
+ * The fd table holds one entry per file descriptor.
+ * Note: the number of possible file descriptors can get quite large;
+ * RLIMIT_NO_FILE can be large or even infinite.
+ * Instead of allocating a plain array of RLIMIT_NO_FILE len, we
+ * allocate a two dimensional sparse array: file descriptors are
+ * of type int, which on all our platforms is 32bit; so we
+ * use the upper 16 bit as index into a base table, and the lower
+ * 16bit as index into the actual entry table; the latter is only
+ * allocated on demand.
+ * Usually (<64K file descriptors and file descriptors handed out
+ * sequentually) there will only be the base table and one entry
+ * table in slot 0. But this approach handles corner cases like
+ * large file descriptor values seamlessly.
  */
-static fdEntry_t *fdTable;
-static int fdCount;
+static fdEntry_t** fdTable;
+static pthread_mutex_t fdTableLock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
  * Null signal handler
  */
 static void sig_wakeup(int sig) {

@@ -73,21 +85,14 @@
 /*
  * Initialization routine (executed when library is loaded)
  * Allocate fd tables and sets up signal handler.
  */
 static void __attribute((constructor)) init() {
-    struct rlimit nbr_files;
     sigset_t sigset;
     struct sigaction sa;
 
-    /*
-     * Allocate table based on the maximum number of
-     * file descriptors.
-     */
-    getrlimit(RLIMIT_NOFILE, &nbr_files);
-    fdCount = nbr_files.rlim_max;
-    fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
+    fdTable = (fdEntry_t**)calloc(0x10000, sizeof(fdEntry_t*));
     if (fdTable == NULL) {
         fprintf(stderr, "library initialization failed - "
                 "unable to allocate file descriptor table - out of memory");
         abort();
     }

@@ -109,14 +114,37 @@
  * Return the fd table for this fd or NULL is fd out
  * of range.
  */
 static inline fdEntry_t *getFdEntry(int fd)
 {
-    if (fd < 0 || fd >= fdCount) {
+    int base_index;
+    int index;
+    fdEntry_t* entryTable = NULL;
+
+    if (fd < 0) {
         return NULL;
     }
-    return &fdTable[fd];
+
+    base_index = fd >> 16;
+    index = fd & 0xFFFF;
+
+    /* Look up the entry table; create it if needed */
+    pthread_mutex_lock(&fdTableLock);
+    if (fdTable[base_index] == NULL) {
+      entryTable = calloc(0x10000, sizeof(fdEntry_t));
+      if (entryTable == NULL) {
+        fprintf(stderr, "Unable to allocate file descriptor table - out of memory");
+        pthread_mutex_unlock(&fdTableLock);
+        abort();
+      }
+      fdTable[base_index] = entryTable;
+    } else {
+      entryTable = fdTable[base_index];
+    }
+    pthread_mutex_unlock(&fdTableLock);
+
+    return entryTable + index;
 }
 
 /*
  * Start a blocking operation :-
  *    Insert thread onto thread list for the fd.
< prev index next >