shm_test.c revision ec6edca7aa42b6affd989ef91b5897f96795e40f
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/* History: Nov - 21 - 2001 Created - Manoj Iyer, IBM Austin TX. */ 24/* email:manjo@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 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 *)(uintptr_t)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/* Function: usage */ 89/* */ 90/* Description: Print the usage message. */ 91/* */ 92/* Return: exits with -1 */ 93/* */ 94/******************************************************************************/ 95static void 96usage(char *progname) /* name of this program */{ 97 fprintf(stderr, 98 "Usage: %s -d NUMDIR -f NUMFILES -h -t NUMTHRD\n" 99 "\t -h Help!\n" 100 "\t -l Number of repatetions to execute: Default: 1000\n" 101 "\t -t Number of threads to generate: Default: 30\n", 102 progname); 103 exit(-1); 104} 105 106/******************************************************************************/ 107/* */ 108/* Function: rm_shared_mem */ 109/* */ 110/* Description: This function removes the shared segments that were created */ 111/* This function is called when shmat fails or logical end of */ 112/* the while loop is reached in shmat_rd_wr function. */ 113/* */ 114/* Input: shm_id - id of the shared memory segment to be removed */ 115/* shm_addr - address of the shared memory segment to be removed */ 116/* cmd - remove id only or remove id and detach?? */ 117/* 0 - remove id dont detach segment. */ 118/* 1 - remove id and detach segment. */ 119/* */ 120/* Output: NONE. */ 121/* */ 122/* Return: exits with -1 on error, 0 on success */ 123/* */ 124/******************************************************************************/ 125static int 126rm_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) /* remove id only or remove id and detach seg */ 129{ 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 { 136 dprt("pid[%d]: rm_shared_mem(): shmctl unable to remove shm_id[%d]\n", 137 getpid(), shm_id); 138 perror("rm_shared_mem(): shmctl()"); 139 return -1; 140 } 141 142 if (cmd) 143 { 144 if (shmdt((void *)shm_addr) == -1) 145 { 146 dprt("pid[%d]:rm_shared_mem(): shmdt unable to detach addr = %#x\n", 147 getpid(), shm_addr); 148 perror("rm_shared_mem(): shmdt()"); 149 return -1; 150 } 151 } 152 return 0; 153} 154 155/******************************************************************************/ 156/* */ 157/* Function: shmat_rd_wr */ 158/* */ 159/* Description: This function repeatedly attaches and detaches the memory */ 160/* The size of the file is a multiple of page size. */ 161/* The function acts as either reader or writer thread depending */ 162/* on arg[3]. The reader and writer thread use the same key so */ 163/* they get access to the same shared memory segment. */ 164/* */ 165/* Input: The argument pointer contains the following. */ 166/* arg[0] - number of repatetions of the above operation */ 167/* arg[1] - shared memory key. */ 168/* arg[2] - size of the memory that is to be attached. */ 169/* arg[3] - reader or writer. */ 170/* */ 171/* Return: exits with -1 on error, 0 on success */ 172/* */ 173/******************************************************************************/ 174static void * 175shmat_rd_wr(void *args) /* arguments to the thread function */ 176{ 177 int shmndx = 0; /* index to the number of attach and detach */ 178 int index = 0; /* index to the number of blocks touched */ 179 int reader = 0; /* this thread is a reader thread if set to 1 */ 180 key_t shm_id = 0; /* shared memory id */ 181 long *locargs = /* local pointer to arguments */ 182 (long *)args; 183 volatile int exit_val = 0; /* exit value of the pthread */ 184 char *read_from_mem;/* ptr to touch each (4096) block in memory */ 185 char *write_to_mem; /* ptr to touch each (4096) block in memory */ 186 char *shmat_addr; /* address of the attached memory */ 187 char buff; /* temporary buffer */ 188 189 reader = (int)locargs[3]; 190 while (shmndx++ < (int)locargs[0]) 191 { 192 dprt("pid[%d]: shmat_rd_wr(): locargs[1] = %#x\n", 193 getpid(), (int)locargs[1]); 194 195 /* get shared memory id */ 196 if ((shm_id = shmget((int)locargs[1], (int)locargs[2], IPC_CREAT|0666)) 197 == -1) 198 { 199 dprt("pid[%d]: shmat_rd_wr(): shmget failed\n", getpid()); 200 perror("do_shmat_shmadt(): shmget()"); 201 PTHREAD_EXIT(-1); 202 } 203 204 fprintf(stdout, "pid[%d]: shmat_rd_wr(): shmget():" 205 "success got segment id %d\n", 206 getpid(), shm_id); 207 208 /* get shared memory segment */ 209 if ((shmat_addr = (char *)shmat(shm_id, NULL, 0)) == (void *)-1) 210 { 211 rm_shared_mem(shm_id, shmat_addr, 0); 212 fprintf(stderr, "pid[%d]: do_shmat_shmadt(): shmat_addr = %#lx\n", 213 getpid(), (long)shmat_addr); 214 perror("do_shmat_shmadt(): shmat()"); 215 PTHREAD_EXIT(-1); 216 } 217 dprt("pid[%d]: do_shmat_shmadt(): content of memory shmat_addr = %s\n", 218 getpid(), shmat_addr); 219 220 fprintf(stdout, "pid[%d]: do_shmat_shmadt(): got shmat address = %#lx\n", 221 getpid(), (long)shmat_addr); 222 223 if (!reader) 224 { 225 /* write character 'Y' to that memory area */ 226 index = 0; 227 write_to_mem = shmat_addr; 228 while (index < (int)locargs[2]) 229 { 230 dprt("pid[%d]: do_shmat_shmatd(): write_to_mem = %#x\n", 231 getpid(), write_to_mem); 232 *write_to_mem = 'Y'; 233 index++; 234 write_to_mem++; 235 sched_yield(); 236 } 237 } 238 else 239 { 240 /* read from the memory area */ 241 index = 0; 242 read_from_mem = shmat_addr; 243 while (index < (int)locargs[2]) 244 { 245 buff = *read_from_mem; 246 index++; 247 read_from_mem++; 248 sched_yield(); 249 } 250 } 251 252 sched_yield(); 253 254 /* remove the shared memory */ 255 if (rm_shared_mem(shm_id, shmat_addr, 1) == -1) 256 { 257 fprintf(stderr, 258 "pid[%d]: do_shmat_shmatd(): rm_shared_mem(): faild to rm id\n", 259 getpid()); 260 PTHREAD_EXIT(-1); 261 } 262 } 263 264 PTHREAD_EXIT(0); 265} 266 267/******************************************************************************/ 268/* */ 269/* Function: main */ 270/* */ 271/* Description: This is the entry point to the program. This function will */ 272/* parse the input arguments and set the values accordingly. If */ 273/* no arguments (or desired) are provided default values are used*/ 274/* refer the usage function for the arguments that this program */ 275/* takes. It also creates the threads which do most of the dirty */ 276/* work. If the threads exits with a value '0' the program exits */ 277/* with success '0' else it exits with failure '-1'. */ 278/* */ 279/* Return: -1 on failure */ 280/* 0 on success */ 281/* */ 282/******************************************************************************/ 283int 284main(int argc, /* number of input parameters */ 285 char **argv) /* pointer to the command line arguments. */ 286{ 287 int c; /* command line options */ 288 int num_thrd = MAXT;/* number of threads to create */ 289 int num_reps = MAXR;/* number of repatitions the test is run */ 290 int thrd_ndx; /* index into the array of thread ids */ 291 int th_status; /* exit status of LWP's */ 292 int map_size; /* size of the file mapped. */ 293 int shmkey = 1969;/* key used to generate shmid by shmget() */ 294 pthread_t thrdid[30]; /* maxinum of 30 threads allowed */ 295 long chld_args[4]; /* arguments to the thread function */ 296 char *map_address=NULL; 297 /* address in memory of the mapped file */ 298 extern int optopt; /* options to the program */ 299 300 while ((c = getopt(argc, argv, "hl:t:")) != -1) 301 { 302 switch(c) 303 { 304 case 'h': 305 usage(argv[0]); 306 break; 307 case 'l': /* how many repetitions of the test to exec */ 308 if ((num_reps = atoi(optarg)) == 0) 309 OPT_MISSING(argv[0], optopt); 310 else 311 if (num_reps < 0) 312 { 313 fprintf(stdout, 314 "WARNING: bad argument. Using default\n"); 315 num_reps = MAXR; 316 } 317 break; 318 case 't': 319 if ((num_thrd = atoi(optarg)) == 0) 320 OPT_MISSING(argv[0], optopt); 321 else 322 if (num_thrd < 0) 323 { 324 fprintf(stdout, 325 "WARNING: bad argument. Using default\n"); 326 num_thrd = MAXT; 327 } 328 break; 329 default : 330 usage(argv[0]); 331 break; 332 } 333 } 334 335 chld_args[0] = num_reps; 336 337 for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx+=2) 338 { 339 srand(time(NULL)%100); 340 map_size = (1 + (int)(1000.0*rand()/(RAND_MAX+1.0))) * 4096; 341 342 chld_args[1] = shmkey++; 343 chld_args[2] = map_size; 344 345 dprt("main(): thrd_ndx = %d map_address = %#x map_size = %d\n", 346 thrd_ndx, map_address, map_size); 347 348 chld_args[3] = WRITER; 349 350 if (pthread_create(&thrdid[thrd_ndx], NULL, shmat_rd_wr, chld_args)) 351 { 352 perror("shmat_rd_wr(): pthread_create()"); 353 exit(-1); 354 } 355 356 chld_args[3] = READER; 357 358 if (pthread_create(&thrdid[thrd_ndx+1], NULL, shmat_rd_wr, chld_args)) 359 { 360 perror("shmat_rd_wr(): pthread_create()"); 361 exit(-1); 362 } 363 } 364 365 sync(); 366 367 for (thrd_ndx = 0; thrd_ndx < num_thrd; thrd_ndx++) 368 { 369 if (pthread_join(thrdid[thrd_ndx], (void *)&th_status) != 0) 370 { 371 perror("shmat_rd_wr(): pthread_join()"); 372 exit(-1); 373 } 374 else 375 { 376 dprt("WE ARE HERE %d\n", __LINE__); 377 if (th_status == -1) 378 { 379 fprintf(stderr, 380 "thread [%ld] - process exited with errors\n", 381 (long)thrdid[thrd_ndx]); 382 exit(-1); 383 } 384 } 385 } 386 exit(0); 387} 388