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