[LTP] [PATCH 2/2] [mtest06] Rewrite mmap1 to use new library

vkabatov@redhat.com vkabatov@redhat.com
Fri Nov 3 19:59:41 CET 2017


From: Veronika Kabatova <vkabatov@redhat.com>

* Use new tst_test framework
* Use safe macros
* Simplify signal handler && don't exit from it
* Wait for threads to finish before exiting the test function

Signed-off-by: Veronika Kabatova <vkabatov@redhat.com>
---
 testcases/kernel/mem/mtest06/mmap1.c | 381 +++++++++++++----------------------
 1 file changed, 144 insertions(+), 237 deletions(-)

diff --git a/testcases/kernel/mem/mtest06/mmap1.c b/testcases/kernel/mem/mtest06/mmap1.c
index 38f9ad793..cf01a3487 100644
--- a/testcases/kernel/mem/mtest06/mmap1.c
+++ b/testcases/kernel/mem/mtest06/mmap1.c
@@ -20,8 +20,7 @@
 /* the GNU General Public License for more details.			      */
 /*									      */
 /* You should have received a copy of the GNU General Public License	      */
-/* along with this program;  if not, write to the Free Software		      */
-/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
+/* along with this program;  if not, see <http://www.gnu.org/licenses/>.      */
 /*									      */
 /******************************************************************************/
 /******************************************************************************/
@@ -36,82 +35,116 @@
 /*	        read must be a success between map and unmap of the region.   */
 /*									      */
 /******************************************************************************/
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/mman.h>
+#include <pthread.h>
 #include <sched.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <sys/wait.h>
 #include <setjmp.h>
-#include <pthread.h>
-#include <signal.h>
-#include <string.h>
-#include "test.h"
-#include "safe_macros.h"
-
-#define DISTANT_MMAP_SIZE (64*1024*1024)
-#define OPT_MISSING(prog, opt) do { \
-	fprintf(stderr, "%s: option -%c ", prog, opt); \
-        fprintf(stderr, "requires an argument\n"); \
-	usage(prog); \
-} while (0)
-
-static int verbose_print = 0;
+#include <stdlib.h>
+#include "tst_safe_pthread.h"
+#include "tst_test.h"
+
+#define DISTANT_MMAP_SIZE (64 * 1024 * 1024)
+
+static long file_size = 1024;
+static long num_iter = 1000;
+static float exec_time = 24;
+
+static char *opt_verbose_print;
+static char *opt_file_size;
+static char *opt_num_iter;
+static char *opt_exec_time;
+
 static char *volatile map_address;
 static jmp_buf jmpbuf;
 static sig_atomic_t volatile active_map;
+static sig_atomic_t volatile test_end;
 static void *distant_area;
 static pthread_mutex_t thread_lock = PTHREAD_MUTEX_INITIALIZER;
 
