aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYang Tse <yangsita@gmail.com>2006-10-30 17:24:31 +0000
committerYang Tse <yangsita@gmail.com>2006-10-30 17:24:31 +0000
commitafcd9f1b1c403936a423e9b27d267bd4ad9286bd (patch)
tree527f6369aabc1ef567f9b7e92bce338625edc364
parent755ccbc468a8ebe99ac108d32e3dfb7fa8e0fad7 (diff)
Address some pitfalls in the rlimit() function check that were
preventing execution of this test on many platforms
-rw-r--r--tests/libtest/lib518.c214
1 files changed, 145 insertions, 69 deletions
diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c
index 1696651dc..e64ef7d59 100644
--- a/tests/libtest/lib518.c
+++ b/tests/libtest/lib518.c
@@ -39,8 +39,9 @@
#error "this test requires FD_SETSIZE"
#endif
+#define SAFETY_MARGIN 16
#define NUM_OPEN (FD_SETSIZE + 10)
-#define NUM_NEEDED (NUM_OPEN + 16)
+#define NUM_NEEDED (NUM_OPEN + SAFETY_MARGIN)
#if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
#define DEV_NULL "NUL"
@@ -50,7 +51,8 @@
#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
-static int fd[NUM_OPEN];
+static int *fd = NULL;
+static struct rlimit num_open;
/*
* our_errno() returns the NOT *socket-related* errno (or equivalent)
@@ -68,114 +70,185 @@ static int our_errno(void)
static void close_file_descriptors(void)
{
- int i;
-
- for (i = 0; i < NUM_OPEN; i++) {
- close(fd[i]);
- fd[i] = -1;
- }
+ for (num_open.rlim_cur = 0;
+ num_open.rlim_cur < num_open.rlim_max;
+ num_open.rlim_cur++)
+ close(fd[num_open.rlim_cur]);
+ free(fd);
+ fd = NULL;
}
static int rlimit(int keep_open)
{
- int i;
+ char *fmt;
struct rlimit rl;
char strbuff[81];
- char fmt_d[] = "%d";
- char fmt_ld[] = "%ld";
- char fmt_lld[] = "%lld";
- char *fmt;
+ char fmt_u[] = "%u";
+ char fmt_lu[] = "%lu";
+#ifdef HAVE_LONGLONG
+ char fmt_llu[] = "%llu";
- if (sizeof(rl.rlim_max) < sizeof(long))
- fmt = fmt_d;
- else if (sizeof(rl.rlim_max) == sizeof(long))
- fmt = fmt_ld;
+ if (sizeof(rl.rlim_max) > sizeof(long))
+ fmt = fmt_llu;
else
- fmt = fmt_lld;
+#endif
+ fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu;
- fprintf(stderr, "NUM_OPEN: %d\n", NUM_OPEN);
- fprintf(stderr, "NUM_NEEDED: %d\n", NUM_NEEDED);
+ /* get initial open file limits */
- /* get open file limits */
if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
fprintf(stderr, "warning: getrlimit: failed to get RLIMIT_NOFILE "
"with errno %d\n", our_errno());
return -1;
}
- /* check that hard limit is high enough */
+ /* show initial open file limits */
+
#ifdef RLIM_INFINITY
- if (rl.rlim_max != RLIM_INFINITY)
+ if (rl.rlim_cur == RLIM_INFINITY)
+ strcpy(strbuff, "INFINITY");
+ else
#endif
- if ((rl.rlim_max > 0) && (rl.rlim_max < NUM_NEEDED)) {
- sprintf(strbuff, fmt, rl.rlim_max);
- fprintf(stderr, "warning: RLIMIT_NOFILE hard limit %s < %d\n",
- strbuff, NUM_NEEDED);
- return -2;
- }
+ sprintf(strbuff, fmt, rl.rlim_cur);
+ fprintf(stderr, "initial SOFT_LIMIT: %s\n", strbuff);
- /* increase soft limit if needed */
#ifdef RLIM_INFINITY
- if (rl.rlim_cur != RLIM_INFINITY)
-#endif
- if ((rl.rlim_cur > 0) && (rl.rlim_cur < NUM_NEEDED)) {
- rl.rlim_cur = NUM_NEEDED;
- if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
- fprintf(stderr, "warning: setrlimit: failed to set RLIMIT_NOFILE "
- "with errno %d\n", our_errno());
- return -3;
- }
- /* verify that it has been increased */
- if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
- fprintf(stderr, "warning: getrlimit: failed to get RLIMIT_NOFILE "
- "with errno %d\n", our_errno());
- return -4;
- }
- if ((rl.rlim_cur > 0) && (rl.rlim_cur < NUM_NEEDED)) {
- sprintf(strbuff, fmt, rl.rlim_cur);
- fprintf(stderr, "warning: RLIMIT_NOFILE soft limit %s < %d\n",
- strbuff, NUM_NEEDED);
- return -5;
- }
+ if (rl.rlim_max == RLIM_INFINITY)
+ strcpy(strbuff, "INFINITY");
+ else
+#endif
+ sprintf(strbuff, fmt, rl.rlim_max);
+ fprintf(stderr, "initial HARD_LIMIT: %s\n", strbuff);
+
+ /* show our constants */
+
+ fprintf(stderr, "test518 FD_SETSIZE: %d\n", FD_SETSIZE);
+ fprintf(stderr, "test518 NUM_OPEN : %d\n", NUM_OPEN);
+ fprintf(stderr, "test518 NUM_NEEDED: %d\n", NUM_NEEDED);
+
+ /* increase soft limit up to hard limit if different */
+
+ if (rl.rlim_cur != rl.rlim_max) {
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
+ fprintf(stderr, "warning: setrlimit: failed to set RLIMIT_NOFILE "
+ "with errno %d\n", our_errno());
+ return -2;
}
+ }
+
+ /* get current open file limits */
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
+ fprintf(stderr, "warning: getrlimit: failed to get RLIMIT_NOFILE "
+ "with errno %d\n", our_errno());
+ return -3;
+ }
+
+ /* if soft limit has not been increased all the way up to hard
+ limit, warn about it but continue since it may be high enough */
+
+ if (rl.rlim_cur != rl.rlim_max) {
+ fprintf(stderr, "warning: setrlimit: did not raise soft limit "
+ "up to hard limit\n");
+ }
+
+ /* show current open file limits */
#ifdef RLIM_INFINITY
if (rl.rlim_cur == RLIM_INFINITY)
- fprintf(stderr, "SOFT_LIMIT: INFINITY\n");
+ strcpy(strbuff, "INFINITY");
else
#endif
- {
sprintf(strbuff, fmt, rl.rlim_cur);
- fprintf(stderr, "SOFT_LIMIT: %s\n", strbuff);
- }
+ fprintf(stderr, "current SOFT_LIMIT: %s\n", strbuff);
#ifdef RLIM_INFINITY
if (rl.rlim_max == RLIM_INFINITY)
- fprintf(stderr, "HARD_LIMIT: INFINITY\n");
+ strcpy(strbuff, "INFINITY");
else
#endif
- {
sprintf(strbuff, fmt, rl.rlim_max);
- fprintf(stderr, "HARD_LIMIT: %s\n", strbuff);
+ fprintf(stderr, "current HARD_LIMIT: %s\n", strbuff);
+
+ /*
+ ** Our extreme test target is to open more than FD_SETSIZE files but
+ ** it could happen that it would exceed the limit of allowed open
+ ** files and we would not be able to test libcurl functionality. In
+ ** this case we will open the maximum allowed minus our safety margin,
+ ** which will run the test under this stress condition.
+ */
+
+ num_open.rlim_cur = FD_SETSIZE;
+ num_open.rlim_max = NUM_OPEN;
+ if (num_open.rlim_cur > num_open.rlim_max)
+ num_open.rlim_max = num_open.rlim_cur;
+
+#ifdef RLIM_INFINITY
+ if ((rl.rlim_cur > 0) && (rl.rlim_cur != RLIM_INFINITY)) {
+#else
+ if (rl.rlim_cur > 0) {
+#endif
+ if (num_open.rlim_max > rl.rlim_cur - SAFETY_MARGIN) {
+ num_open.rlim_max = rl.rlim_cur - SAFETY_MARGIN;
+ }
}
+ sprintf(strbuff, fmt, num_open.rlim_max);
+ fprintf(stderr, "allocating array for %s file descriptors\n", strbuff);
+
+ /* verify that we won't overflow size_t in malloc() */
+
+ if (num_open.rlim_max > ((size_t)-1) / sizeof(*fd)) {
+ fprintf(stderr, "is not possible, we would overflow size_t in malloc()\n");
+ num_open.rlim_max = ((size_t)-1) / sizeof(*fd);
+ sprintf(strbuff, fmt, num_open.rlim_max);
+ fprintf(stderr, "allocating array for %s file descriptors\n", strbuff);
+ }
+
+ fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max));
+ if (!fd) {
+ fprintf(stderr, "warning: memory allocation failed "
+ "with errno %d\n", our_errno());
+ return -4;
+ }
+
+ /* initialize fighting lazy allocation */
+
+ for (num_open.rlim_cur = 0;
+ num_open.rlim_cur < num_open.rlim_max;
+ num_open.rlim_cur++)
+ fd[num_open.rlim_cur] = -1;
+
+ sprintf(strbuff, fmt, num_open.rlim_max);
+ fprintf(stderr, "opening %s file descriptors\n", strbuff);
+
/* open a dummy descriptor */
fd[0] = open(DEV_NULL, O_RDONLY);
if (fd[0] < 0) {
fprintf(stderr, "open: failed to open %s "
"with errno %d\n", DEV_NULL, our_errno());
- return -6;
+ free(fd);
+ fd = NULL;
+ return -5;
}
/* create a bunch of file descriptors */
- for (i = 1; i < NUM_OPEN; i++) {
- fd[i] = dup(fd[0]);
- if (fd[i] < 0) {
- fprintf(stderr, "dup: attempt #%d failed "
- "with errno %d\n", i, our_errno());
- for (i--; i >= 0; i--)
- close(fd[i]);
- return -7;
+ for (num_open.rlim_cur = 1;
+ num_open.rlim_cur < num_open.rlim_max;
+ num_open.rlim_cur++) {
+ fd[num_open.rlim_cur] = dup(fd[0]);
+ if (fd[num_open.rlim_cur] < 0) {
+ sprintf(strbuff, fmt, num_open.rlim_cur);
+ fprintf(stderr, "dup: attempt #%s failed "
+ "with errno %d\n", strbuff, our_errno());
+ for (num_open.rlim_cur = 0;
+ fd[num_open.rlim_cur] >= 0;
+ num_open.rlim_cur++)
+ close(fd[num_open.rlim_cur]);
+ free(fd);
+ fd = NULL;
+ return -6;
}
}
@@ -195,15 +268,18 @@ int test(char *URL)
if(!strcmp(URL, "check")) {
/* used by the test script to ask if we can run this test or not */
if(rlimit(FALSE)) {
+ fprintf(stderr, "Previous condition prevents running this test\n");
printf("rlimit problems\n");
return 1;
}
return 0; /* sure, run this! */
}
- if(rlimit(TRUE))
+ if (rlimit(TRUE)) {
/* failure */
- return 100;
+ fprintf(stderr, "Previous condition aborts this test\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
/* now run the test with NUM_OPEN open file descriptors
and close them all once this test is over */