[LTP] [PATCH v2 1/4] mm: mallocstress: use new library and safe macros

Sandeep Patil sspatil@google.com
Tue Nov 14 03:11:15 CET 2017


Make necessary changes to the test to start using the new ltp library
api instead of being a standalong program.  Use appropriate SAFE_ macros
in the process to reduce the error check paths.

Signed-off-by: Sandeep Patil <sspatil@google.com>
---
v1->v2
------
- Refactored test to use new library as suggested by Jan and then use the appropriate
  safe macros that do not need cleanup functions


 testcases/kernel/mem/mtest07/mallocstress.c | 317 +++++++++-------------------
 1 file changed, 100 insertions(+), 217 deletions(-)

diff --git a/testcases/kernel/mem/mtest07/mallocstress.c b/testcases/kernel/mem/mtest07/mallocstress.c
index 9588fb495..0f495a6b3 100644
--- a/testcases/kernel/mem/mtest07/mallocstress.c
+++ b/testcases/kernel/mem/mtest07/mallocstress.c
@@ -73,36 +73,22 @@
 #include <sys/ipc.h>
 #include <sys/sem.h>
 
-#define MAXL    100		/* default number of loops to do malloc and free      */
-#define MAXT     60		/* default number of threads to create.               */
+#include "tst_test.h"
+#include "tst_safe_pthread.h"
 
-#ifdef DEBUG
-#define dprt(args)	printf args
-#else
-#define dprt(args)
-#endif
+/* Number of loops per-thread */
+#define NUM_LOOPS	100
 
-#define OPT_MISSING(prog, opt)   do{\
-			       fprintf(stderr, "%s: option -%c ", prog, opt); \
-                               fprintf(stderr, "requires an argument\n"); \
-                               usage(prog); \
-                                   } while (0)
-
-int num_loop = MAXL;		/* number of loops to perform                     */
-int semid;
+/* Number of threads to create */
+#define NUM_THREADS     60
 
 /* Define SPEW_SIGNALS to tickle thread_create bug (it fails if interrupted). */
 #define SPEW_SIGNALS
 
