< 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:
@@ -31,10 +31,11 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include <unistd.h>
+#include <limits.h>
#include <errno.h>
#include <sys/poll.h>
/*
* Stack allocated by thread when doing blocking operation
@@ -57,14 +58,24 @@
* 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;
+ * 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.
+ * The fd table is organized as sparse two dimensional array, with a
+ * root array holding pointers to entry arrays, which in turn hold
+ * the entries. entry arrays are allocated on demand, save for the
+ * very first one, which is pre-allocated.
+ */
+fdEntry_t** fdTable;
+pthread_mutex_t fdTableLock = PTHREAD_MUTEX_INITIALIZER;
+/* Number of bits to apply to the file descriptor to get the index into
+ * the root array resp. entry array */
+unsigned fdTableRootArrayBits;
+unsigned fdTableEntryArrayBits;
/*
* Null signal handler
*/
static void sig_wakeup(int sig) {
@@ -74,25 +85,49 @@
* Initialization routine (executed when library is loaded)
* Allocate fd tables and sets up signal handler.
*/
static void __attribute((constructor)) init() {
struct rlimit nbr_files;
+ unsigned max = 0;
+ unsigned maxbits;
sigset_t sigset;
struct sigaction sa;
- /*
- * 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) {
+ max = nbr_files.rlim_max;
+ } else {
+ max = INT_MAX;
+ }
+
+ /* How many bits do we need to cover all possible values for
+ * file descriptors? */
+ for (maxbits = 1;
+ (unsigned) 1 << maxbits < max && maxbits < 32;
+ maxbits ++);
+
+ /* Calculate size of entry arrays: for small possible file descriptor ranges,
+ * fall back to a linear array. For larger ranges, make the entry tables 64K.
+ * This means for the largest possible range of INT_MAX (32bit ints), the root
+ * table will be 32K entries (32K * 64K = INT_MAX) */
+ fdTableEntryArrayBits = maxbits > 16 ? 16 : maxbits;
+ fdTableRootArrayBits = maxbits - fdTableEntryArrayBits;
+
+ /* Allocate root array */
+ fdTable = (fdEntry_t**)calloc(1 << fdTableRootArrayBits, sizeof(fdEntry_t*));
if (fdTable == NULL) {
fprintf(stderr, "library initialization failed - "
"unable to allocate file descriptor table - out of memory");
abort();
}
+ fdTable[0] = (fdEntry_t*)calloc(1 << fdTableEntryArrayBits, sizeof(fdEntry_t));
+ if (fdTable[0] == NULL) {
+ fprintf(stderr, "library initialization failed - "
+ "unable to allocate file descriptor table - out of memory");
+ abort();
+ }
/*
* Setup the signal handler
*/
sa.sa_handler = sig_wakeup;
@@ -109,14 +144,48 @@
* 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 rootArrayIndex;
+ int entryArrayIndex;
+ unsigned rootArrayMask;
+ unsigned entryArrayMask;
+ fdEntry_t* entryTable = NULL;
+
+ if (fd < 0) {
return NULL;
}
- return &fdTable[fd];
+
+ entryArrayMask = (1 << fdTableEntryArrayBits) - 1;
+ rootArrayMask =
+ ((1 << (fdTableRootArrayBits + fdTableEntryArrayBits)) - 1) & ~entryArrayMask;
+
+ entryArrayIndex = fd & entryArrayMask;
+ rootArrayIndex = (fd & rootArrayMask) >> fdTableEntryArrayBits;
+
+ if (rootArrayIndex == 0) {
+ /* fast path: first entry array gets preallocated. */
+ entryTable = fdTable[0];
+ } else {
+ /* Slow path: check if entry array exists, create it if needed */
+ pthread_mutex_lock(&fdTableLock);
+ if (fdTable[rootArrayIndex] == NULL) {
+ entryTable = (fdEntry_t*)calloc(1 << fdTableEntryArrayBits, sizeof(fdEntry_t));
+ if (entryTable == NULL) {
+ fprintf(stderr, "Unable to allocate file descriptor table - out of memory");
+ pthread_mutex_unlock(&fdTableLock);
+ abort();
+ }
+ fdTable[rootArrayIndex] = entryTable;
+ } else {
+ entryTable = fdTable[rootArrayIndex];
+ }
+ pthread_mutex_unlock(&fdTableLock);
+ }
+
+ return entryTable + entryArrayIndex;
}
/*
* Start a blocking operation :-
* Insert thread onto thread list for the fd.
< prev index next >