< prev index next >
src/java.base/linux/native/libnet/linux_close.c
Print this page
rev 13795 : 8150460: (linux|bsd|aix)_close.c: file descriptor table may become large or may not work at all
Reviewed-by:
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
@@ -21,10 +21,12 @@
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+#include <assert.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
@@ -57,14 +59,36 @@
* Signal to unblock thread
*/
static int sigWakeup = (__SIGRTMAX - 2);
/*
- * The fd table and the number of file descriptors
- */
-static fdEntry_t *fdTable;
-static int fdCount;
+ * fdTable holds one entry per file descriptor, up to a certain
+ * maximum.
+ * Theoretically, the number of possible file descriptors can get
+ * large, though usually it does not. To save memory, we keep file
+ * descriptors with large numerical values in an overflow table. That
+ * table is organized as a two-dimensional sparse array, allocated
+ * on demand.
+ */
+
+static fdEntry_t* fdTable;
+/* Max. number of file descriptors in fdTable. */
+static const int fdTableMaxSize = 0x1000; /* 4K */
+/* Max. theoretical number of file descriptor on system. */
+static int fdLimit;
+/* Length of fdTable, in number of entries. */
+static int fdTableLen;
+
+/* Overflow table: organized as array of n slabs, each holding
+ * 64k entries.
+ */
+static fdEntry_t** fdOverflowTable;
+/* Number of slabs in the overflow table */
+static int fdOverflowTableLen;
+/* Number of entries in one slab */
+static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
+pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
/*
* Null signal handler
*/
static void sig_wakeup(int sig) {
@@ -76,22 +100,43 @@
*/
static void __attribute((constructor)) init() {
struct rlimit nbr_files;
sigset_t sigset;
struct sigaction sa;
+ int i = 0;
- /*
- * Allocate table based on the maximum number of
- * file descriptors.
- */
+ /* Determine the maximum number of possible file descriptors. */
getrlimit(RLIMIT_NOFILE, &nbr_files);
- fdCount = nbr_files.rlim_max;
- fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
+ if (nbr_files.rlim_max != RLIM_INFINITY) {
+ fdLimit = nbr_files.rlim_max;
+ } else {
+ /* We just do not know. */
+ fdLimit = INT_MAX;
+ }
+
+ /* Allocate table for low value file descriptors. */
+ fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
+ fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
if (fdTable == NULL) {
fprintf(stderr, "library initialization failed - "
"unable to allocate file descriptor table - out of memory");
abort();
+ } else {
+ for (i = 0; i < fdTableLen; i ++) {
+ pthread_mutex_init(&fdTable[i].lock, NULL);
+ }
+ }
+
+ /* Allocate overflow table, if needed */
+ if (fdLimit > fdTableMaxSize) {
+ fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
+ fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
+ if (fdOverflowTable == NULL) {
+ fprintf(stderr, "library initialization failed - "
+ "unable to allocate file descriptor overflow table - out of memory");
+ abort();
+ }
}
/*
* Setup the signal handler
*/
@@ -104,19 +149,55 @@
sigaddset(&sigset, sigWakeup);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
}
/*
- * Return the fd table for this fd or NULL is fd out
- * of range.
+ * Return the fd table for this fd.
*/
static inline fdEntry_t *getFdEntry(int fd)
{
- if (fd < 0 || fd >= fdCount) {
+ fdEntry_t* result = NULL;
+
+ if (fd < 0) {
return NULL;
}
- return &fdTable[fd];
+
+ /* This should not happen. If it does, our assumption about
+ * max. fd value was wrong. */
+ assert(fd < fdLimit);
+
+ if (fd < fdTableMaxSize) {
+ assert(fd < fdTableLen);
+ result = fdTable + fd;
+ } else {
+ const int indexInOverflowTable = fd - fdTableMaxSize;
+ const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
+ const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
+ assert(rootindex < fdOverflowTableLen);
+ assert(slabindex < fdOverflowTableSlabSize);
+ pthread_mutex_lock(&fdOverflowTableLock);
+ if (fdOverflowTable[rootindex] == NULL) {
+ fdEntry_t* const newSlab =
+ (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
+ if (newSlab == NULL) {
+ fprintf(stderr, "Unable to allocate file descriptor table - out of memory");
+ pthread_mutex_unlock(&fdOverflowTableLock);
+ abort();
+ } else {
+ int i;
+ for (i = 0; i < fdOverflowTableSlabSize; i ++) {
+ pthread_mutex_init(&newSlab[i].lock, NULL);
+ }
+ fdOverflowTable[rootindex] = newSlab;
+ }
+ }
+ pthread_mutex_unlock(&fdOverflowTableLock);
+ result = fdOverflowTable[rootindex] + slabindex;
+ }
+
+ return result;
+
}
/*
* Start a blocking operation :-
* Insert thread onto thread list for the fd.
< prev index next >