-/******************************************************************************/
-/*								 	      */
-/* Function:	my_yield						      */
-/*									      */
-/* Description:	Yield control to another thread.                              */
-/*              Generate a signal, too.                                       */
-/*									      */
-/******************************************************************************/
-static void my_yield()
+static pthread_t *thread_id;	/* Spawned thread */
+int semid;
+
+static void my_yield(void)
 {
 #ifdef SPEW_SIGNALS
 	/* usleep just happens to use signals in glibc at moment.
@@ -119,60 +105,32 @@ static void my_yield()
 #endif
 }
 
-/******************************************************************************/
-/*								 	      */
-/* Function:	usage							      */
-/*									      */
-/* Description:	Print the usage message.				      */
-/*									      */
-/* Input:	char *progname - name of this program                         */
-/*									      */
-/* Return:	exits with -1						      */
-/*									      */
-/******************************************************************************/
-static void usage(char *progname)
-{				/* name of this program                       */
-	fprintf(stderr,
-		"Usage: %s -d NUMDIR -f NUMFILES -h -t NUMTHRD\n"
-		"\t -h Help!\n"
-		"\t -l Number of loops:               Default: 1000\n"
-		"\t -t Number of threads to generate: Default: 30\n", progname);
-	exit(-1);
-}
-
-/******************************************************************************/
-/* Function:	allocate_free				                      */
-/*								              */
-/* Description:	This function does the allocation and free by calling malloc  */
-/*		and free fuctions. The size of the memory to be malloced is   */
-/*		determined by the caller of this function. The size can be    */
-/*		a number from the fibannoaci series, power of 2 or 3 or 5     */
-/*									      */
-/* Input:	int repeat - number of times the alloc/free is repeated.      */
-/*		int scheme  - 0 to 3; selects how fast memory size grows      */
-/*								              */
-/* Return:	1 on failure						      */
-/*		0 on success						      */
-/******************************************************************************/
-int allocate_free(int repeat,	/* number of times to repeat allocate/free    */
-		  int scheme)
-{				/* how fast to increase block size            */
+/*
+ * allocate_free() - Allocate and free test called per-thread
+ *
+ * @scheme: 0-3; selects how fast memory size grows
+ *
+ * This function does the allocation and free by calling malloc
+ * and free functions. The size of the memory to be malloced is
+ * determined by the caller of this function. The size can be
+ * a number from the fibannoaci series, power of 2 or 3 or 5
+ *
+ * Return:
+ *  0: success
+ *  1: failure
+ */
+int allocate_free(int scheme)
+{
 	int loop;
 	const int MAXPTRS = 50;	/* only 42 or so get used on 32 bit machine */
 
-	dprt(("pid[%d]: allocate_free: repeat %d, scheme %d\n", getpid(),
-	      repeat, scheme));
-
-	for (loop = 0; loop < repeat; loop++) {
-		size_t oldsize = 5;	/* remember size for fibannoci series     */
-		size_t size = sizeof(long);	/* size of next block in ptrs[]           */
-		long *ptrs[MAXPTRS];	/* the pointers allocated in this loop    */
-		int num_alloc;	/* number of elements in ptrs[] so far    */
+	for (loop = 0; loop < NUM_LOOPS; loop++) {
+		size_t oldsize = 5;
+		size_t size = sizeof(long);
+		long *ptrs[MAXPTRS];
+		int num_alloc;
 		int i;
 
-		dprt(("pid[%d]: allocate_free: loop %d of %d\n", getpid(), loop,
-		      repeat));
-
 		/* loop terminates in one of three ways:
 		 * 1. after MAXPTRS iterations
 		 * 2. if malloc fails
@@ -181,15 +139,11 @@ int allocate_free(int repeat,	/* number of times to repeat allocate/free    */
 		for (num_alloc = 0; num_alloc < MAXPTRS; num_alloc++) {
 			size_t newsize = 0;
 
-			dprt(("pid[%d]: loop %d/%d; num_alloc=%d; size=%u\n",
-			      getpid(), loop, repeat, num_alloc, size));
-
 			/* Malloc the next block */
 			ptrs[num_alloc] = malloc(size);
-			if (ptrs[num_alloc] == NULL) {
-				/* terminate loop if malloc couldn't give us the memory we asked for */
+			/* terminate loop if malloc fails */
+			if (!ptrs[num_alloc])
 				break;
-			}
 			ptrs[num_alloc][0] = num_alloc;
 
 			/* Increase size according to one of four schedules. */
@@ -219,10 +173,8 @@ int allocate_free(int repeat,	/* number of times to repeat allocate/free    */
 		}
 
 		for (i = 0; i < num_alloc; i++) {
-			dprt(("pid[%d]: freeing ptrs[i] %p\n", getpid(),
-			      ptrs[i]));
 			if (ptrs[i][0] != i) {
-				fprintf(stderr,
+				tst_res(TFAIL,
 					"pid[%d]: fail: bad sentinel value\n",
 					getpid());
 				return 1;
@@ -233,175 +185,106 @@ int allocate_free(int repeat,	/* number of times to repeat allocate/free    */
 
 		my_yield();
 	}
+
 	/* Success! */
 	return 0;
 }
 
-/******************************************************************************/
-/* Function:	alloc_mem				                      */
-/*								              */
-/* Description:	Decide how fast to increase block sizes, then call            */
-/*              allocate_free() to actually to the test.                      */
-/*								              */
-/* Input:	threadnum is the thread number, 0...N-1                       */
-/*              global num_loop is how many iterations to run                 */
-/*								              */
-/* Return:	pthread_exit -1	on failure				      */
-/*		pthread_exit  0 on success			              */
-/*								              */
-/******************************************************************************/
 void *alloc_mem(void *threadnum)
 {
 	struct sembuf sop[1];
+	int err;
+
+	/* waiting for other threads starting */
 	sop[0].sem_num = 0;
 	sop[0].sem_op = 0;
 	sop[0].sem_flg = 0;
-	/* waiting for other threads starting */
-	if (semop(semid, sop, 1) == -1) {
-		if (errno != EIDRM)
-			perror("semop");
+	TEST(semop(semid, sop, 1));
+	if (TEST_RETURN == -1 && TEST_ERRNO != EIDRM) {
+		tst_res(TBROK | TTERRNO,
+			"Thread [%d] failed to wait on semaphore",
+			(int)(uintptr_t)threadnum);
 		return (void *)-1;
 	}
 
 	/* thread N will use growth scheme N mod 4 */
-	int err = allocate_free(num_loop, ((uintptr_t) threadnum) % 4);
-	fprintf(stdout,
+	err = allocate_free(((uintptr_t)threadnum) % 4);
+	tst_res(TINFO,
 		"Thread [%d]: allocate_free() returned %d, %s.  Thread exiting.\n",
-		(int)(uintptr_t) threadnum, err,
+		(int)(uintptr_t)threadnum, err,
 		(err ? "failed" : "succeeded"));
 	return (void *)(uintptr_t) (err ? -1 : 0);
 }
 
-/******************************************************************************/
-/*								 	      */
-/* Function:	main							      */
-/*									      */
-/* Description:	This is the entry point to the program. This function will    */
-/*		parse the input arguments and set the values accordingly. If  */
-/*		no arguments (or desired) are provided default values are used*/
-/*		refer the usage function for the arguments that this program  */
-/*		takes. It also creates the threads which do most of the dirty */
-/*		work. If the threads exits with a value '0' the program exits */
-/*		with success '0' else it exits with failure '-1'.             */
-/*									      */
-/* Return:	-1 on failure						      */
-/*		 0 on success						      */
-/*									      */
-/******************************************************************************/
-int main(int argc,		/* number of input parameters                 */
-	 char **argv)
-{				/* pointer to the command line arguments.     */
-	int c;			/* command line options                       */
-	int num_thrd = MAXT;	/* number of threads to create                */
-	int thrd_ndx;		/* index into the array of thread ids         */
-	pthread_t *thrdid;	/* the threads                                */
-	extern int optopt;	/* options to the program                     */
+static void stress_malloc(unsigned int n)
+{
 	struct sembuf sop[1];
-	int ret = 0;
-
-	while ((c = getopt(argc, argv, "hl:t:")) != -1) {
-		switch (c) {
-		case 'h':
-			usage(argv[0]);
-			break;
-		case 'l':
-			if ((num_loop = atoi(optarg)) == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (num_loop < 1) {
-				fprintf(stdout,
-					"WARNING: bad argument. Using default\n");
-				num_loop = MAXL;
-			}
-			break;
-		case 't':
-			if ((num_thrd = atoi(optarg)) == 0)
-				OPT_MISSING(argv[0], optopt);
-			else if (num_thrd < 1) {
-				fprintf(stdout,
-					"WARNING: bad argument. Using default\n");
-				num_thrd = MAXT;
-			}
-			break;
-		default:
-			usage(argv[0]);
-			break;
+	int thread_index;
+
+	(void)n;
+	/* kick off all the waiting threads */
+	sop[0].sem_num = 0;
+	sop[0].sem_op = -1;
+	sop[0].sem_flg = 0;
+	TEST(semop(semid, sop, 1));
+	if (TEST_RETURN == -1)
+		tst_res(TBROK | TTERRNO, "Failed to wakeup all threads");
+
+	/* wait for all threads to finish */
+	for (thread_index = 0; thread_index < NUM_THREADS; thread_index++) {
+		void *status;
+
+		SAFE_PTHREAD_JOIN(thread_id[thread_index], &status);
+		if ((intptr_t)status != 0) {
+			tst_res(TFAIL, "thread [%d] - exited with errors\n",
+				thread_index);
 		}
 	}
 
-	dprt(("number of times to loop in the thread = %d\n", num_loop));
+	tst_res(TPASS, "malloc stress test finished successfully");
+}
 
-	thrdid = malloc(sizeof(pthread_t) * num_thrd);
-	if (thrdid == NULL) {
-		perror("main(): allocating space for thrdid[] malloc()");
-		return 1;
-	}
+static void setup(void)
+{
+	struct sembuf sop[1];
+	int thread_index;
+
+	thread_id = SAFE_MALLOC(sizeof(pthread_t) * NUM_THREADS);
 
 	semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
-	if (semid < 0) {
-		perror("Semaphore creation failed  Reason:");
-	}
+	if (semid < 0)
+		tst_res(TBROK | TTERRNO, "Semaphore creation failed");
 
 	sop[0].sem_num = 0;
 	sop[0].sem_op = 1;
 	sop[0].sem_flg = 0;
-	if (semop(semid, sop, 1) == -1) {
-		perror("semop");
-		ret = -1;
-		goto out;
-	}
+	TEST(semop(semid, sop, 1));
+	if (TEST_RETURN == -1)
+		tst_res(TBROK | TTERRNO, "Failed to initialize semaphore");
 
-	for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) {
-		if (pthread_create(&thrdid[thrd_ndx], NULL, alloc_mem,
-				   (void *)(uintptr_t) thrd_ndx)) {
-			int err = errno;
-			if (err == EINTR) {
-				fprintf(stderr,
-					"main(): pthread_create failed with EINTR!\n");
-				ret = -1;
-				goto out;
-			}
-			perror("main(): pthread_create()");
-			ret = -11;
-			goto out;
-		}
+	for (thread_index = 0; thread_index < NUM_THREADS; thread_index++) {
+		SAFE_PTHREAD_CREATE(&thread_id[thread_index], NULL, alloc_mem,
+				    (void *)(uintptr_t)thread_index);
 	}
-	my_yield();
+}
 
-	sop[0].sem_op = -1;
-	if (semop(semid, sop, 1) == -1) {
-		perror("semop");
-		ret = -1;
-		goto out;
+static void cleanup(void)
+{
+	if (semid > 0) {
+		TEST(semctl(semid, 0, IPC_RMID));
+		if (TEST_RETURN == -1)
+			tst_res(TWARN, "Failed to destroy semaphore");
 	}
 
-	for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) {
-		void *th_status;	/* exit status of LWP */
-		if (pthread_join(thrdid[thrd_ndx], &th_status) != 0) {
-			perror("main(): pthread_join()");
-			ret = -1;
-			goto out;
-		} else {
-			if ((intptr_t) th_status != 0) {
-				fprintf(stderr,
-					"main(): thread [%d] - exited with errors\n",
-					thrd_ndx);
-				ret = -1;
-				goto out;
-			}
-			dprt(("main(): thread [%d]: exited without errors\n",
-			      thrd_ndx));
-		}
-		my_yield();
-	}
-	printf("main(): test passed.\n");
-out:
-	if (semctl(semid, 0, IPC_RMID) == -1) {
-		perror("semctl\n");
-		ret = -1;
+	if (thread_id) {
+		free(thread_id);
+		thread_id = NULL;
 	}
-	if (thrdid) {
-		free(thrdid);
-		thrdid = NULL;
-	}
-	exit(ret);
 }
+
+static struct tst_test test = {
+	.tcnt = 1,
+	.cleanup = cleanup,
+	.setup = setup,
+	.test = stress_malloc,
+};
-- 
2.15.0.448.gf294e3d99a-goog



More information about the ltp mailing list