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 |                            pipe_test_02                              |
     21 | ==================================================================== |
     22 |                                                                      |
     23 | Description:  Max data transfer through pipe interprocess channel    |
     24 |               in non-blocking mode                                   |
     25 |                                                                      |
     26 | Algorithm:    o  Create a pipe                                       |
     27 |               o  Make write & read end of pipe non-blocking          |
     28 |               o  Spawn a child process                               |
     29 |               o  parent:                                             |
     30 |                  -  create & send data packets to the child          |
     31 |                  -  compute checksum on sent packets                 |
     32 |               o  child:                                              |
     33 |                  -  recieve packets from parent & compute checksum   |
     34 |                  -  send final checksum to parent                    |
     35 |               o  parent:                                             |
     36 |                  -  compare checksum of sent packets with the        |
     37 |                     child's checksum                                 |
     38 |                                                                      |
     39 | System calls: The following system calls are tested:                 |
     40 |                                                                      |
     41 |               pipe () - Creates an interprocess channel              |
     42 |               fork () - Creates a new process                        |
     43 |               fcntl () -                                             |
     44 |               waitpid () - Waits for a child process to stop or      |
     45 |                                                                      |
     46 | Usage:        pipe_test_02                                           |
     47 |                                                                      |
     48 | To compile:   cc -o pipe_test_02 pipe_test_02.c                      |
     49 |                                                                      |
     50 | Last update:   Ver. 1.3, 3/3/94 12:06:38                           |
     51 |                                                                      |
     52 | Change Activity                                                      |
     53 |                                                                      |
     54 |   Version  Date    Name  Reason                                      |
     55 |    0.1     010393  DJK   Initial version for AIX 4.1                 |
     56 |    1.2     021394  DJK   Move to "prod" directory                    |
     57 |                                                                      |
     58 +---------------------------------------------------------------------*/
     59 
     60 #include <errno.h>
     61 #include <fcntl.h>
     62 #include <signal.h>
     63 #include <stdio.h>
     64 #include <stdlib.h>
     65 #include <string.h>
     66 #include <sys/types.h>
     67 #include <sys/wait.h>
     68 #include <unistd.h>
     69 
     70 /* Defines:
     71  *
     72  * MB: one megabyte (MB)
     73  *
     74  * VALID_PACKET: value sent with each packet, used to verify that the
     75  * packets contents were not garbled.
     76  *
     77  * DEFAULT_NUM_CHILDREN: default number of child processes spawned
     78  *
     79  * DEFAULT_PACKETS_TO_SEND: default number of packets sent to each child
     80  * process.
     81  *
     82  * MAXCHILD: maximum number of child processes which may be spawned
     83  * (based upon the number of file descriptors that a process may use)
     84  *
     85  * USAGE: usage statement
     86  */
     87 #define MB			(1024*1024)
     88 #define DEFAULT_PACKETS_TO_SEND 1024
     89 #define DEFAULT_NUM_CHILDREN	1
     90 #define OPEN_MAX		256
     91 #define MAXCHILD 		(OPEN_MAX/2 - 2)
     92 #define VALID_PACKET		0xabcdef01
     93 #define USAGE	"\nUsage: %s [-n] [-p nprocs] [{-m totmegs | -b totbytes}]\n\n" \
     94 		"\t-n          transfer data with NON-BLOCKING reads & writes\n" \
     95 		"\t-p nprocs   number of child processes to spawn\n" \
     96 		"\t-m totmegs  number of MB to send through pipe\n" \
     97 		"\t-b totmegs  number of bytes to send through pipe\n" \
     98 		"\t                  (must be less than %d)\n\n"
     99 
    100 /*
    101  * Function Prototypes:
    102  *
    103  * setup (): Parse command line arguments and intialize variables
    104  * child (): Child process
    105  * cleanup (): Close all pipes and kill child processes
    106  * sys_error (): System error message function
    107  * error (): Error message function
    108  * setup_signal_handlers (): Sets up signal catching functions
    109  * handler (): Signal catching function
    110  */
    111 void setup(int, char **);
    112 void child(int[], int[]);
    113 void cleanup();
    114 void sys_error(const char *, int);
    115 void error(const char *, int);
    116 void setup_signal_handlers();
    117 void handler(int, int, struct sigcontext *);
    118 
    119 /*
    120  * Structures & Global variables
    121  *
    122  * num_children: number of child processes to be spawned
    123  *
    124  * num_packets: number of packets to be sent to each child process
    125  *
    126  * non_blocking_flag: uses NON-BLOCKING
    127  *
    128  * pid: process id's of the spawned processes
    129  *
    130  * p2child: half duplex pipes from parent to child (parent writes,
    131  *          child reads).
    132  *
    133  * p2parent: half duplex pipe from child to parent (child writes,
    134  *           parent reads).
    135  */
    136 
    137 enum { READ, WRITE };		/* Pipe read & write end indices */
    138 
    139 struct data_packet {
    140 	pid_t pid;		/* Child process id */
    141 	int last;		/* Indicates last packet when set */
    142 	long valid;		/* Insure packet was not garbled */
    143 	long seq_number;	/* Packet sequence number */
    144 	unsigned long checksum;	/* Cumulative checksum so far */
    145 	unsigned char data;	/* Data sent in packet */
    146 };
    147 typedef struct data_packet data_packet;
    148 
    149 int num_children = DEFAULT_NUM_CHILDREN;
    150 long num_packets = DEFAULT_PACKETS_TO_SEND;
    151 int non_blocking_flag = 0;	/* Uses NON-BLOCKING pipes when set */
    152 int bflg = 0;			/* Data quantity flag (MB) */
    153 int mflg = 0;			/* Data quantity flag (bytes) */
    154 
    155 pid_t parent_pid;		/* Parent's process id */
    156 pid_t pid[MAXCHILD];		/* Process id's of spawned processes */
    157 int p2child[MAXCHILD][2];	/* Pipes from parent to child processes */
    158 int p2parent[2];		/* Pipe from child processes to parent */
    159 char err_msg[256];		/* Generic error message buffer */
    160 
    161 /*---------------------------------------------------------------------+
    162 |                               main ()                                |
    163 | ==================================================================== |
    164 |                                                                      |
    165 | Function:  Main program  (see prolog for more details)               |
    166 |                                                                      |
    167 | Returns:   (0)  Successful completion                                |
    168 |            (-1) Error occurred                                       |
    169 |                                                                      |
    170 +---------------------------------------------------------------------*/
    171 int main(int argc, char **argv)
    172 {
    173 	int i;
    174 	int n;			/* Number of bytes written */
    175 	int status;		/* Child's exit status */
    176 	long packets_sent;
    177 	unsigned char data;
    178 	unsigned long cksum_parent = 0;
    179 	data_packet packet;
    180 
    181 	/*
    182 	 * Parse command line arguments, initialize global variables and
    183 	 * print program header
    184 	 */
    185 	setup(argc, argv);
    186 	printf("%s: IPC Pipe TestSuite program\n", *argv);
    187 	fflush(stdout);
    188 
    189 	/*
    190 	 * Create two sets of half duplex pipes:
    191 	 *
    192 	 * p2child: for sending packets from the parent process to the child
    193 	 *          processes and
    194 	 * p2parent: for sending checksums from the child processes to the
    195 	 *           parent
    196 	 *
    197 	 * If the non-blocking command line option was specified, use fcntl ()
    198 	 * to set the O_NONBLOCK file descriptor status flags.  This will
    199 	 * prevent reads & and writes from blocking if the data is not yet
    200 	 * available
    201 	 */
    202 	printf("\n\tCreating pipes...\n");
    203 	fflush(stdout);
    204 
    205 	if (pipe(p2parent) < 0)
    206 		sys_error("pipe failed", __LINE__);
    207 
    208 	if (non_blocking_flag) {
    209 		printf("\n\tSending data NON-BLOCKING!\n");
    210 		fflush(stdout);
    211 	}
    212 
    213 	for (i = 0; i < num_children; i++) {
    214 		if (pipe(&p2child[i][0]) < 0)
    215 			sys_error("pipe failed", __LINE__);
    216 		if (non_blocking_flag) {
    217 			if (fcntl(p2child[i][READ], F_SETFL, O_NONBLOCK) < 0)
    218 				sys_error("fcntl (O_NONBLOCK) failed",
    219 					  __LINE__);
    220 			if (fcntl(p2child[i][WRITE], F_SETFL, O_NONBLOCK) < 0)
    221 				sys_error("fcntl (O_NONBLOCK) failed",
    222 					  __LINE__);
    223 		}
    224 	}
    225 
    226 	/*
    227 	 * Spawn num_children processes
    228 	 *
    229 	 * Fork of the child process & record the newly created process's
    230 	 * id for future reference.
    231 	 *
    232 	 * Then close the READ end of the p2child pipe, since the parent
    233 	 * process will be writing into this pipe rather than reading.
    234 	 * Also close the WRITE end of the p2parent pipe, for just the
    235 	 * the reverse reasons...
    236 	 */
    237 	printf("\n\tSpawning %d child processes ... \n", num_children);
    238 	fflush(stdout);
    239 
    240 	for (i = 0; i < num_children; i++) {
    241 
    242 		if ((pid[i] = fork()) == 0) {
    243 
    244 			/* Child process */
    245 			child(&p2child[i][0], p2parent);
    246 			exit(0);
    247 
    248 		} else if (pid[i] < (pid_t) 0)
    249 			sys_error("fork failed", __LINE__);
    250 
    251 		if (close(p2child[i][READ]) < 0)
    252 			sys_error("close failed", __LINE__);
    253 	}
    254 	if (close(p2parent[WRITE]) < 0)
    255 		sys_error("close failed", __LINE__);
    256 
    257 	/*
    258 	 * Send data packets to the child processes
    259 	 *
    260 	 * Build packets (initialize all of the packets fields) and then
    261 	 * send the packets to all of the child processes.
    262 	 *
    263 	 * Might have to make several attempts with the NON-BLOCKING writes
    264 	 * if the resource is not immediately available.
    265 	 */
    266 	printf
    267 	    ("\n\tParent: sending %ld packets (%ld bytes) to child processes ...\n",
    268 	     num_packets, num_packets * sizeof(struct data_packet));
    269 
    270 	packet.last = 0;
    271 	packet.valid = VALID_PACKET;
    272 
    273 	for (packets_sent = data = 0; num_packets > 0; num_packets--) {
    274 
    275 		packet.seq_number = ++packets_sent;
    276 		packet.data = data++;
    277 		packet.pid = pid[i];
    278 		packet.checksum = cksum_parent += packet.data;
    279 
    280 		for (i = 0; i < num_children; i++) {
    281 try_write_ETXN_again:
    282 			if ((n = write(p2child[i][WRITE], &packet,
    283 				       sizeof(packet))) < 0) {
    284 				if (non_blocking_flag && errno == EAGAIN) {
    285 					goto try_write_ETXN_again;
    286 				} else {
    287 					sys_error("write failed", __LINE__);
    288 				}
    289 			}
    290 		}
    291 	}
    292 
    293 	/*
    294 	 * Send the last packet to the child processes
    295 	 *
    296 	 * [ Upon receiving this packet, the child process will know that all
    297 	 *   of the packets have been sent and that the parent process is
    298 	 *   expecting the child to send it's checksum back. ]
    299 	 *
    300 	 * After sending the last packet, close the WRITE end of the p2child
    301 	 * pipe as we are finish sending packets to the child processes.
    302 	 *
    303 	 * Then wait for all of the child processes to send the checksum
    304 	 * packets.  Upon receiving the checksum packets verify that the
    305 	 * child's checksum matches that of the parent.
    306 	 *
    307 	 * Might have to make several attempts with the NON-BLOCKING writes
    308 	 * if the resource is not immediately available.
    309 	 *
    310 	 * Finally, close READ end of p2parent pipe as we have finished
    311 	 * receiving checksums from the child.
    312 	 */
    313 	packet.last = 1;
    314 	printf
    315 	    ("\n\tParent: done sending packets & waiting for children to complete!\n");
    316 	for (i = 0; i < num_children; i++) {
    317 try_read_again:
    318 		if (write(p2child[i][WRITE], &packet, sizeof(packet)) < 0) {
    319 			if (non_blocking_flag && errno == EAGAIN) {
    320 				goto try_read_again;
    321 			} else {
    322 				sys_error("write failed", __LINE__);
    323 			}
    324 		}
    325 		if (close(p2child[i][WRITE]) < 0)
    326 			sys_error("close failed", __LINE__);
    327 
    328 		if (read(p2parent[READ], &packet, sizeof(packet)) <= 0)
    329 			sys_error("read failed", __LINE__);
    330 
    331 		if (packet.valid != VALID_PACKET)
    332 			error("received packet with corrupted data from child!",
    333 			      __LINE__);
    334 
    335 		if (cksum_parent != packet.checksum) {
    336 			sprintf(err_msg, "checksum of data sent by parent "
    337 				"does not match checksum of data received by "
    338 				"child [pid %d]\n"
    339 				"\tchild's checksum: %08lx\n"
    340 				"\tparent's checksum: %08lx\n",
    341 				packet.pid, packet.checksum, cksum_parent);
    342 			error(err_msg, __LINE__);
    343 		}
    344 	}
    345 	if (close(p2parent[READ]) < 0)
    346 		sys_error("close failed", __LINE__);
    347 
    348 	/*
    349 	 * Wait for all of the child processes to complete & check their
    350 	 * exit status.
    351 	 *
    352 	 * Upon completion of the child proccesses, exit program with success.
    353 	 */
    354 	for (i = 0; i < num_children; i++) {
    355 		waitpid(pid[i], &status, 0);
    356 
    357 		if (!WIFEXITED(status))
    358 			sys_error("child process terminated abnormally",
    359 				  __LINE__);
    360 	}
    361 	printf
    362 	    ("\n\tParent: children received all packets & exited successfully\n");
    363 
    364 	/* Program completed successfully -- exit */
    365 	printf("\nsuccessful!\n");
    366 
    367 	return (0);
    368 }
    369 
    370 /*---------------------------------------------------------------------+
    371 |                               child ()                               |
    372 | ==================================================================== |
    373 |                                                                      |
    374 | Function:  Receive packets from the parent, insure they are valid    |
    375 |            and not out of sequence, and calculate a running          |
    376 |            checksum.  Upon receiving the last packet from the        |
    377 |            parent, build a checksum packet and send it to the parent.|
    378 |                                                                      |
    379 | Args:      p2child   - Pipe from parent to child                     |
    380 |            p2parent  - Pipe from child to parent                     |
    381 |                                                                      |
    382 | Returns:   Exits with (-1) if an error occurs                        |
    383 |                                                                      |
    384 +---------------------------------------------------------------------*/
    385 void child(int p2child[], int p2parent[])
    386 {
    387 	int n;			/* Bytes read */
    388 	pid_t pid = getpid();	/* Process id of child */
    389 	int end_of_transmission = 0;
    390 	long packets_received = 0;	/* Number of packets received
    391 					 * from parent
    392 					 */
    393 
    394 	data_packet packet;	/* Packet used to transmiting data */
    395 	unsigned long cksum_child = 0;	/* Checksum of data fields received */
    396 
    397 	/*
    398 	 * Close the WRITE end of the p2child pipe, since the child
    399 	 * process will be reading from this pipe rather than writing.
    400 	 * Also close the READ end of the p2parent pipe, for just the
    401 	 * the reverse reasons...
    402 	 */
    403 	if (close(p2child[WRITE]) < 0)
    404 		sys_error("close failed", __LINE__);
    405 	if (close(p2parent[READ]) < 0)
    406 		sys_error("close failed", __LINE__);
    407 
    408 	/*
    409 	 * Receive packets from parent & insure packets are valid
    410 	 *
    411 	 * Read packets from the parent through p2child pipe.  Upon
    412 	 * recieving the packet, verify that it is valid, in sequence
    413 	 * and that both the parent's and child's checksums match.
    414 	 *
    415 	 * Might have to make several attempts with the NON-BLOCKING
    416 	 * reads if the resource is not immediately available.
    417 	 *
    418 	 * Continue reading packets until the "last" packet is received
    419 	 * from the parent.  Upon receiving the last packet, close
    420 	 * the p2child READ pipe, as we are finished receiving packets
    421 	 * from the parent.
    422 	 */
    423 	while (!end_of_transmission) {
    424 try_write_again:
    425 		n = read(p2child[READ], &packet, sizeof(packet));
    426 		if (n < 0) {
    427 			/* Resource not available */
    428 			if (non_blocking_flag && errno == EAGAIN)
    429 				goto try_write_again;
    430 			else
    431 				sys_error("read failed", __LINE__);
    432 		} else if (n > 0) {
    433 			/* Insure packet is valid */
    434 			if (packet.valid != VALID_PACKET) {
    435 				sprintf(err_msg,
    436 					"child received invalid packet "
    437 					"from parent:\n\tpacket #: %ld\n",
    438 					packets_received);
    439 				error(err_msg, __LINE__);
    440 			}
    441 			/* Received last packet */
    442 			if (packet.last) {
    443 				end_of_transmission = 1;
    444 			} else {
    445 
    446 				/* Insure packet was not received out of sequence */
    447 				packets_received++;
    448 				if (packets_received != packet.seq_number) {
    449 					sprintf(err_msg,
    450 						"child received packet out of sequence\n"
    451 						"\texpecting packet: %ld\n"
    452 						"\treceived packet:  %ld\n",
    453 						packets_received,
    454 						packet.seq_number);
    455 					error(err_msg, __LINE__);
    456 				}
    457 
    458 				/* Insure checksums still match */
    459 				cksum_child += packet.data;
    460 				if (cksum_child != packet.checksum) {
    461 					sprintf(err_msg,
    462 						"child & parent checksums do not match\n"
    463 						"\tchild checksum:  %08lx\n"
    464 						"\tparent checksum: %08lx\n"
    465 						"\tpacket number:   %ld\n",
    466 						cksum_child, packet.checksum,
    467 						packets_received);
    468 					error(err_msg, __LINE__);
    469 				}
    470 			}
    471 		}
    472 	}
    473 	if (close(p2child[READ]) < 0)
    474 		sys_error("close failed", __LINE__);
    475 
    476 	/*
    477 	 * Send parent packet containing child's checksum
    478 	 *
    479 	 * Build a checksum packet (initialize packet fields) and then
    480 	 * send the packet to the parent.
    481 	 *
    482 	 * Then close the WRITE p2parent pipe as we have finished sending packets
    483 	 * to the parent.
    484 	 */
    485 	printf("\t\tChild:  pid [%d] received %ld packets from parent\n",
    486 	       pid, packets_received);
    487 
    488 	packet.pid = pid;
    489 	packet.valid = VALID_PACKET;
    490 	packet.checksum = cksum_child;
    491 
    492 	if (write(p2parent[WRITE], &packet, sizeof(packet)) < 0)
    493 		sys_error("write failed", __LINE__);
    494 	if (close(p2parent[WRITE]) < 0)
    495 		sys_error("close failed", __LINE__);
    496 }
    497 
    498 /*---------------------------------------------------------------------+
    499 |                               setup ()                               |
    500 | ==================================================================== |
    501 |                                                                      |
    502 | Function:  Parse the command line arguments & initialize global      |
    503 |            variables.                                                |
    504 |                                                                      |
    505 | Updates:   (command line options)                                    |
    506 |                                                                      |
    507 |            [-n] non_blocking_flag: prevents read & write calls from  |
    508 |                 from blocking if the resource is not available.      |
    509 |                                                                      |
    510 |            [-p] num_packets: number of packets ...                   |
    511 |                                                                      |
    512 |            [-c] num_children: number of child processes to spawn ... |
    513 |                                                                      |
    514 +---------------------------------------------------------------------*/
    515 void setup(int argc, char **argv)
    516 {
    517 	int i;
    518 	int errflag = 0;
    519 	int bytes = 0, megabytes = 0;
    520 	char *program_name = *argv;
    521 	extern char *optarg;	/* Command line option */
    522 
    523 	while ((i = getopt(argc, argv, "nm:b:p:?")) != EOF) {
    524 		switch (i) {
    525 		case 'n':	/* NON-BLOCKING flag */
    526 			non_blocking_flag++;
    527 			break;
    528 		case 'm':	/* MB */
    529 			mflg++;
    530 			megabytes = atoi(optarg);
    531 			break;
    532 		case 'b':	/* bytes */
    533 			bflg++;
    534 			bytes = atoi(optarg);
    535 			break;
    536 		case 'p':	/* number of child procs */
    537 			num_children = atoi(optarg);
    538 			break;
    539 		case '?':
    540 			errflag++;
    541 			break;
    542 		}
    543 	}
    544 	if (mflg) {
    545 		num_packets = megabytes * MB / sizeof(struct data_packet);
    546 	} else if (bflg) {
    547 		num_packets = bytes / sizeof(struct data_packet);
    548 	}
    549 
    550 	if (num_packets == 0 || num_children == 0 || num_children > MAXCHILD)
    551 		errflag++;
    552 
    553 	if (errflag) {
    554 		fprintf(stderr, USAGE, program_name, MAXCHILD);
    555 		exit(2);
    556 	}
    557 	/*
    558 	 * Setup signal catching function for SIGPIPE & SIGINT, record
    559 	 * the process id of the parent and initialize the child process
    560 	 * id array.
    561 	 */
    562 	setup_signal_handlers();
    563 
    564 	parent_pid = getpid();
    565 
    566 	for (i = 0; i < num_children; i++) {
    567 		pid[i] = (pid_t) 0;
    568 	}
    569 }
    570 
    571 /*---------------------------------------------------------------------+
    572 |                          setup_handler ()                            |
    573 | ==================================================================== |
    574 |                                                                      |
    575 | Function:  Setup the signal handler for SIGPIPE.                     |
    576 |                                                                      |
    577 +---------------------------------------------------------------------*/
    578 void setup_signal_handlers()
    579 {
    580 	struct sigaction invec;
    581 
    582 	invec.sa_handler = (void (*)(int))handler;
    583 	sigemptyset(&invec.sa_mask);
    584 	invec.sa_flags = 0;
    585 
    586 	if (sigaction(SIGINT, &invec, NULL) < 0)
    587 		sys_error("sigaction failed", __LINE__);
    588 
    589 	if (sigaction(SIGPIPE, &invec, NULL) < 0)
    590 		sys_error("sigaction failed", __LINE__);
    591 }
    592 
    593 /*---------------------------------------------------------------------+
    594 |                             handler ()                               |
    595 | ==================================================================== |
    596 |                                                                      |
    597 | Function:  Signal catching function for SIGPIPE signal.              |
    598 |                                                                      |
    599 |            o  SIGPIPE: Print message and abort program...            |
    600 |                                                                      |
    601 |            o  SIGINT:  Parent process calls cleanup, child processes |
    602 |                        simply exit                                   |
    603 |                                                                      |
    604 |            o  Other:   Print message and abort program...            |
    605 |                                                                      |
    606 +---------------------------------------------------------------------*/
    607 void handler(int sig, int code, struct sigcontext *scp)
    608 {
    609 	char msg[100];		/* Buffer for error message */
    610 
    611 	if (sig == SIGPIPE) {
    612 		error("wrote to pipe with closed read end", __LINE__);
    613 	} else if (sig == SIGINT) {
    614 		if (getpid() == parent_pid) {
    615 
    616 			fprintf(stderr, "Received SIGINT -- cleaning up...\n");
    617 			fflush(stderr);
    618 
    619 			cleanup();
    620 		} else
    621 			exit(-1);
    622 	} else {
    623 		sprintf(msg, "Received an unexpected signal (%d)", sig);
    624 		error(msg, __LINE__);
    625 	}
    626 }
    627 
    628 /*---------------------------------------------------------------------+
    629 |                             cleanup ()                               |
    630 | ==================================================================== |
    631 |                                                                      |
    632 | Function:  Closes all of the pipes, kills all of the child           |
    633 |            processes and exits the program...                        |
    634 |                                                                      |
    635 +---------------------------------------------------------------------*/
    636 void cleanup()
    637 {
    638 	int i;
    639 
    640 	if (getpid() == parent_pid) {
    641 		for (i = 0; i < num_children; i++) {
    642 			if (pid[i] > (pid_t) 0 && kill(pid[i], SIGKILL) < 0)
    643 				sys_error("signal failed", __LINE__);
    644 
    645 			close(p2child[i][READ]);
    646 			close(p2child[i][WRITE]);
    647 			close(p2parent[READ]);
    648 			close(p2parent[WRITE]);
    649 		}
    650 	}
    651 
    652 	exit(-1);
    653 }
    654 
    655 /*---------------------------------------------------------------------+
    656 |                             sys_error ()                             |
    657 | ==================================================================== |
    658 |                                                                      |
    659 | Function:  Creates system error message and calls error ()           |
    660 |                                                                      |
    661 +---------------------------------------------------------------------*/
    662 void sys_error(const char *msg, int line)
    663 {
    664 	char syserr_msg[256];
    665 
    666 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
    667 	error(syserr_msg, line);
    668 }
    669 
    670 /*---------------------------------------------------------------------+
    671 |                               error ()                               |
    672 | ==================================================================== |
    673 |                                                                      |
    674 | Function:  Prints out message and calls cleanup...                   |
    675 |                                                                      |
    676 +---------------------------------------------------------------------*/
    677 void error(const char *msg, int line)
    678 {
    679 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
    680 	fflush(stderr);
    681 	cleanup();
    682 }
    683