Home | History | Annotate | Download | only in ipc_stress
      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 +---------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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