• 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_07.c                            |
21 | ==================================================================== |
22 |                                                                      |
23 | Description:  Verify shared memory functions with                    |
24 |                                                                      |
25 | Algorithm:                                                           |
26 |                    ## shared memory segments ##                      |
27 |               *  from 1 up to number_of_writer                       |
28 |               {                                                      |
29 |               o  Obtain three shared memory segments per writer      |
30 |                  one for storing the read count (number of thread    |
31 |                  reading "scratch" shm) ,                            |
32 |                  another for storing the checksums of readers ,      |
33 |                  and the last for the "scratch" shared memory segment|
34 |                  for storing a series of values .                    |
35 |               }                                                      |
36 |                    ## Threads ##                                     |
37 |               *  from 1 up to number_of_writer                       |
38 |               {                                                      |
39 |                  Initializes mutexes ,                               |
40 |                  Insure the writer gets first access to the segment: |
41 |                  Threads are synchronized with Condition Varaiables  |
42 |                                                                      |
43 |                  thread_hold[number_of_writer]=1;                    |
44 |                                                                      |
45 |               }                                                      |
46 |               *  from 1 up to number_of_writer                       |
47 |               {                                                      |
48 |                  Create/Start all num_writers threads (writer)       |
49 |                  from 1 up to number_of_reader                       |
50 |                       {                                              |
51 |                       Create/Start all num_readers threads (reader)  |
52 |                       }                                              |
53 |               }                                                      |
54 |               *  from 1 up to number_of_writer                       |
55 |               {                                                      |
56 |                  Wait for the termination of writer thread           |
57 |                  from 1 up to number_of_reader                       |
58 |                       {                                              |
59 |                       Wait for the termination of reader thread      |
60 |                       }                                              |
61 |               }                                                      |
62 |               *  from 1 up to number_of_writer                       |
63 |               {                                                      |
64 |                  Get writer checksum                                 |
65 |                  from 1 up to number_of_reader                       |
66 |                       {                                              |
67 |                       Verify that each checksum calculated by readers|
68 |                       match with the writer checksum                 |
69 |                       }                                              |
70 |               }                                                      |
71 |----------------------------------------------------------------------|
72 |                               writer ()                              |
73 |----------------------------------------------------------------------|
74 |               o  Writer:                                             |
75 |                     - Fill the "scratch" shared memory segment up    |
76 |                       with data                                      |
77 |                     - Compute the segment checksum                   |
78 |                     - release lock (reader threads may begin) i.e:   |
79 |                                                                      |
80 |                       thread_hold[num_w]=0;                          |
81 |                                                                      |
82 |----------------------------------------------------------------------|
83 |                               reader ()                              |
84 |----------------------------------------------------------------------|
85 |               o  Reader:                                             |
86 |                     - Check to see if we need to wait i.e:           |
87 |                                                                      |
88 |                       while (thread_hold[num_w]) wait;               |
89 |                                                                      |
90 |                     - Evaluate checksum                              |
91 |                     - Store the resulting checksum                   |
92 |----------------------------------------------------------------------|
93 |                                                                      |
94 |                                                                      |
95 | System calls: The following system calls are tested:                 |
96 |               shmget ()                                              |
97 |               shmat ()                                               |
98 |               shmctl ()                                              |
99 |                                                                      |
100 |               The following system calls are used:                   |
101 |               malloc ()                                              |
102 |               pthread_mutex_init()                                   |
103 |               pthread_cond_init()                                    |
104 |               pthread_attr_init()                                    |
105 |               pthread_attr_setdetachstate()                          |
106 |               pthread_create()                                       |
107 |               pthread_join()                                         |
108 |               pthread_mutex_lock()                                   |
109 |               pthread_cond_broadcast()                               |
110 |               pthread_mutex_unlock()                                 |
111 |               pthread_cond_wait()                                    |
112 |               pthread_mutex_destroy()                                |
113 |                                                                      |
114 |                                                                      |
115 | Usage:                                                               |
116 |       shmem_test_07 [-c num_readers] [-s shmem_size] [-g num_writers]|
117 |                                                                      |
118 | To compile:                                                          |
119 |       cc_r -g -lpthreads -lc_r -o shmem_test_07 shmem_test_07.c      |
120 |                                                                      |
121 | Last update:                                                         |
122 |                                                                      |
123 | Change Activity                                                      |
124 |                                                                      |
125 |   Version  Date    Name  Reason                                      |
126 |    0.1     011697  JM    Initial version for AIX 4.2G                |
127 |                                                                      |
128 +---------------------------------------------------------------------*/
129 #define _XOPEN_SOURCE 600
130 #include <pthread.h>
131 #include <errno.h>
132 #include <stdio.h>
133 #include <string.h>
134 #include <unistd.h>
135 #include <limits.h>
136 #include <sys/ipc.h>
137 #include <sys/shm.h>
138 #include <sys/sem.h>
139 #include <sys/signal.h>
140 #include <sys/types.h>
141 #include <sys/wait.h>
142 #include <stdlib.h>
143 
144 #include <sys/stat.h>
145 /* Defines
146  *
147  * DEFAULT_SHMEM_SIZE: default shared memory size, unless specified with
148  * -s command line option
149  *
150  * SHMEM_MODE: shared memory access permissions (permit process to read
151  * and write access)
152  *
153  * USAGE: usage statement
154  */
155 #define MAX_THREAD_NUMBER	500
156 #define MAX_WRITER_NUMBER	100
157 #define MAX_READER_NUMBER	400
158 
159 #define DEFAULT_NUM_READERS	2
160 #define DEFAULT_NUM_WRITERS	2
161 
162 #define SHMEM_MODE              (SHM_R | SHM_W)
163 
164 #define DEFAULT_SHMEM_SIZE	200000
165 #define MB              	(1024*1024)
166 #define MAX_SHMEM_NUMBER        11
167 
168 #define USAGE	"\nUsage: %s [-c num_readers] [-g num_writers] [-s shmem_size]\n\n" \
169 		"\t-c num_readers    number of thread (readers) to create\n" \
170 		"\t-g num_writers    number of thread (writers) to create\n" \
171 		"\t-s buffer_size    size of shared memory segment (bytes)\n" \
172 		"\t                  (must be less than 256MB!)\n\n"
173 
174 /*
175  * Function prototypes
176  *
177  * parse_args (): Parse command line arguments
178  * reader (): Thread program
179  * writer (): "scratch" each and every shared memory segment
180  * sys_error (): System error message function
181  * error (): Error message function
182  * release (): Release the shared memory segments
183  */
184 static void parse_args(int, char **);
185 static void *reader(void *);
186 static void *writer(void *);
187 static void sys_error(const char *, int);
188 static void error(const char *, int);
189 static void release();
190 
191 /*
192  * Global Variables:
193  *
194  * checksum: Array of checksums computed by reader threads
195  * read_count: number of reader threads reading data
196 
197  * num_readers: number of reader threads to create
198  * num_writers: number of writer threads to create
199  * buffer_size: size of "scratch" shared memory segment
200  * parent_pid: Process id of the parent
201  */
202 pthread_t *writer_th;
203 pthread_t *reader_th;
204 
205 pthread_mutex_t mutex_r[MAX_WRITER_NUMBER];
206 pthread_mutex_t cond_mutex[MAX_WRITER_NUMBER];
207 int thread_hold[MAX_WRITER_NUMBER];
208 pthread_cond_t cond_var[MAX_WRITER_NUMBER];
209 
210 int *read_count[MAX_WRITER_NUMBER];	/* Shared memory segment address */
211 unsigned long *checksum[MAX_WRITER_NUMBER];	/* Shared memory segment address */
212 unsigned char *shmptr[MAX_WRITER_NUMBER];	/* Shared memory segment address */
213 unsigned long cksum[MAX_WRITER_NUMBER];	/* Shared memory segment checksum */
214 
215 int shmem_size = DEFAULT_SHMEM_SIZE;
216 pid_t parent_pid;		/* process id of parent */
217 
218 int num_readers = DEFAULT_NUM_READERS;
219 int buffer_size = DEFAULT_SHMEM_SIZE;
220 int num_writers = DEFAULT_NUM_WRITERS;
221 
222 int shmid[MAX_THREAD_NUMBER + MAX_WRITER_NUMBER];
223 
224 /*---------------------------------------------------------------------+
225 |                               main                                   |
226 | ==================================================================== |
227 |                                                                      |
228 | Function:  Main program  (see prolog for more details)               |
229 |                                                                      |
230 | Returns:   (0)  Successful completion                                |
231 |            (-1) Error occurred                                       |
232 |                                                                      |
233 +---------------------------------------------------------------------*/
main(int argc,char ** argv)234 int main(int argc, char **argv)
235 {
236 	pthread_attr_t newattr;
237 
238 	int i;			/* Misc loop index */
239 	int j;			/* Misc loop index */
240 	int k;			/* Misc loop index */
241 	size_t Size;		/* Size (in bytes) of shared memory segment */
242 
243 	unsigned long *ulptr;	/* Misc pointer */
244 	/* Index into shared memory segment */
245 
246 	/*
247 	 * Parse command line arguments and print out program header
248 	 */
249 	parse_args(argc, argv);
250 
251 	printf("%s: IPC Shared Memory TestSuite program\n", *argv);
252 	/*
253 	 * Show options in effect.
254 	 */
255 	printf("\tNumber of writers    = %d\n", num_writers);
256 	printf("\tNumber of readers    = %d\n", num_readers);
257 	printf("\tBytes per writer	= %d\n", buffer_size);
258 
259 /*---------------------------------------------------------------------+
260 |			shared memory segments                         |
261 +---------------------------------------------------------------------*/
262 
263 	for (i = 0; i < num_writers; i++) {
264 		/*
265 		 * Obtain a unique shared memory identifier with shmget ().
266 		 * Attach the shared memory segment to the process with shmat ().
267 		 */
268 
269 		j = i * 3;
270 		Size = sizeof(int);
271 		/*
272 		 * Create a shared memory segment for storing the read count
273 		 * (number of reader threads reading shared data)
274 		 * After creating the shared memory segment, initialize it.
275 		 */
276 
277 		if ((shmid[j] = shmget(IPC_PRIVATE, Size, SHMEM_MODE)) < 0)
278 			sys_error("read_count shmget failed", __LINE__);
279 
280 		if ((long)(read_count[i] = shmat(shmid[j], 0, 0)) == -1)
281 			sys_error("shmat failed", __LINE__);
282 
283 		*(read_count[i]) = 0;
284 
285 		/*
286 		 * Create a shared memory segment for storing the checksums of readers.
287 		 * After creating the shared memory segment, initialize it.
288 		 */
289 
290 		j++;
291 		Size = sizeof(unsigned long) * num_readers;
292 
293 		if ((shmid[j] = shmget(IPC_PRIVATE, Size, SHMEM_MODE)) < 0)
294 			sys_error("checksum shmget failed", __LINE__);
295 
296 		if ((long)(checksum[i] = shmat(shmid[j], 0, 0))
297 		    == -1)
298 			sys_error("shmat failed", __LINE__);
299 
300 		ulptr = checksum[i];
301 
302 		for (k = 0; k < num_readers; k++) {
303 			*ulptr = 0;
304 			ulptr++;
305 		}
306 
307 		/*
308 		 * Create the "scratch" shared memory segment for storing
309 		 * a series of values .
310 		 */
311 
312 		Size = buffer_size;
313 		j++;
314 
315 		if ((shmid[j] = shmget(IPC_PRIVATE, Size, SHMEM_MODE)) < 0)
316 			sys_error("shmptr shmget failed", __LINE__);
317 
318 		if ((long)(shmptr[i] = shmat(shmid[j], 0, 0)) == -1)
319 			sys_error("shmat failed", __LINE__);
320 
321 	}
322 /*---------------------------------------------------------------------+
323 |			Threads                                        |
324 +---------------------------------------------------------------------*/
325 
326 	/*
327 	 * Create threads array...
328 	 */
329 	writer_th = malloc((size_t)(num_writers * sizeof(pthread_t)));
330 	reader_th = malloc((size_t)(num_writers * num_readers * sizeof(pthread_t)));
331 	/*
332 	 * Initializes mutexes and sets their attributes
333 	 */
334 	for (i = 0; i < num_writers; i++) {
335 
336 		if (pthread_mutex_init(&mutex_r[i], NULL) != 0)
337 			sys_error("Can't initialize mutex_r", __LINE__);
338 
339 		if (pthread_mutex_init(&cond_mutex[i], NULL))
340 			sys_error("Can't initialize cond_mutex", __LINE__);
341 		if (pthread_cond_init(&cond_var[i], NULL))
342 			sys_error("cond_init(&cond_var) failed", __LINE__);
343 		/*
344 		 * lock the access to the shared memory data segment --
345 		 * get lock now to insure the writer gets first access to the segment.
346 		 *
347 		 */
348 
349 		thread_hold[i] = 1;
350 
351 	}
352 
353 	/*
354 	 * Creates a thread attributes object and initializes it
355 	 * with default values.
356 	 */
357 	if (pthread_attr_init(&newattr))
358 		sys_error("attr_init(&newattr) failed", __LINE__);
359 	/*
360 	 * Sets the value of the detachstate attribute of a thread attributes
361 	 * object :
362 	 * PTHREAD_CREATE_UNDETACHED    Specifies that the thread will be
363 	 * created in undetached state.
364 	 */
365 #ifdef _LINUX_
366 	// the DEFAULT state for linux pthread_create is to be "undetatched" or joinable
367 	/* if (pthread_attr_setdetachstate (&newattr, PTHREAD_CREATE_JOINABLE))
368 	   sys_error ("attr_setdetachstate(&newattr) failed", __LINE__); */
369 #else
370 	if (pthread_attr_setdetachstate(&newattr, PTHREAD_CREATE_UNDETACHED))
371 		sys_error("attr_setdetachstate(&newattr) failed", __LINE__);
372 #endif
373 
374 	/*
375 	 * Create all num_writers threads .  Each writer thread will fill
376 	 * the "scratch" shared memory segment (shmptr) up with data and
377 	 * will store the result in cksum array accessible by the main.
378 	 */
379 
380 	for (i = 0; i < num_writers; i++) {
381 		if (pthread_create
382 		    (&writer_th[i], &newattr, writer, (void *)(long)i))
383 			sys_error("writer: pthread_create failed", __LINE__);
384 
385 		/*
386 		 * Create all num_readers threads .  Each reader thread will compute
387 		 * the checksum of the shared memory segment (shmptr) and will store
388 		 * the result in the other shared memory segment (checksum)accessible
389 		 * by the writer.
390 		 */
391 
392 		k = i * num_readers;
393 		for (j = k; j < (k + num_readers); j++) {
394 			if (pthread_create
395 			    (&reader_th[j], &newattr, reader, (void *)(long)j))
396 				sys_error("reader: pthread_create failed",
397 					  __LINE__);
398 		}
399 	}
400 
401 	for (i = 0; i < num_writers; i++) {
402 		if (pthread_join(writer_th[i], NULL)) {
403 			printf("writer_th: pthread_join return: %d\n", i);
404 			sys_error("pthread_join bad status", __LINE__);
405 		}
406 
407 		/*
408 		 * Wait for the reader threads to compute the checksums and complete.
409 		 */
410 		k = i * num_readers;
411 		for (j = k; j < (k + num_readers); j++) {
412 			if (pthread_join(reader_th[j], NULL)) {
413 				printf("reader_th: pthread_join return: %d\n",
414 				       j);
415 				sys_error("pthread_join bad status", __LINE__);
416 			}
417 		}
418 	}
419 
420 	/*
421 	 * After the threads complete, check their exit status to insure
422 	 * that they ran to completion and then verify the corresponding
423 	 * checksum.
424 	 */
425 	for (i = 0; i < num_writers; i++) {
426 		ulptr = checksum[i];
427 		for (j = 0; j < num_readers; j++) {
428 
429 			if (cksum[i] != *ulptr)
430 				error("checksums do not match", __LINE__);
431 
432 		}
433 	}
434 	printf("\n\tMain: readers calculated segment successfully\n");
435 
436 	release();
437 	printf("\nsuccessful!\n");
438 
439 	return (0);
440 }
441 
442 /*---------------------------------------------------------------------+
443 |                               writer ()                              |
444 | ==================================================================== |
445 |                                                                      |
446 | Function:  Fill the "scratch" shared memory segment up with data and |
447 |            compute the segment checksum.                             |
448 |            Release "write" lock after completing so that the readers |
449 |	     are able to start.                                        |
450 |	                                                               |
451 | Updates:   cksum[]  - array containing checksums computed by writers.|
452 |	     data shared memory segment filled up.                     |
453 |                                                                      |
454 +---------------------------------------------------------------------*/
writer(void * parm)455 void *writer(void *parm)
456 {
457 	int num_w = (int)(long)parm;
458 	unsigned long cksum_w = 0;	/* Shared memory regions checksum */
459 	unsigned char data = 0;	/* Value written into shared memory segment */
460 	unsigned char *ptr;	/* Misc pointer */
461 
462 	/*
463 	 * Fill the "scratch" shared memory segment up with data and
464 	 * compute the segments checksum.  Release "write" lock after
465 	 * completing so that the reader threads may begin to read the
466 	 * data.
467 	 */
468 	data = num_w;
469 
470 	for (ptr = shmptr[num_w]; ptr < (shmptr[num_w] + buffer_size); ptr++) {
471 		*ptr = (data++) % (UCHAR_MAX + 1);
472 		cksum_w += *ptr;
473 	}
474 	if (pthread_mutex_lock(&cond_mutex[num_w]))
475 		sys_error("mutex_lock(&cond_mutex) failed", __LINE__);
476 	thread_hold[num_w] = 0;
477 	if (pthread_cond_broadcast(&cond_var[num_w]))
478 		sys_error("cond_signal(&cond_var) failed", __LINE__);
479 	if (pthread_mutex_unlock(&cond_mutex[num_w]))
480 		sys_error("mutex_unlock(&cond_mutex) failed", __LINE__);
481 
482 	cksum[num_w] = cksum_w;
483 	printf("\t\twriter (%03d): shared memory checksum %08lx\n", num_w,
484 	       cksum_w);
485 
486 	return NULL;
487 }
488 
489 /*---------------------------------------------------------------------+
490 |                               reader ()                              |
491 | ==================================================================== |
492 |                                                                      |
493 | Function:  Waits for read access to the shared memory segment,       |
494 |            computes the shared memory segments checksum and releases |
495 |            the read lock.  Then stores the checksum.                 |
496 |                                                                      |
497 | Updates:   checksum - shared memory segment containing checksums     |
498 |                       computed by reader threads                     |
499 |                                                                      |
500 +---------------------------------------------------------------------*/
reader(void * parm)501 void *reader(void *parm)
502 {
503 	int num_p = (int)(long)parm;
504 	unsigned long cksum_r = 0;	/* Shared memory regions checksum */
505 	int i;			/* Misc index */
506 	int num_r;		/* Misc index */
507 	int num_w;		/* Misc index */
508 	unsigned char *ptr;	/* Misc pointer */
509 	unsigned long *ulptr_r;	/* Misc pointer */
510 
511 	/*
512 	 * Wait for a READ_COUNT lock on the shared memory segment, then
513 	 * compute the checksum and release the READ_COUNT lock.
514 	 */
515 
516 	num_r = num_p % num_readers;
517 	num_w = num_p - num_r;
518 	num_w = num_w / num_readers;
519 	ptr = shmptr[num_w];
520 	ulptr_r = checksum[num_w];
521 
522 	if (pthread_mutex_lock(&cond_mutex[num_w]))
523 		sys_error("Can't take cond lock", __LINE__);
524 	/*
525 	 * Check to see if we need to wait: if yes, wait for the condition
526 	 * variable (blocking wait).
527 	 */
528 	while (thread_hold[num_w]) {
529 		if (pthread_cond_wait(&cond_var[num_w], &cond_mutex[num_w]))
530 			sys_error("cond_wait failed", __LINE__);
531 	}
532 	if (pthread_mutex_unlock(&cond_mutex[num_w]))
533 		sys_error("Can't release cond lock", __LINE__);
534 
535 	if (pthread_mutex_lock(&mutex_r[num_w]))
536 		sys_error("Can't take read lock", __LINE__);
537 
538 	(*(read_count[num_w]))++;
539 
540 	if (pthread_mutex_unlock(&mutex_r[num_w]))
541 		sys_error("Can't release read lock", __LINE__);
542 
543 	for (i = 0; i < buffer_size; i++)
544 		cksum_r += *ptr++;
545 
546 	if (pthread_mutex_lock(&mutex_r[num_w]))
547 		sys_error("Can't take read lock", __LINE__);
548 	(*(read_count[num_w]))--;
549 	if (pthread_mutex_unlock(&mutex_r[num_w]))
550 		sys_error("Can't release 1 read lock", __LINE__);
551 
552 	/*
553 	 * Store the resulting checksum and print out a message
554 	 */
555 
556 	*ulptr_r = cksum_r;
557 	printf("\t\treader (%03d) of writer (%03d): checksum %08lx\n", num_r,
558 	       num_w, cksum_r);
559 	return NULL;
560 }
561 
562 /*---------------------------------------------------------------------+
563 |                             parse_args ()                            |
564 | ==================================================================== |
565 |                                                                      |
566 | Function:  Parse the command line arguments & initialize global      |
567 |            variables.                                                |
568 |                                                                      |
569 | Updates:   (command line options)                                    |
570 |                                                                      |
571 |            [-s] size: shared memory segment size                     |
572 |                                                                      |
573 |            [-c] num_readers: number of reader threads                |
574 |                                                                      |
575 |            [-g] num_writers: number of writer threads                |
576 |                                                                      |
577 +---------------------------------------------------------------------*/
parse_args(int argc,char ** argv)578 void parse_args(int argc, char **argv)
579 {
580 	int i;
581 	int errflag = 0;
582 	char *program_name = *argv;
583 	extern char *optarg;	/* Command line option */
584 
585 	while ((i = getopt(argc, argv, "c:s:g:?")) != EOF) {
586 		switch (i) {
587 		case 'c':
588 			num_readers = atoi(optarg);
589 			break;
590 		case 's':
591 			buffer_size = atoi(optarg);
592 			break;
593 		case 'g':	/* number of group */
594 			num_writers = atoi(optarg);
595 			break;
596 		case '?':
597 			errflag++;
598 			break;
599 		}
600 	}
601 	if (num_writers >= MAX_WRITER_NUMBER) {
602 		errflag++;
603 		fprintf(stderr, "ERROR: num_writers must be less than %d\n",
604 			MAX_WRITER_NUMBER);
605 	}
606 	if (num_readers >= MAX_READER_NUMBER) {
607 		errflag++;
608 		fprintf(stderr, "ERROR: num_readers must be less than %d\n",
609 			MAX_READER_NUMBER);
610 	}
611 	i = num_readers * num_writers;
612 	if (i >= MAX_THREAD_NUMBER) {
613 		errflag++;
614 		fprintf(stderr,
615 			"ERROR: maximun threads number must be less than %d\n",
616 			MAX_THREAD_NUMBER);
617 	}
618 
619 	if (errflag) {
620 		fprintf(stderr, USAGE, program_name);
621 		exit(2);
622 	}
623 }
624 
625 /*---------------------------------------------------------------------+
626 |                             release ()                               |
627 | ==================================================================== |
628 |                                                                      |
629 | Function:  Release shared memory regions.                            |
630 |                                                                      |
631 +---------------------------------------------------------------------*/
release()632 void release()
633 {
634 	int i;
635 	int j;
636 	for (i = 0; i < num_writers; i++) {
637 		if (pthread_mutex_destroy(&cond_mutex[i]) != 0)
638 			sys_error("Can't destroy cond_mutex", __LINE__);
639 		if (pthread_mutex_destroy(&mutex_r[i]) != 0)
640 			sys_error("Can't destroy mutex_r", __LINE__);
641 	}
642 
643 	for (i = 0; i < num_writers; i++) {
644 		/*
645 		 * Release shared memory regions
646 		 */
647 		j = i * 3;
648 		if (shmctl(shmid[j], IPC_RMID, 0) < 0)
649 			sys_error("read_count shmctl failed", __LINE__);
650 		j++;
651 		if (shmctl(shmid[j], IPC_RMID, 0) < 0)
652 			sys_error("checksum shmctl failed", __LINE__);
653 		j++;
654 		if (shmctl(shmid[j], IPC_RMID, 0) < 0)
655 			sys_error("shmptr shmctl failed", __LINE__);
656 
657 	}
658 }
659 
660 /*---------------------------------------------------------------------+
661 |                             sys_error ()                             |
662 | ==================================================================== |
663 |                                                                      |
664 | Function:  Creates system error message and calls error ()           |
665 |                                                                      |
666 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)667 void sys_error(const char *msg, int line)
668 {
669 	char syserr_msg[256];
670 
671 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
672 	error(syserr_msg, line);
673 }
674 
675 /*---------------------------------------------------------------------+
676 |                               error ()                               |
677 | ==================================================================== |
678 |                                                                      |
679 | Function:  Prints out message and exits...                           |
680 |                                                                      |
681 +---------------------------------------------------------------------*/
error(const char * msg,int line)682 void error(const char *msg, int line)
683 {
684 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
685 	if (line >= 260)
686 		release();
687 	exit(-1);
688 }
689