• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   Copyright (C) Bull S.A. 1996
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 |                           shmem_test_02                              |
21 | ==================================================================== |
22 |                                                                      |
23 | Description:  Verify anonymous shared memory mapping, with exclusive |
24 |               writes and shared reads                                |
25 |                                                                      |
26 | Algorithm:    o  Obtain two shared memory segments using             |
27 |                  mmap (MAP_ANON), one for random data created by the |
28 |                  the parent, and another for the childs checksums    |
29 |               o  Spawn N child processes                             |
30 |               o  Parent:                                             |
31 |                     - obtain write lock on data                      |
32 |                     - fill shared memory segment with data           |
33 |                     - compute data checksum                          |
34 |                     - release lock                                   |
35 |               o  Child:                                              |
36 |                     - obtain read lock on data                       |
37 |                     - compute data checksum                          |
38 |                     - release lock                                   |
39 |                     - store checksum in other shared memory segment  |
40 |               o  Parent:                                             |
41 |                     - wait for child proceeses to complete           |
42 |                     - compare child's checksum (from shared memory)  |
43 |                       with that of the parent                        |
44 |                                                                      |
45 | System calls: The following system calls are tested:                 |
46 |                                                                      |
47 |               mmap () - Maps a file-system object into memory        |
48 |                                                                      |
49 | Usage:        shmem_test_02 [-c num_children] [-s shmem_size]        |
50 |                                                                      |
51 | To compile:   cc -o shmem_test_02 shmem_test_02.c -lbsd              |
52 |                                                                      |
53 |**********************************************************************|
54 |******!!!!!! LINUX PORT - must be using kernel >= 2.4.3  !!!!!!*******|
55 |**********************************************************************|
56 |                                                                      |
57 | Last update:   Ver. 1.2, 2/8/94 00:08:39                             |
58 |                                                                      |
59 | Change Activity                                                      |
60 |                                                                      |
61 |   Version  Date    Name  Reason                                      |
62 |    0.1     111593  DJK   Initial version for AIX 4.1                 |
63 |    1.2     020794  DJK   Moved to "prod" directory                   |
64 |    1.3     060601  VHM   "ported" to linux                           |
65 |                                                                      |
66 +---------------------------------------------------------------------*/
67 
68 #include <errno.h>
69 #include <limits.h>
70 #include <unistd.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <fcntl.h>
75 #include <sys/file.h>
76 #include <sys/mman.h>
77 #include <sys/types.h>
78 #include <sys/signal.h>
79 #include <sys/wait.h>
80 
81 /* Defines
82  *
83  * USAGE: usage statement
84  */
85 #define LOCK_FILE "lockfile"
86 #define NLOOPS		20
87 #define	SHMEM_MODE	(SHM_R | SHM_W)
88 #define USAGE	"\nUsage: %s [-c num_children] [-s shmem_size]\n\n" \
89 		"\t-c num_children   number of child processes to spawn\n" \
90 		"\t-s shmem_size     size of shared memory segment (bytes)\n" \
91 		"\t                  (must be less than 256MB!)\n\n"
92 
93 #define GOTHERE printf("got to line %d\n", __LINE__);
94 
95 /*
96  * Function prototypes
97  *
98  * parse_args (): Parse command line arguments
99  * sys_error (): System error message function
100  * error (): Error message function
101  */
102 
103 struct data {
104 	int who;
105 	int value;
106 };
107 
108 void cleanup();
109 void handler(int, int, struct sigcontext *);
110 void setup_signal_handlers();
111 static void child(int, unsigned char *);
112 static int create_lock_file(char *);
113 static void unlock_file(int);
114 static void write_lock(int);
115 static void read_lock(int);
116 void parse_args(int, char **);
117 void sys_error(const char *, int);
118 void error(const char *, int);
119 void loop(int, char);
120 void tell(int, char *);
121 
122 enum { READ, WRITE };		/* Pipe read & write end indices */
123 enum { PARENT, CHILD };		/* Pipe read & write end indices */
124 
125 #define MAX_CHILDREN		400
126 #define BUFFER_SIZE		50
127 #define DEFAULT_NUM_CHILDREN	2
128 #define DEFAULT_SHMEM_SIZE	100000
129 
130 int num_children = DEFAULT_NUM_CHILDREN;
131 int buffer_size = DEFAULT_SHMEM_SIZE;
132 
133 unsigned long *checksum;	/* Shared memory segment address */
134 int lockfd;
135 pid_t parent_pid;
136 pid_t pid[MAX_CHILDREN];
137 
138 /*---------------------------------------------------------------------+
139 |                               main                                   |
140 | ==================================================================== |
141 |                                                                      |
142 | Function:  Main program  (see prolog for more details)               |
143 |                                                                      |
144 | Returns:   (0)  Successful completion                                |
145 |            (-1) Error occurred                                       |
146 |                                                                      |
147 +---------------------------------------------------------------------*/
main(int argc,char ** argv)148 int main(int argc, char **argv)
149 {
150 	unsigned char *shmptr,	/* Shared memory segment address */
151 	 value = 0;		/* Value written into shared memory segment */
152 	int i;
153 	unsigned char *ptr;
154 	int status;
155 	int shmem_size;
156 	unsigned long cksum;
157 
158 	lockfd = create_lock_file(LOCK_FILE);
159 	setup_signal_handlers();
160 
161 	/*
162 	 * Parse command line arguments and print out program header
163 	 */
164 	parse_args(argc, argv);
165 	printf("%s: IPC Shared Memory TestSuite program\n", *argv);
166 
167 	parent_pid = getpid();
168 	for (i = 0; i < num_children; i++)
169 		pid[i] = (pid_t) 0;
170 
171 	/*
172 	 * Get chunk of shared memory for storing num_children checksum
173 	 */
174 	shmem_size = sizeof(unsigned long) * num_children;
175 	if ((checksum = (unsigned long *)
176 	     mmap(0, shmem_size, PROT_READ | PROT_WRITE,
177 		  MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
178 		sys_error("mmap failed", __LINE__);
179 
180 	for (i = 0; i < num_children; i++)
181 		*(checksum + (sizeof(unsigned long) * i)) = 0;
182 
183 	/*
184 	 * Get chunk of memory for writing scratch data
185 	 */
186 	printf("\n\tGet shared memory segment (%d bytes)\n", buffer_size);
187 	if ((shmptr = mmap(0, buffer_size, PROT_READ | PROT_WRITE,
188 			   MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
189 		sys_error("mmap failed", __LINE__);
190 
191 	/*
192 	 * Parent:
193 	 *
194 	 * Fill buffer with data..
195 	 */
196 	cksum = value = 0;
197 
198 	printf("\n\tParent: calculate shared memory segment checksum\n");
199 	write_lock(lockfd);
200 	for (ptr = shmptr; ptr < (shmptr + buffer_size); ptr++) {
201 		*ptr = (value++) % (UCHAR_MAX + 1);
202 		cksum += *ptr;
203 	}
204 	unlock_file(lockfd);
205 	printf("\t        shared memory checksum %08lx\n", cksum);
206 
207 	printf("\n\tSpawning %d child processes ... \n", num_children);
208 	for (i = 0; i < num_children; i++) {
209 
210 		if ((pid[i] = fork()) == (pid_t) 0) {
211 			child(i, shmptr);
212 			exit(0);
213 		} else if (pid[i] < (pid_t) 0)
214 			sys_error("fork failed", __LINE__);
215 	}
216 
217 	/*
218 	 * Wait for child processes to compute checksum and complete...
219 	 */
220 	for (i = 0; i < num_children; i++) {
221 		waitpid(pid[i], &status, 0);
222 
223 		if (!WIFEXITED(status))
224 			sys_error("child process terminated abnormally",
225 				  __LINE__);
226 		if (cksum != *(checksum + (sizeof(unsigned long) * i))) {
227 			printf("checksum [%d] = %08lx\n", i, checksum[i]);
228 			error("checksums do not match", __LINE__);
229 		}
230 	}
231 	printf("\n\tParent: children calculated segment successfully\n");
232 	/*
233 	 * Program completed successfully -- exit
234 	 */
235 	printf("\nsuccessful!\n");
236 
237 	return (0);
238 }
239 
child(int num,unsigned char * shmptr)240 static void child(int num, unsigned char *shmptr)
241 {
242 	unsigned long cksum = 0;
243 	int i;
244 
245 	read_lock(lockfd);
246 	for (i = 0; i < buffer_size; i++)
247 		cksum += *shmptr++;
248 	unlock_file(lockfd);
249 
250 	*(checksum + (sizeof(unsigned long) * num)) = cksum;
251 	printf("\t\tchild (%02d): checksum %08lx\n", num,
252 	       *(checksum + (sizeof(unsigned long) * num)));
253 }
254 
write_lock(int fd)255 static void write_lock(int fd)
256 {
257 	if (lockf(fd, F_LOCK, 0) < 0)
258 		sys_error("lockf (LOCK) failed", __LINE__);
259 }
260 
read_lock(int fd)261 static void read_lock(int fd)
262 {
263 	if (lockf(fd, F_TEST, 0) < 0)
264 		sys_error("lockf (LOCK) failed", __LINE__);
265 }
266 
unlock_file(int fd)267 static void unlock_file(int fd)
268 {
269 	if (lockf(fd, F_ULOCK, 0) < 0)
270 		sys_error("lockf (UNLOCK) failed", __LINE__);
271 }
272 
273 /*---------------------------------------------------------------------+
274 |                          setup_handler ()                            |
275 | ==================================================================== |
276 |                                                                      |
277 | Function:  Setup the signal handler for SIGPIPE.                     |
278 |                                                                      |
279 +---------------------------------------------------------------------*/
setup_signal_handlers()280 void setup_signal_handlers()
281 {
282 	struct sigaction invec;
283 
284 	invec.sa_handler = (void (*)(int))handler;
285 	sigemptyset(&invec.sa_mask);
286 	invec.sa_flags = 0;
287 
288 	if (sigaction(SIGINT, &invec, NULL) < 0)
289 		sys_error("sigaction failed", __LINE__);
290 
291 }
292 
293 /*---------------------------------------------------------------------+
294 |                             handler ()                               |
295 | ==================================================================== |
296 |                                                                      |
297 | Function:  Signal catching function for SIGPIPE signal.              |
298 |                                                                      |
299 |            o  SIGPIPE: Print message and abort program...            |
300 |                                                                      |
301 |            o  SIGINT:  Parent process calls cleanup, child processes |
302 |                        simply exit                                   |
303 |                                                                      |
304 |            o  Other:   Print message and abort program...            |
305 |                                                                      |
306 +---------------------------------------------------------------------*/
handler(int sig,int code,struct sigcontext * scp)307 void handler(int sig, int code, struct sigcontext *scp)
308 {
309 	char msg[100];		/* Buffer for error message */
310 
311 	if (sig == SIGINT) {
312 		if (getpid() == parent_pid) {
313 
314 			fprintf(stderr, "Received SIGINT -- cleaning up...\n");
315 			fflush(stderr);
316 
317 			cleanup();
318 		} else
319 			exit(-1);
320 	} else {
321 		sprintf(msg, "Received an unexpected signal (%d)", sig);
322 		error(msg, __LINE__);
323 	}
324 }
325 
326 /*---------------------------------------------------------------------+
327 |                             cleanup ()                               |
328 | ==================================================================== |
329 |                                                                      |
330 | Function:  Closes all of the pipes, kills all of the child           |
331 |            processes and exits the program...                        |
332 |                                                                      |
333 +---------------------------------------------------------------------*/
cleanup()334 void cleanup()
335 {
336 	int i;
337 
338 	if (getpid() == parent_pid) {
339 		for (i = 0; i < num_children; i++) {
340 			if (pid[i] > (pid_t) 0 && kill(pid[i], SIGKILL) < 0)
341 				sys_error("signal failed", __LINE__);
342 		}
343 	}
344 
345 	exit(-1);
346 }
347 
create_lock_file(char * lock_name)348 static int create_lock_file(char *lock_name)
349 {
350 	int fd;
351 
352 	if ((fd = open(lock_name, O_RDWR)) < 0) {
353 		if ((fd = open(lock_name, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) {
354 			perror("cannot create lock file");
355 			exit(-1);
356 		}
357 	}
358 	return (fd);
359 }
360 
361 /*---------------------------------------------------------------------+
362 |                             parse_args ()                            |
363 | ==================================================================== |
364 |                                                                      |
365 | Function:  Parse the command line arguments & initialize global      |
366 |            variables.                                                |
367 |                                                                      |
368 | Updates:   (command line options)                                    |
369 |                                                                      |
370 |            [-s] size: shared memory segment size                     |
371 |                                                                      |
372 |            [-c] num_children: number of child processes              |
373 |                                                                      |
374 +---------------------------------------------------------------------*/
parse_args(int argc,char ** argv)375 void parse_args(int argc, char **argv)
376 {
377 	int i;
378 	int errflag = 0;
379 	char *program_name = *argv;
380 	extern char *optarg;	/* Command line option */
381 
382 	while ((i = getopt(argc, argv, "c:s:?")) != EOF) {
383 		switch (i) {
384 		case 'c':
385 			num_children = atoi(optarg);
386 			break;
387 		case 's':
388 			buffer_size = atoi(optarg);
389 			break;
390 		case '?':
391 			errflag++;
392 			break;
393 		}
394 	}
395 
396 	if (errflag) {
397 		fprintf(stderr, USAGE, program_name);
398 		exit(2);
399 	}
400 }
401 
402 /*---------------------------------------------------------------------+
403 |                             sys_error ()                             |
404 | ==================================================================== |
405 |                                                                      |
406 | Function:  Creates system error message and calls error ()           |
407 |                                                                      |
408 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)409 void sys_error(const char *msg, int line)
410 {
411 	char syserr_msg[256];
412 
413 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
414 	error(syserr_msg, line);
415 }
416 
417 /*---------------------------------------------------------------------+
418 |                               error ()                               |
419 | ==================================================================== |
420 |                                                                      |
421 | Function:  Prints out message and exits...                           |
422 |                                                                      |
423 +---------------------------------------------------------------------*/
error(const char * msg,int line)424 void error(const char *msg, int line)
425 {
426 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
427 	cleanup();
428 }
429