From 905ca77c9ed0edac993c0f9bd9dac36253d96dd5 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Wed, 1 Nov 2006 18:33:50 +0000 Subject: test 518 is all about testing libcurl functionality when more than FD_SETSIZE file descriptors are open. This means that if for any reason we are not able to open more than FD_SETSIZE file descriptors then test 518 should not be run. test 537 is all about testing libcurl functionality when the system has nearly exhausted the number of free file descriptors. Test 537 will try to run with very few free file descriptors. --- tests/libtest/Makefile.am | 7 +- tests/libtest/lib518.c | 325 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 276 insertions(+), 56 deletions(-) (limited to 'tests/libtest') diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am index f7f901c80..eb936eb48 100644 --- a/tests/libtest/Makefile.am +++ b/tests/libtest/Makefile.am @@ -42,7 +42,7 @@ SUPPORTFILES = first.c test.h noinst_PROGRAMS = lib500 lib501 lib502 lib503 lib504 lib505 lib506 \ lib507 lib508 lib509 lib510 lib511 lib512 lib513 lib514 lib515 lib516 \ lib517 lib518 lib519 lib520 lib521 lib523 lib524 lib525 lib526 lib527 \ - lib529 lib530 lib532 lib533 lib536 + lib529 lib530 lib532 lib533 lib536 lib537 # Dependencies (may need to be overriden) LDADD = $(LIBDIR)/libcurl.la @@ -103,6 +103,7 @@ lib517_SOURCES = lib517.c $(SUPPORTFILES) lib517_DEPENDENCIES = $(DEPENDENCIES) lib518_SOURCES = lib518.c $(SUPPORTFILES) +lib518_CFLAGS = -DLIB518 lib518_DEPENDENCIES = $(DEPENDENCIES) lib519_SOURCES = lib519.c $(SUPPORTFILES) @@ -149,3 +150,7 @@ lib533_DEPENDENCIES = $(DEPENDENCIES) lib536_SOURCES = lib536.c $(SUPPORTFILES) lib536_DEPENDENCIES = $(DEPENDENCIES) +lib537_SOURCES = lib518.c $(SUPPORTFILES) +lib537_CFLAGS = -DLIB537 +lib537_DEPENDENCIES = $(DEPENDENCIES) + diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c index 875ddc206..bb09f0ffc 100644 --- a/tests/libtest/lib518.c +++ b/tests/libtest/lib518.c @@ -8,6 +8,10 @@ * $Id$ */ +/* + * This source code is used for lib518 and lib537. + */ + #include "test.h" #ifdef HAVE_SYS_TYPES_H @@ -35,13 +39,21 @@ #include #endif -#ifndef FD_SETSIZE +#if defined(LIB518) && !defined(FD_SETSIZE) #error "this test requires FD_SETSIZE" #endif +#ifdef LIB518 #define SAFETY_MARGIN 16 #define NUM_OPEN (FD_SETSIZE + 10) #define NUM_NEEDED (NUM_OPEN + SAFETY_MARGIN) +#endif + +#ifdef LIB537 +#define SAFETY_MARGIN 5 +#endif + +#define MEMCHUNK_NITEMS 32000 #if defined(WIN32) || defined(_WIN32) || defined(MSDOS) #define DEV_NULL "NUL" @@ -53,6 +65,7 @@ static int *fd = NULL; static struct rlimit num_open; +static char msgbuff[256]; /* * our_errno() returns the NOT *socket-related* errno (or equivalent) @@ -68,6 +81,15 @@ static int our_errno(void) #endif } +static void store_errmsg(const char *msg, int err) +{ + if (!err) + snprintf(msgbuff, sizeof(msgbuff), "%s", msg); + else + snprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", + msg, err, strerror(err)); +} + static void close_file_descriptors(void) { fprintf(stderr, "closing file descriptors\n"); @@ -82,9 +104,16 @@ static void close_file_descriptors(void) static int rlimit(int keep_open) { +#ifdef LIB537 + int *tmpfd; +#endif + int i; + int *memchunk = NULL; char *fmt; struct rlimit rl; - char strbuff[81]; + char strbuff[256]; + char strbuff1[81]; + char strbuff2[81]; char fmt_u[] = "%u"; char fmt_lu[] = "%lu"; #ifdef HAVE_LONGLONG @@ -99,8 +128,8 @@ static int rlimit(int keep_open) /* get initial open file limits */ if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { - fprintf(stderr, "warning: getrlimit: failed to get RLIMIT_NOFILE " - "with errno %d\n", our_errno()); + store_errmsg("getrlimit() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); return -1; } @@ -112,7 +141,7 @@ static int rlimit(int keep_open) else #endif sprintf(strbuff, fmt, rl.rlim_cur); - fprintf(stderr, "initial SOFT_LIMIT: %s\n", strbuff); + fprintf(stderr, "initial soft limit: %s\n", strbuff); #ifdef RLIM_INFINITY if (rl.rlim_max == RLIM_INFINITY) @@ -120,21 +149,31 @@ static int rlimit(int keep_open) else #endif sprintf(strbuff, fmt, rl.rlim_max); - fprintf(stderr, "initial HARD_LIMIT: %s\n", strbuff); + fprintf(stderr, "initial hard limit: %s\n", strbuff); +#ifdef LIB518 /* 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); +#endif - /* increase soft limit up to hard limit if different */ + /* + * if soft limit and hard limit are different we ask the + * system to raise soft limit all the way up to the hard + * limit. Due to some other system limit the soft limit + * might not be raised up to the hard limit. So from this + * point the resulting soft limit is our limit. Trying to + * open more than soft limit file descriptors will fail. + */ if (rl.rlim_cur != rl.rlim_max) { + fprintf(stderr, "raising soft limit up to hard limit\n"); 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()); + store_errmsg("setrlimit() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); return -2; } } @@ -142,19 +181,11 @@ static int rlimit(int keep_open) /* 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()); + store_errmsg("getrlimit() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); 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 @@ -163,7 +194,7 @@ static int rlimit(int keep_open) else #endif sprintf(strbuff, fmt, rl.rlim_cur); - fprintf(stderr, "current SOFT_LIMIT: %s\n", strbuff); + fprintf(stderr, "current soft limit: %s\n", strbuff); #ifdef RLIM_INFINITY if (rl.rlim_max == RLIM_INFINITY) @@ -171,51 +202,153 @@ static int rlimit(int keep_open) else #endif sprintf(strbuff, fmt, rl.rlim_max); - fprintf(stderr, "current HARD_LIMIT: %s\n", strbuff); + fprintf(stderr, "current hard limit: %s\n", strbuff); + + /* + * test 518 is all about testing libcurl functionality + * when more than FD_SETSIZE file descriptors are open. + * This means that if for any reason we are not able to + * open more than FD_SETSIZE file descriptors then test + * 518 should not be run. + * + * test 537 is all about testing libcurl functionality + * when the system has nearly exhausted the number of + * free file descriptors. Test 537 will try to run with + * very few free file descriptors. + */ - /* - ** 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. - */ +#ifdef LIB518 + + /* verify that soft limit is higher than FD_SETSIZE */ num_open.rlim_cur = FD_SETSIZE; + + if ((rl.rlim_cur > 0) && +#ifdef RLIM_INFINITY + (rl.rlim_cur != RLIM_INFINITY) && +#endif + (rl.rlim_cur <= num_open.rlim_cur)) { + sprintf(strbuff2, fmt, rl.rlim_cur); + sprintf(strbuff1, fmt, num_open.rlim_cur); + snprintf(strbuff, sizeof(strbuff), "system does not support opening %s " + "files, soft limit is %s", strbuff1, strbuff2); + store_errmsg(strbuff, 0); + fprintf(stderr, "%s\n", msgbuff); + return -4; + } + + /* + * verify that soft limit is higher than NUM_OPEN, + * number of file descriptors we would try to open + */ + + num_open.rlim_cur = NUM_OPEN; + + if ((rl.rlim_cur > 0) && +#ifdef RLIM_INFINITY + (rl.rlim_cur != RLIM_INFINITY) && +#endif + (rl.rlim_cur <= num_open.rlim_cur)) { + sprintf(strbuff2, fmt, rl.rlim_cur); + sprintf(strbuff1, fmt, num_open.rlim_cur); + snprintf(strbuff, sizeof(strbuff), "system does not support opening %s " + "files, soft limit is %s", strbuff1, strbuff2); + store_errmsg(strbuff, 0); + fprintf(stderr, "%s\n", msgbuff); + return -5; + } + + /* + * verify that soft limit is higher than NUM_NEEDED, + * number of file descriptors we would try to open + * plus SAFETY_MARGIN to not exhaust file pool + */ + + num_open.rlim_cur = NUM_NEEDED; + + if ((rl.rlim_cur > 0) && +#ifdef RLIM_INFINITY + (rl.rlim_cur != RLIM_INFINITY) && +#endif + (rl.rlim_cur <= num_open.rlim_cur)) { + sprintf(strbuff2, fmt, rl.rlim_cur); + sprintf(strbuff1, fmt, num_open.rlim_cur); + snprintf(strbuff, sizeof(strbuff), "system does not support opening %s " + "files, soft limit is %s", strbuff1, strbuff2); + store_errmsg(strbuff, 0); + fprintf(stderr, "%s\n", msgbuff); + return -6; + } + +#endif /* LIB518 */ + + /* + * reserve a chunk of memory before opening file descriptors to + * avoid a low memory condition once the file descriptors are + * open. System conditions that could make the test fail should + * be addressed in the precheck phase. This chunk of memory shall + * be always free()ed before exiting the rlimit() function so + * that it becomes available to the test. + */ + + memchunk = malloc(sizeof(*memchunk) * MEMCHUNK_NITEMS); + if (!memchunk) { + store_errmsg("memchunk, malloc() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); + return -7; + } + + /* initialize it to fight lazy allocation */ + + for (i = 0; i < MEMCHUNK_NITEMS; i++) + memchunk[i] = -1; + + /* set the number of file descriptors we will try to open to ... */ + +#ifdef LIB518 + /* NUM_OPEN */ num_open.rlim_max = NUM_OPEN; - if (num_open.rlim_cur > num_open.rlim_max) - num_open.rlim_max = num_open.rlim_cur; +#endif +#ifdef LIB537 #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; - } + /* soft limit minus 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); + else { + /* biggest file descriptor array size */ + num_open.rlim_max = ((size_t)-1) / sizeof(*fd); + } +#endif /* LIB537 */ /* 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); + sprintf(strbuff1, fmt, num_open.rlim_max); + snprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s " + "file descriptors, would overflow size_t", strbuff1); + store_errmsg(strbuff, 0); + fprintf(stderr, "%s\n", msgbuff); + free(memchunk); + return -8; } + 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; + store_errmsg("fd, malloc() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); + free(memchunk); + return -9; } - /* initialize fighting lazy allocation */ + /* initialize it to fight lazy allocation */ for (num_open.rlim_cur = 0; num_open.rlim_cur < num_open.rlim_max; @@ -223,40 +356,120 @@ static int rlimit(int keep_open) fd[num_open.rlim_cur] = -1; sprintf(strbuff, fmt, num_open.rlim_max); - fprintf(stderr, "opening %s file descriptors\n", strbuff); + fprintf(stderr, "trying to open %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()); + snprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL); + store_errmsg(strbuff, our_errno()); + fprintf(stderr, "%s\n", msgbuff); free(fd); fd = NULL; - return -5; + free(memchunk); + return -10; } /* create a bunch of file descriptors */ + +#ifdef LIB518 + 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()); + + fd[num_open.rlim_cur] = -1; + + sprintf(strbuff1, fmt, num_open.rlim_cur); + snprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1); + store_errmsg(strbuff, our_errno()); + fprintf(stderr, "%s\n", msgbuff); + + fprintf(stderr, "closing file descriptors\n"); for (num_open.rlim_cur = 0; fd[num_open.rlim_cur] >= 0; num_open.rlim_cur++) close(fd[num_open.rlim_cur]); + fprintf(stderr, "file descriptors closed\n"); free(fd); fd = NULL; - return -6; + free(memchunk); + return -11; + + } + + } + +#endif /* LIB518 */ + +#ifdef LIB537 + + 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) { + + fd[num_open.rlim_cur] = -1; + + sprintf(strbuff1, fmt, num_open.rlim_cur); + snprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1); + fprintf(stderr, "%s\n", strbuff); + + sprintf(strbuff1, fmt, num_open.rlim_cur + 2); + snprintf(strbuff, sizeof(strbuff), "system does not support opening " + "more than %s files" , strbuff1); + fprintf(stderr, "%s\n", strbuff); + + num_open.rlim_max = num_open.rlim_cur + 2 - SAFETY_MARGIN; + + num_open.rlim_cur -= num_open.rlim_max; + sprintf(strbuff1, fmt, num_open.rlim_cur); + snprintf(strbuff, sizeof(strbuff), "closing %s files", strbuff1); + fprintf(stderr, "%s\n", strbuff); + + for (num_open.rlim_cur = num_open.rlim_max; + fd[num_open.rlim_cur] >= 0; + num_open.rlim_cur++) { + close(fd[num_open.rlim_cur]); + fd[num_open.rlim_cur] = -1; + } + + sprintf(strbuff, fmt, num_open.rlim_max); + fprintf(stderr, "shrinking array for %s file descriptors\n", strbuff); + + tmpfd = realloc(fd, sizeof(*fd) * (size_t)(num_open.rlim_max)); + if (!tmpfd) { + snprintf(strbuff, sizeof(strbuff), "fd, realloc() failed, " + "errno %d, %s", our_errno(), strerror(our_errno())); + fprintf(stderr, "%s\n", strbuff); + } + else { + fd = tmpfd; + tmpfd = NULL; + } + } + } +#endif /* LIB537 */ + sprintf(strbuff, fmt, num_open.rlim_max); fprintf(stderr, "%s file descriptors open\n", strbuff); + /* free the chunk of memory we were reserving so that it + becomes becomes available to the test */ + + free(memchunk); + /* close file descriptors unless instructed to keep them */ if (!keep_open) { close_file_descriptors(); @@ -274,7 +487,7 @@ int test(char *URL) /* 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"); + fprintf(stdout, "rlimit problem: %s\n", msgbuff); return 1; } return 0; /* sure, run this! */ @@ -286,8 +499,10 @@ int test(char *URL) return TEST_ERR_MAJOR_BAD; } - /* run the test with more than FD_SETSIZE or max allowed open - file descriptors and close them all once the test is over */ + fprintf(stderr, "running test...\n"); + + /* run the test with the bunch of open file descriptors + and close them all once the test is over */ if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { fprintf(stderr, "curl_global_init() failed\n"); -- cgit v1.2.3