-char *TCID = "mmap1";
-int TST_TOTAL = 1;
-
 static void sig_handler(int signal, siginfo_t * info, void *ut)
 {
 	switch (signal) {
-	case SIGALRM:
-		tst_resm(TPASS, "Test ended, success");
-		_exit(TPASS);
 	case SIGSEGV:
 		if (active_map) {
-			tst_resm(TINFO, "[%lu] Unexpected page fault at %p",
+			tst_res(TINFO, "[%lu] Unexpected page fault at %p",
 				 pthread_self(), info->si_addr);
-			_exit(TFAIL);
+			test_end = signal;
+			break;
 		}
 		longjmp(jmpbuf, 1);
 		break;
 	default:
-		fprintf(stderr, "Unexpected signal - %d --- exiting\n", signal);
-		_exit(TBROK);
+		test_end = signal;
+		break;
 	}
 }
 
-int mkfile(int size)
+static struct tst_option mmap1_options[] = {
+	{"l:", &opt_num_iter, "Number of mmap/write/unmap loops, default: 1000"},
+	{"s:", &opt_file_size, "Size of the file to be mapped, default: 1024 bytes"},
+	{"x:", &opt_exec_time, "Test execution time, default: 24 hours"},
+	{"v", &opt_verbose_print, "Verbose output, default: quiet"},
+	{NULL, NULL, NULL}
+};
+
+static void mmap1_setup(void)
 {
-	char template[] = "/tmp/ashfileXXXXXX";
-	int fd, i;
+	int i;
+	int siglist[] = {SIGSEGV, SIGALRM, -1};
+	struct sigaction sigptr;
 
-	if ((fd = mkstemp(template)) == -1)
-		tst_brkm(TBROK | TERRNO, NULL, "mkstemp() failed");
+	if (tst_parse_long(opt_file_size, &file_size, 1, LONG_MAX))
+		tst_brk(TBROK, "Invalid file size: %s", opt_file_size);
+	if (tst_parse_long(opt_num_iter, &num_iter, 1, LONG_MAX))
+		tst_brk(TBROK, "Invalid number of interations: %s",
+				opt_num_iter);
+	if (tst_parse_float(opt_exec_time, &exec_time, 0.0005, INT_MAX))
+		tst_brk(TBROK, "Invalid execution time: %s", opt_exec_time);
+
+	if (opt_verbose_print)
+		tst_res(TINFO, "Input parameters are: File size: %ld; "
+			 "Scheduled to run: %lf hours; "
+			 "Number of mmap/write/read: %ld",
+			 file_size, exec_time, num_iter);
+
+	tst_set_timeout(exec_time * 3600 + 300);
+
+	sigptr.sa_sigaction = sig_handler;
+	sigptr.sa_flags = SA_SIGINFO | SA_NODEFER;
+	sigemptyset(&sigptr.sa_mask);
 
-	unlink(template);
+	for (i = 0; siglist[i] != -1; i++) {
+		if (sigaction(siglist[i], &sigptr, NULL) == -1) {
+			tst_brk(TBROK | TERRNO, "could not set handler for %s",
+					tst_strsig(siglist[i]));
+		}
+	}
 
-	for (i = 0; i < size; i++)
-		if (write(fd, "a", 1) == -1)
-			tst_brkm(TBROK | TERRNO, NULL, "write() failed");
+	/* We don't want other mmap calls to map into same area as is
+	 * used for test (mmap_address). The test expects read to return
+	 * test pattern or read must fail with SIGSEGV. Find an area
+	 * that we can use, which is unlikely to be chosen for other
+	 * mmap calls. */
+	distant_area = SAFE_MMAP(NULL, DISTANT_MMAP_SIZE,
+			PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE,
+			-1, 0);
+	SAFE_MUNMAP(distant_area, (size_t)DISTANT_MMAP_SIZE);
+	distant_area += DISTANT_MMAP_SIZE / 2;
+}
+
+static int mkfile(int size)
+{
+	char template[] = "ashfileXXXXXX";
+	int fd, i;
 
-	if (write(fd, "\0", 1) == -1)
-		tst_brkm(TBROK | TERRNO, NULL, "write() failed");
+	if ((fd = mkstemp(template)) == -1)
+		tst_brk(TBROK | TERRNO, "mkstemp() failed");
+	SAFE_UNLINK(template);
 
-	if (fsync(fd) == -1)
-		tst_brkm(TBROK | TERRNO, NULL, "fsync() failed");
+	for (i = 0; i < size; i++) {
+		SAFE_WRITE(1, fd, "a", 1);
+	}
+	SAFE_WRITE(1, fd, "\0", 1);
+	SAFE_FSYNC(fd);
 
 	return fd;
 }
@@ -119,14 +152,13 @@ int mkfile(int size)
 void *map_write_unmap(void *ptr)
 {
 	long *args = ptr;
-	long i;
-	int j;
+	long i, j;
 
-	tst_resm(TINFO, "[%lu] - map, change contents, unmap files %ld times",
+	tst_res(TINFO, "[%lu] - map, change contents, unmap files %ld times",
 		 pthread_self(), args[2]);
 
-	if (verbose_print)
-		tst_resm(TINFO, "map_write_unmap() arguments are: "
+	if (opt_verbose_print)
+		tst_res(TINFO, "map_write_unmap() arguments are: "
 			 "fd - arg[0]: %ld; "
 			 "size of file - arg[1]: %ld; "
 			 "num of map/write/unmap - arg[2]: %ld",
@@ -134,19 +166,14 @@ void *map_write_unmap(void *ptr)
 
 	for (i = 0; i < args[2]; i++) {
 		pthread_mutex_lock(&thread_lock);
-		map_address = mmap(distant_area, (size_t) args[1],
-			PROT_WRITE | PROT_READ, MAP_SHARED, (int)args[0], 0);
-
-		if (map_address == (void *)-1) {
-			perror("map_write_unmap(): mmap()");
-			pthread_mutex_unlock(&thread_lock);
-			pthread_exit((void *)1);
-		}
+		map_address = SAFE_MMAP(distant_area, (size_t)args[1],
+				PROT_WRITE | PROT_READ, MAP_SHARED,
+				(int)args[0], 0);
 		active_map = 1;
 		pthread_mutex_unlock(&thread_lock);
 
-		if (verbose_print)
-			tst_resm(TINFO, "map address = %p", map_address);
+		if (opt_verbose_print)
+			tst_res(TINFO, "map address = %p", map_address);
 
 		j = 0;
 		while (j < args[1]) {
@@ -159,19 +186,15 @@ void *map_write_unmap(void *ptr)
 				sched_yield();
 		}
 
-		if (verbose_print)
-			tst_resm(TINFO,
-				 "[%ld] times done: of total [%ld] iterations, "
-				 "map_write_unmap():memset() content of memory = %s",
-				 i, args[2], (char *)map_address);
+		if (opt_verbose_print)
+			tst_res(TINFO, "[%ld] times done: of total [%ld] "
+					"iterations, map_write_unmap(), "
+					"contents of memory: %s",
+					i, args[2], map_address);
 
 		pthread_mutex_lock(&thread_lock);
 		active_map = 0;
-		if (munmap(map_address, (size_t) args[1]) == -1) {
-			perror("map_write_unmap(): mmap()");
-			pthread_mutex_unlock(&thread_lock);
-			pthread_exit((void *)1);
-		}
+		SAFE_MUNMAP(map_address, (size_t) args[1]);
 		pthread_mutex_unlock(&thread_lock);
 	}
 
@@ -180,36 +203,35 @@ void *map_write_unmap(void *ptr)
 
 void *read_mem(void *ptr)
 {
-	long i;
 	long *args = ptr;
-	int j;
+	long i, j;
 
-	tst_resm(TINFO, "[%lu] - read contents of memory %p %ld times",
+	tst_res(TINFO, "[%lu] - read contents of memory %p %ld times",
 		 pthread_self(), map_address, args[2]);
 
-	if (verbose_print)
-		tst_resm(TINFO, "read_mem() arguments are: "
+	if (opt_verbose_print)
+		tst_res(TINFO, "read_mem() arguments are: "
 			 "number of reads to be performed - arg[2]: %ld; "
 			 "read from address %p", args[2], map_address);
 
 	for (i = 0; i < args[2]; i++) {
-		if (verbose_print)
-			tst_resm(TINFO, "read_mem() in while loop %ld times "
+		if (opt_verbose_print)
+			tst_res(TINFO, "read_mem() in while loop %ld times "
 				 "to go %ld times", i, args[2]);
 
 		if (setjmp(jmpbuf) == 1) {
 			pthread_mutex_unlock(&thread_lock);
-			if (verbose_print)
-				tst_resm(TINFO, "page fault occurred due to "
+			if (opt_verbose_print)
+				tst_res(TINFO, "page fault occurred due to "
 					 "a read after an unmap");
 		} else {
-			if (verbose_print) {
+			if (opt_verbose_print) {
 				pthread_mutex_lock(&thread_lock);
-				tst_resm(TINFO,
-					 "read_mem(): content of memory: %s",
-					 (char *)map_address);
+				tst_res(TINFO, "read_mem(): contents of "
+						"memory: %s", map_address);
 				pthread_mutex_unlock(&thread_lock);
 			}
+
 			for (j = 0; j < args[1]; j++) {
 				pthread_mutex_lock(&thread_lock);
 				if (map_address[j] != 'a') {
@@ -222,175 +244,60 @@ void *read_mem(void *ptr)
 			}
 		}
 	}
-
 	pthread_exit(NULL);
 }
 
-static void usage(char *progname)
-{
-	fprintf(stderr, "Usage: %s -d -l -s -v -x\n"
-		"\t -h help, usage message.\n"
-		"\t -l number of mmap/write/unmap     default: 1000\n"
-		"\t -s size of the file to be mmapped default: 1024 bytes\n"
-		"\t -v print more info.               default: quiet\n"
-		"\t -x test execution time            default: 24 Hrs\n",
-		progname);
-
-	exit(-1);
-}
-
-struct signal_info {
-	int signum;
-	char *signame;
-};
-
-static struct signal_info sig_info[] = {
-	{SIGHUP, "SIGHUP"},
-	{SIGINT, "SIGINT"},
-	{SIGQUIT, "SIGQUIT"},
-	{SIGABRT, "SIGABRT"},
-	{SIGBUS, "SIGBUS"},
-	{SIGSEGV, "SIGSEGV"},
-	{SIGALRM, "SIGALRM"},
-	{SIGUSR1, "SIGUSR1"},
-	{SIGUSR2, "SIGUSR2"},
-	{-1, "ENDSIG"}
-};
-
-int main(int argc, char **argv)
+static void test_mmap1(void)
 {
-	int c, i;
-	int file_size;
-	int num_iter;
-	double exec_time;
-	int fd;
+	int i, fd;
 	void *status;
 	pthread_t thid[2];
 	long chld_args[3];
-	extern char *optarg;
-	struct sigaction sigptr;
-	int ret;
-
-	/* set up the default values */
-	file_size = 1024;
-	num_iter = 1000;
-	exec_time = 24;
-
-	while ((c = getopt(argc, argv, "hvl:s:x:")) != -1) {
-		switch (c) {
-		case 'h':
-			usage(argv[0]);
-			break;
-		case 'l':
-			if ((num_iter = atoi(optarg)) == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (num_iter < 0)
-				printf
-				    ("WARNING: bad argument. Using default %d\n",
-				     (num_iter = 1000));
-			break;
-		case 's':
-			if ((file_size = atoi(optarg)) == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (file_size < 0)
-				printf
-				    ("WARNING: bad argument. Using default %d\n",
-				     (file_size = 1024));
-			break;
-		case 'v':
-			verbose_print = 1;
-			break;
-		case 'x':
-			exec_time = atof(optarg);
-			if (exec_time == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (exec_time < 0)
-				printf
-				    ("WARNING: bad argument. Using default %.0f\n",
-				     (exec_time = 24));
-			break;
-		default:
-			usage(argv[0]);
-			break;
-		}
-	}
-
-	/* We don't want other mmap calls to map into same area as is
-	 * used for test (mmap_address). The test expects read to return
-	 * test pattern or read must fail with SIGSEGV. Find an area
-	 * that we can use, which is unlikely to be chosen for other
-	 * mmap calls. */
-	distant_area = mmap(0, DISTANT_MMAP_SIZE, PROT_WRITE | PROT_READ,
-		MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
-	if (distant_area == (void *)-1)
-		tst_brkm(TBROK | TERRNO, NULL, "distant_area: mmap()");
-	SAFE_MUNMAP(NULL, distant_area, (size_t)DISTANT_MMAP_SIZE);
-	distant_area += DISTANT_MMAP_SIZE / 2;
-
-	if (verbose_print)
-		tst_resm(TINFO, "Input parameters are: File size:  %d; "
-			 "Scheduled to run:  %lf hours; "
-			 "Number of mmap/write/read:  %d",
-			 file_size, exec_time, num_iter);
 
+	test_end = 0;
 	alarm(exec_time * 3600);
 
-	/* Do not mask SIGSEGV, as we are interested in handling it. */
-	sigptr.sa_sigaction = sig_handler;
-	sigfillset(&sigptr.sa_mask);
-	sigdelset(&sigptr.sa_mask, SIGSEGV);
-	sigptr.sa_flags = SA_SIGINFO | SA_NODEFER;
-
-	for (i = 0; sig_info[i].signum != -1; i++) {
-		if (sigaction(sig_info[i].signum, &sigptr, NULL) == -1) {
-			perror("man(): sigaction()");
-			fprintf(stderr,
-				"could not set handler for %s, errno = %d\n",
-				sig_info[i].signame, errno);
-			exit(-1);
-		}
-	}
-
 	for (;;) {
 		if ((fd = mkfile(file_size)) == -1)
-			tst_brkm(TBROK, NULL,
-				 "main(): mkfile(): Failed to create temp file");
-
-		if (verbose_print)
-			tst_resm(TINFO, "Tmp file created");
+			tst_brk(TBROK, "main(): mkfile(): "
+					"Failed to create temp file");
+		if (opt_verbose_print)
+			tst_res(TINFO, "Tmp file created");
 
 		chld_args[0] = fd;
 		chld_args[1] = file_size;
 		chld_args[2] = num_iter;
 
-		if ((ret =
-		     pthread_create(&thid[0], NULL, map_write_unmap,
-				    chld_args)))
-			tst_brkm(TBROK, NULL, "main(): pthread_create(): %s",
-				 strerror(ret));
-
-		tst_resm(TINFO, "created writing thread[%lu]", thid[0]);
-
-		if ((ret = pthread_create(&thid[1], NULL, read_mem, chld_args)))
-			tst_brkm(TBROK, NULL, "main(): pthread_create(): %s",
-				 strerror(ret));
-
-		tst_resm(TINFO, "created reading thread[%lu]", thid[1]);
+		SAFE_PTHREAD_CREATE(&thid[0], NULL, map_write_unmap, chld_args);
+		tst_res(TINFO, "created writing thread[%lu]", thid[0]);
+		SAFE_PTHREAD_CREATE(&thid[1], NULL, read_mem, chld_args);
+		tst_res(TINFO, "created reading thread[%lu]", thid[1]);
 
 		for (i = 0; i < 2; i++) {
-			if ((ret = pthread_join(thid[i], &status)))
-				tst_brkm(TBROK, NULL,
-					 "main(): pthread_join(): %s",
-					 strerror(ret));
-
+			SAFE_PTHREAD_JOIN(thid[i], &status);
 			if (status)
-				tst_brkm(TFAIL, NULL,
-					 "thread [%lu] - process exited "
+				tst_res(TFAIL, "thread [%lu] - process exited "
 					 "with %ld", thid[i], (long)status);
 		}
-
-		close(fd);
+		SAFE_CLOSE(fd);
+
+		switch (test_end) {
+		case 0:
+			continue;
+		case SIGALRM:
+			tst_res(TPASS, "Test ended, success");
+			return;
+		default:
+			tst_res(TFAIL, "Test failed with unexpected signal %s",
+					tst_strsig(test_end));
+			return;
+		}
 	}
-
-	exit(0);
 }
+
+static struct tst_test test = {
+	.test_all = test_mmap1,
+	.setup = mmap1_setup,
+	.options = mmap1_options,
+	.needs_tmpdir = 1,
+};
-- 
2.13.6



More information about the ltp mailing list