Home | History | Annotate | Download | only in mtest07
      1 /******************************************************************************/
      2 /*									      */
      3 /* Copyright (c) International Business Machines  Corp., 2001		      */
      4 /*									      */
      5 /* This program is free software;  you can redistribute it and/or modify      */
      6 /* it under the terms of the GNU General Public License as published by       */
      7 /* the Free Software Foundation; either version 2 of the License, or          */
      8 /* (at your option) any later version.					      */
      9 /*									      */
     10 /* This program is distributed in the hope that it will be useful,	      */
     11 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of	      */
     12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See	              */
     13 /* the GNU General Public License for more details.			      */
     14 /*									      */
     15 /* You should have received a copy of the GNU General Public License	      */
     16 /* along with this program;  if not, write to the Free Software		      */
     17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
     18 /*									      */
     19 /******************************************************************************/
     20 
     21 /******************************************************************************/
     22 /*                                                                            */
     23 /* History:     Nov - 21 - 2001 Created - Manoj Iyer, IBM Austin TX.          */
     24 /*                               email:manjo (at) austin.ibm.com                   */
     25 /*                                                                            */
     26 /*		Nov - 26 - 2001 Modified - Manoj Iyer, IBM Austin Tx.         */
     27 /*				- Added function rm_shared_mem.               */
     28 /*                                                                            */
     29 /*		Dec - 03 - 2001 Modified - Manoj Iyer, IBM Austin Tx.         */
     30 /*				- Added code to spawn threads.		      */
     31 /*				- Removed dead code.		              */
     32 /*				- Checked in the initial version to CVS       */
     33 /*								              */
     34 /*		Feb - 27 - 2001 Modified - Manoj Iyer, IBM Austin TX.         */
     35 /*				- removed compiler warnings.                  */
     36 /*				- removed compiler errors.                    */
     37 /*                                                                            */
     38 /* File:	shm_test.c				                      */
     39 /*									      */
     40 /* Description:	This program is designed to stress the Memory management sub -*/
     41 /*		system of Linux. This program will spawn multiple pairs of    */
     42 /*		reader and writer threads. One thread will create the shared  */
     43 /*		segment of random size and write to this memory, the other    */
     44 /*		pair will read from this memory.		              */
     45 /*									      */
     46 /******************************************************************************/
     47 #include <pthread.h>		/* required by pthread functions                      */
     48 #include <stdio.h>		/* required by fprintf()                              */
     49 #include <stdlib.h>		/* required by exit(), atoi()                         */
     50 #include <string.h>		/* required by strncpy()                              */
     51 #include <unistd.h>		/* required by getopt(), mmap()                       */
     52 #include <sys/types.h>		/* required by open(), shmat(), shmdt()               */
     53 #include <sys/stat.h>		/* required by open()                                 */
     54 #include <sys/ipc.h>		/* required by shmat() shmdt(), shmctl()              */
     55 #include <sys/shm.h>		/* required by shmat() shmdt(), shmctl()              */
     56 #include <sys/mman.h>		/* required by mmap()                                 */
     57 #include <fcntl.h>		/* required by open()                                 */
     58 #include <stdint.h>		/* required by uintptr_t                              */
     59 
     60 void noprintf(char *string, ...)
     61 {
     62 }
     63 
     64 #ifdef DEBUG
     65 #define dprt	printf
     66 #else
     67 #define dprt	noprintf
     68 #endif
     69 
     70 #define PTHREAD_EXIT(val)    do {\
     71 			exit_val = val; \
     72                         dprt("pid[%d]: exiting with %d\n", getpid(),exit_val); \
     73 			pthread_exit((void *)(uintptr_t)exit_val); \
     74 				} while (0)
     75 
     76 #define OPT_MISSING(prog, opt)   do{\
     77 			       fprintf(stderr, "%s: option -%c ", prog, opt); \
     78                                fprintf(stderr, "requires an argument\n"); \
     79                                usage(prog); \
     80                                    } while (0)
     81 
     82 #define MAXT	30		/* default number of threads to create.               */
     83 #define MAXR	1000		/* default number of repatetions to execute           */
     84 #define WRITER  0		/* cause thread function to shmat and write           */
     85 #define READER  1		/* cause thread function to shmat and read            */
     86 
     87 /******************************************************************************/
     88 /*								 	      */
     89 /* Function:	usage							      */
     90 /*									      */
     91 /* Description:	Print the usage message.				      */
     92 /*									      */
     93 /* Return:	exits with -1						      */
     94 /*									      */
     95 /******************************************************************************/
     96 static void usage(char *progname)
     97 {				/* name of this program                       */
     98 	fprintf(stderr,
     99 		"Usage: %s -d NUMDIR -f NUMFILES -h -t NUMTHRD\n"
    100 		"\t -h Help!\n"
    101 		"\t -l Number of repatetions to execute:       Default: 1000\n"
    102 		"\t -t Number of threads to generate:          Default: 30\n",
    103 		progname);
    104 	exit(-1);
    105 }
    106 
    107 /******************************************************************************/
    108 /*								 	      */
    109 /* Function:	rm_shared_mem						      */
    110 /*									      */
    111 /* Description:	This function removes the shared segments that were created   */
    112 /*		This function is called when shmat fails or logical end of    */
    113 /*		the while loop is reached in shmat_rd_wr function.         */
    114 /*									      */
    115 /* Input:	shm_id   - id of the shared memory segment to be removed      */
    116 /*		shm_addr - address of the shared memory segment to be removed */
    117 /*		cmd      - remove id only or remove id and detach??           */
    118 /*			   0 - remove id dont detach segment.                 */
    119 /*			   1 - remove id and detach segment.                  */
    120 /*									      */
    121 /* Output:	NONE.                                                         */
    122 /*									      */
    123 /* Return:	exits with -1 on error, 0 on success                          */
    124 /*									      */
    125 /******************************************************************************/
    126 static int rm_shared_mem(key_t shm_id,	/* id of shared memory segment to be removed  */
    127 			 char *shm_addr,	/* address of shared mem seg to be removed    */
    128 			 int cmd)
    129 {				/* remove id only or remove id and detach seg */
    130 	struct shmid *shmbuf = NULL;	/* info about the segment pointed by shmkey   */
    131 
    132 	dprt("pid[%d]: rm_shared_mem(): shm_id = %d shm_addr = %#x cmd = %d\n",
    133 	     getpid(), shm_id, shm_addr, cmd);
    134 	if (shmctl(shm_id, IPC_RMID, (struct shmid_ds *)shmbuf) == -1) {
    135 		dprt("pid[%d]: rm_shared_mem(): shmctl unable to remove shm_id[%d]\n", getpid(), shm_id);
    136 		perror("rm_shared_mem(): shmctl()");
    137 		return -1;
    138 	}
    139 
    140 	if (cmd) {
    141 		if (shmdt((void *)shm_addr) == -1) {
    142 			dprt("pid[%d]:rm_shared_mem(): shmdt unable to detach addr = %#x\n", getpid(), shm_addr);
    143 			perror("rm_shared_mem(): shmdt()");
    144 			return -1;
    145 		}
    146 	}
    147 	return 0;
    148 }
    149 
    150 /******************************************************************************/
    151 /*								 	      */
    152 /* Function:	shmat_rd_wr						      */
    153 /*									      */
    154 /* Description:	This function repeatedly attaches and detaches the memory     */
    155 /*		The size of the file is a multiple of page size.              */
    156 /*		The function acts as either reader or writer thread depending */
    157 /*		on arg[3]. The reader and writer thread use the same key so   */
    158 /*		they get access to the same shared memory segment.            */
    159 /*									      */
    160 /* Input:	The argument pointer contains the following.                  */
    161 /*		arg[0] - number of repatetions of the above operation         */
    162 /*		arg[1] - shared memory key.				      */
    163 /*		arg[2] - size of the memory that is to be attached.           */
    164 /*		arg[3] - reader or writer.                                    */
    165 /*									      */
    166 /* Return:	exits with -1 on error, 0 on success                          */
    167 /*									      */
    168 /******************************************************************************/
    169 static void *shmat_rd_wr(void *args)
    170 {				/* arguments to the thread function             */
    171 	int shmndx = 0;		/* index to the number of attach and detach   */
    172 	int index = 0;		/* index to the number of blocks touched      */
    173 	int reader = 0;		/* this thread is a reader thread if set to 1 */
    174 	key_t shm_id = 0;	/* shared memory id                           */
    175 	long *locargs =		/* local pointer to arguments                 */
    176 	    (long *)args;
    177 	volatile int exit_val = 0;	/* exit value of the pthread                  */
    178 	char *read_from_mem;	/* ptr to touch each (4096) block in memory   */
    179 	char *write_to_mem;	/* ptr to touch each (4096) block in memory   */
    180 	char *shmat_addr;	/* address of the attached memory             */
    181 	char buff;		/* temporary buffer                           */
    182 
    183 	reader = (int)locargs[3];
    184 	while (shmndx++ < (int)locargs[0]) {
    185 		dprt("pid[%d]: shmat_rd_wr(): locargs[1] = %#x\n",
    186 		     getpid(), (int)locargs[1]);
    187 
    188 		/* get shared memory id */
    189 		if ((shm_id =
    190 		     shmget((int)locargs[1], (int)locargs[2], IPC_CREAT | 0666))
    191 		    == -1) {
    192 			dprt("pid[%d]: shmat_rd_wr(): shmget failed\n",
    193 			     getpid());
    194 			perror("do_shmat_shmadt(): shmget()");
    195 			PTHREAD_EXIT(-1);
    196 		}
    197 
    198 		fprintf(stdout, "pid[%d]: shmat_rd_wr(): shmget():"
    199 			"success got segment id %d\n", getpid(), shm_id);
    200 
    201 		/* get shared memory segment */
    202 		if ((shmat_addr = shmat(shm_id, NULL, 0)) == (void *)-1) {
    203 			rm_shared_mem(shm_id, shmat_addr, 0);
    204 			fprintf(stderr,
    205 				"pid[%d]: do_shmat_shmadt(): shmat_addr = %#lx\n",
    206 				getpid(), (long)shmat_addr);
    207 			perror("do_shmat_shmadt(): shmat()");
    208 			PTHREAD_EXIT(-1);
    209 		}
    210 		dprt("pid[%d]: do_shmat_shmadt(): content of memory shmat_addr = %s\n", getpid(), shmat_addr);
    211 
    212 		fprintf(stdout,
    213 			"pid[%d]: do_shmat_shmadt(): got shmat address = %#lx\n",
    214 			getpid(), (long)shmat_addr);
    215 
    216 		if (!reader) {
    217 			/* write character 'Y' to that memory area */
    218 			index = 0;
    219 			write_to_mem = shmat_addr;
    220 			while (index < (int)locargs[2]) {
    221 				dprt("pid[%d]: do_shmat_shmatd(): write_to_mem = %#x\n", getpid(), write_to_mem);
    222 				*write_to_mem = 'Y';
    223 				index++;
    224 				write_to_mem++;
    225 				sched_yield();
    226 			}
    227 		} else {
    228 			/* read from the memory area */
    229 			index = 0;
    230 			read_from_mem = shmat_addr;
    231 			while (index < (int)locargs[2]) {
    232 				buff = *read_from_mem;
    233 				index++;
    234 				read_from_mem++;
    235 				sched_yield();
    236 			}
    237 		}
    238 
    239 		sched_yield();
    240 
    241 		/* remove the shared memory */
    242 		if (rm_shared_mem(shm_id, shmat_addr, 1) == -1) {
    243 			fprintf(stderr,
    244 				"pid[%d]: do_shmat_shmatd(): rm_shared_mem(): faild to rm id\n",
    245 				getpid());
    246 			PTHREAD_EXIT(-1);
    247 		}
    248 	}
    249 
    250 	PTHREAD_EXIT(0);
    251 }
    252 
    253 /******************************************************************************/
    254 /*								 	      */
    255 /* Function:	main							      */
    256 /*									      */
    257 /* Description:	This is the entry point to the program. This function will    */
    258 /*		parse the input arguments and set the values accordingly. If  */
    259 /*		no arguments (or desired) are provided default values are used*/
    260 /*		refer the usage function for the arguments that this program  */
    261 /*		takes. It also creates the threads which do most of the dirty */
    262 /*		work. If the threads exits with a value '0' the program exits */
    263 /*		with success '0' else it exits with failure '-1'.             */
    264 /*									      */
    265 /* Return:	-1 on failure						      */
    266 /*		 0 on success						      */
    267 /*									      */
    268 /******************************************************************************/
    269 int main(int argc,		/* number of input parameters                 */
    270 	 char **argv)
    271 {				/* pointer to the command line arguments.     */
    272 	int c;			/* command line options                       */
    273 	int num_thrd = MAXT;	/* number of threads to create                */
    274 	int num_reps = MAXR;	/* number of repatitions the test is run      */
    275 	int thrd_ndx;		/* index into the array of thread ids         */
    276 	void *th_status;	/* exit status of LWP's                       */
    277 	int map_size;		/* size of the file mapped.                   */
    278 	int shmkey = 1969;	/* key used to generate shmid by shmget()     */
    279 	pthread_t thrdid[30];	/* maxinum of 30 threads allowed              */
    280 	long chld_args[4];	/* arguments to the thread function           */
    281 	char *map_address = NULL;
    282 	/* address in memory of the mapped file       */
    283 	extern int optopt;	/* options to the program                     */
    284 
    285 	while ((c = getopt(argc, argv, "hl:t:")) != -1) {
    286 		switch (c) {
    287 		case 'h':
    288 			usage(argv[0]);
    289 			break;
    290 		case 'l':	/* how many repetitions of the test to exec   */
    291 			if ((num_reps = atoi(optarg)) == 0)
    292 				OPT_MISSING(argv[0], optopt);
    293 			else if (num_reps < 0) {
    294 				fprintf(stdout,
    295 					"WARNING: bad argument. Using default\n");
    296 				num_reps = MAXR;
    297 			}
    298 			break;
    299 		case 't':
    300 			if ((num_thrd = atoi(optarg)) == 0)
    301 				OPT_MISSING(argv[0], optopt);
    302 			else if (num_thrd < 0) {
    303 				fprintf(stdout,
    304 					"WARNING: bad argument. Using default\n");
    305 				num_thrd = MAXT;
    306 			}
    307 			break;
    308 		default:
    309 			usage(argv[0]);
    310 			break;
    311 		}
    312 	}
    313 
    314 	chld_args[0] = num_reps;
    315 
    316 	for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx += 2) {
    317 		srand(time(NULL) % 100);
    318 		map_size =
    319 		    (1 + (int)(1000.0 * rand() / (RAND_MAX + 1.0))) * 4096;
    320 
    321 		chld_args[1] = shmkey++;
    322 		chld_args[2] = map_size;
    323 
    324 		dprt("main(): thrd_ndx = %d map_address = %#x map_size = %d\n",
    325 		     thrd_ndx, map_address, map_size);
    326 
    327 		chld_args[3] = WRITER;
    328 
    329 		if (pthread_create
    330 		    (&thrdid[thrd_ndx], NULL, shmat_rd_wr, chld_args)) {
    331 			perror("shmat_rd_wr(): pthread_create()");
    332 			exit(-1);
    333 		}
    334 
    335 		chld_args[3] = READER;
    336 
    337 		if (pthread_create
    338 		    (&thrdid[thrd_ndx + 1], NULL, shmat_rd_wr, chld_args)) {
    339 			perror("shmat_rd_wr(): pthread_create()");
    340 			exit(-1);
    341 		}
    342 	}
    343 
    344 	sync();
    345 
    346 	for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) {
    347 		if (pthread_join(thrdid[thrd_ndx], &th_status) != 0) {
    348 			perror("shmat_rd_wr(): pthread_join()");
    349 			exit(-1);
    350 		} else {
    351 			dprt("WE ARE HERE %d\n", __LINE__);
    352 			if (th_status == (void *)-1) {
    353 				fprintf(stderr,
    354 					"thread [%ld] - process exited with errors\n",
    355 					(long)thrdid[thrd_ndx]);
    356 				exit(-1);
    357 			}
    358 		}
    359 	}
    360 	exit(0);
    361 }
    362