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