提交 0ce54d50 编写于 作者: S stuefe

8150460: (linux|bsd|aix)_close.c: file descriptor table may become large or may not work at all

Reviewed-by: dsamersoff, rriggs
上级 6a279c04
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
* (see aix_close_init). * (see aix_close_init).
* *
*/ */
#include <assert.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
...@@ -76,10 +79,35 @@ typedef struct { ...@@ -76,10 +79,35 @@ typedef struct {
static int sigWakeup = (SIGRTMAX - 1); static int sigWakeup = (SIGRTMAX - 1);
/* /*
* The fd table and the number of file descriptors * 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. Entries for small value file
* descriptors are kept in a simple table, which covers most scenarios.
* Entries for large value file descriptors are kept in an overflow
* table, which is organized as a sparse two dimensional array whose
* slabs are allocated on demand. This covers all corner cases while
* keeping memory consumption reasonable.
*/
/* Base table for low value file descriptors */
static fdEntry_t* fdTable = NULL;
/* Maximum size of base table (in number of entries). */
static const int fdTableMaxSize = 0x1000; /* 4K */
/* Actual size of base table (in number of entries) */
static int fdTableLen = 0;
/* Max. theoretical number of file descriptors on system. */
static int fdLimit = 0;
/* Overflow table, should base table not be large enough. Organized as
* an array of n slabs, each holding 64k entries.
*/ */
static fdEntry_t *fdTable = NULL; static fdEntry_t** fdOverflowTable = NULL;
static int fdCount = 0; /* Number of slabs in the overflow table */
static int fdOverflowTableLen = 0;
/* Number of entries in one slab */
static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
/* /*
* Null signal handler * Null signal handler
...@@ -98,42 +126,42 @@ void aix_close_init() { ...@@ -98,42 +126,42 @@ void aix_close_init() {
struct rlimit nbr_files; struct rlimit nbr_files;
sigset_t sigset; sigset_t sigset;
struct sigaction sa; struct sigaction sa;
int i = 0;
/* Check already initialized */ /* Determine the maximum number of possible file descriptors. */
if (fdCount > 0 && fdTable != NULL) {
return;
}
/*
* Allocate table based on the maximum number of
* file descriptors.
*/
if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
fprintf(stderr, "library initialization failed - " fprintf(stderr, "library initialization failed - "
"unable to get max # of allocated fds\n"); "unable to get max # of allocated fds\n");
abort(); abort();
} }
fdCount = nbr_files.rlim_max; if (nbr_files.rlim_max != RLIM_INFINITY) {
/* fdLimit = nbr_files.rlim_max;
* We have a conceptual problem here, when the number of files is } else {
* unlimited. As a kind of workaround, we ensure the table is big /* We just do not know. */
* enough for handle even a large number of files. Since SAP itself fdLimit = INT_MAX;
* recommends a limit of 32000 files, we just use 64000 as 'infinity'.
*/
if (nbr_files.rlim_max == RLIM_INFINITY) {
fdCount = 64000;
} }
fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
/* Allocate table for low value file descriptors. */
fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
if (fdTable == NULL) { if (fdTable == NULL) {
fprintf(stderr, "library initialization failed - " fprintf(stderr, "library initialization failed - "
"unable to allocate file descriptor table - out of memory"); "unable to allocate file descriptor table - out of memory");
abort(); abort();
} else {
for (i = 0; i < fdTableLen; i ++) {
pthread_mutex_init(&fdTable[i].lock, NULL);
}
} }
{ /* Allocate overflow table, if needed */
int i; if (fdLimit > fdTableMaxSize) {
for (i=0; i < fdCount; i++) { fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
pthread_mutex_init(&fdTable[i].lock, NULL); 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();
} }
} }
...@@ -151,17 +179,60 @@ void aix_close_init() { ...@@ -151,17 +179,60 @@ void aix_close_init() {
} }
/* /*
* Return the fd table for this fd or NULL is fd out * Return the fd table for this fd.
* of range.
*/ */
static inline fdEntry_t *getFdEntry(int fd) static inline fdEntry_t *getFdEntry(int fd)
{ {
if (fd < 0 || fd >= fdCount) { fdEntry_t* result = NULL;
if (fd < 0) {
return NULL; 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) {
/* fd is in base table. */
assert(fd < fdTableLen);
result = &fdTable[fd];
} else {
/* fd is in overflow table. */
const int indexInOverflowTable = fd - fdTableMaxSize;
const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
fdEntry_t* slab = NULL;
assert(rootindex < fdOverflowTableLen);
assert(slabindex < fdOverflowTableSlabSize);
pthread_mutex_lock(&fdOverflowTableLock);
/* Allocate new slab in overflow table if needed */
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 overflow"
" table slab - 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);
slab = fdOverflowTable[rootindex];
result = &slab[slabindex];
}
return result;
} }
/* /*
* Start a blocking operation :- * Start a blocking operation :-
* Insert thread onto thread list for the fd. * Insert thread onto thread list for the fd.
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
* questions. * questions.
*/ */
#include <assert.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/param.h> #include <sys/param.h>
...@@ -61,18 +63,35 @@ typedef struct { ...@@ -61,18 +63,35 @@ typedef struct {
static int sigWakeup = SIGIO; static int sigWakeup = SIGIO;
/* /*
* The fd table and the number of file descriptors * 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. Entries for small value file
* descriptors are kept in a simple table, which covers most scenarios.
* Entries for large value file descriptors are kept in an overflow
* table, which is organized as a sparse two dimensional array whose
* slabs are allocated on demand. This covers all corner cases while
* keeping memory consumption reasonable.
*/ */
static fdEntry_t *fdTable;
static int fdCount;
/* /* Base table for low value file descriptors */
* This limit applies if getlimit() returns unlimited. static fdEntry_t* fdTable = NULL;
* Unfortunately, this means if someone wants a higher limit /* Maximum size of base table (in number of entries). */
* then they have to set an explicit limit, higher than this, static const int fdTableMaxSize = 0x1000; /* 4K */
* which is probably counter-intuitive. /* Actual size of base table (in number of entries) */
static int fdTableLen = 0;
/* Max. theoretical number of file descriptors on system. */
static int fdLimit = 0;
/* Overflow table, should base table not be large enough. Organized as
* an array of n slabs, each holding 64k entries.
*/ */
#define MAX_FD_COUNT 4096 static fdEntry_t** fdOverflowTable = NULL;
/* Number of slabs in the overflow table */
static int fdOverflowTableLen = 0;
/* Number of entries in one slab */
static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
/* /*
* Null signal handler * Null signal handler
...@@ -88,26 +107,43 @@ static void __attribute((constructor)) init() { ...@@ -88,26 +107,43 @@ static void __attribute((constructor)) init() {
struct rlimit nbr_files; struct rlimit nbr_files;
sigset_t sigset; sigset_t sigset;
struct sigaction sa; struct sigaction sa;
int i; int i = 0;
/* /* Determine the maximum number of possible file descriptors. */
* Allocate table based on the maximum number of if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
* file descriptors. fprintf(stderr, "library initialization failed - "
*/ "unable to get max # of allocated fds\n");
getrlimit(RLIMIT_NOFILE, &nbr_files); abort();
if (nbr_files.rlim_max == RLIM_INFINITY) { }
fdCount = MAX_FD_COUNT; if (nbr_files.rlim_max != RLIM_INFINITY) {
fdLimit = nbr_files.rlim_max;
} else { } else {
fdCount = nbr_files.rlim_max; /* We just do not know. */
fdLimit = INT_MAX;
} }
fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
/* Allocate table for low value file descriptors. */
fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
if (fdTable == NULL) { if (fdTable == NULL) {
fprintf(stderr, "library initialization failed - " fprintf(stderr, "library initialization failed - "
"unable to allocate file descriptor table - out of memory"); "unable to allocate file descriptor table - out of memory");
abort(); abort();
} else {
for (i = 0; i < fdTableLen; i ++) {
pthread_mutex_init(&fdTable[i].lock, NULL);
}
} }
for (i=0; i<fdCount; 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();
}
} }
/* /*
...@@ -124,17 +160,60 @@ static void __attribute((constructor)) init() { ...@@ -124,17 +160,60 @@ static void __attribute((constructor)) init() {
} }
/* /*
* Return the fd table for this fd or NULL is fd out * Return the fd table for this fd.
* of range.
*/ */
static inline fdEntry_t *getFdEntry(int fd) static inline fdEntry_t *getFdEntry(int fd)
{ {
if (fd < 0 || fd >= fdCount) { fdEntry_t* result = NULL;
if (fd < 0) {
return NULL; 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) {
/* fd is in base table. */
assert(fd < fdTableLen);
result = &fdTable[fd];
} else {
/* fd is in overflow table. */
const int indexInOverflowTable = fd - fdTableMaxSize;
const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
fdEntry_t* slab = NULL;
assert(rootindex < fdOverflowTableLen);
assert(slabindex < fdOverflowTableSlabSize);
pthread_mutex_lock(&fdOverflowTableLock);
/* Allocate new slab in overflow table if needed */
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 overflow"
" table slab - 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);
slab = fdOverflowTable[rootindex];
result = &slab[slabindex];
}
return result;
} }
/* /*
* Start a blocking operation :- * Start a blocking operation :-
* Insert thread onto thread list for the fd. * Insert thread onto thread list for the fd.
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
* questions. * questions.
*/ */
#include <assert.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
...@@ -59,10 +61,35 @@ typedef struct { ...@@ -59,10 +61,35 @@ typedef struct {
static int sigWakeup = (__SIGRTMAX - 2); static int sigWakeup = (__SIGRTMAX - 2);
/* /*
* The fd table and the number of file descriptors * 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. Entries for small value file
* descriptors are kept in a simple table, which covers most scenarios.
* Entries for large value file descriptors are kept in an overflow
* table, which is organized as a sparse two dimensional array whose
* slabs are allocated on demand. This covers all corner cases while
* keeping memory consumption reasonable.
*/ */
static fdEntry_t *fdTable;
static int fdCount; /* Base table for low value file descriptors */
static fdEntry_t* fdTable = NULL;
/* Maximum size of base table (in number of entries). */
static const int fdTableMaxSize = 0x1000; /* 4K */
/* Actual size of base table (in number of entries) */
static int fdTableLen = 0;
/* Max. theoretical number of file descriptors on system. */
static int fdLimit = 0;
/* Overflow table, should base table not be large enough. Organized as
* an array of n slabs, each holding 64k entries.
*/
static fdEntry_t** fdOverflowTable = NULL;
/* Number of slabs in the overflow table */
static int fdOverflowTableLen = 0;
/* Number of entries in one slab */
static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
/* /*
* Null signal handler * Null signal handler
...@@ -78,18 +105,43 @@ static void __attribute((constructor)) init() { ...@@ -78,18 +105,43 @@ static void __attribute((constructor)) init() {
struct rlimit nbr_files; struct rlimit nbr_files;
sigset_t sigset; sigset_t sigset;
struct sigaction sa; struct sigaction sa;
int i = 0;
/* /* Determine the maximum number of possible file descriptors. */
* Allocate table based on the maximum number of if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
* file descriptors. fprintf(stderr, "library initialization failed - "
*/ "unable to get max # of allocated fds\n");
getrlimit(RLIMIT_NOFILE, &nbr_files); abort();
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) { if (fdTable == NULL) {
fprintf(stderr, "library initialization failed - " fprintf(stderr, "library initialization failed - "
"unable to allocate file descriptor table - out of memory"); "unable to allocate file descriptor table - out of memory");
abort(); 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();
}
} }
/* /*
...@@ -106,15 +158,57 @@ static void __attribute((constructor)) init() { ...@@ -106,15 +158,57 @@ static void __attribute((constructor)) init() {
} }
/* /*
* Return the fd table for this fd or NULL is fd out * Return the fd table for this fd.
* of range.
*/ */
static inline fdEntry_t *getFdEntry(int fd) static inline fdEntry_t *getFdEntry(int fd)
{ {
if (fd < 0 || fd >= fdCount) { fdEntry_t* result = NULL;
if (fd < 0) {
return NULL; 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) {
/* fd is in base table. */
assert(fd < fdTableLen);
result = &fdTable[fd];
} else {
/* fd is in overflow table. */
const int indexInOverflowTable = fd - fdTableMaxSize;
const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
fdEntry_t* slab = NULL;
assert(rootindex < fdOverflowTableLen);
assert(slabindex < fdOverflowTableSlabSize);
pthread_mutex_lock(&fdOverflowTableLock);
/* Allocate new slab in overflow table if needed */
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 overflow"
" table slab - 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);
slab = fdOverflowTable[rootindex];
result = &slab[slabindex];
}
return result;
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册