/****************************************************************************\ prisoner: solution to EECS 338 Assignment #2 Andrew Witte 8 February 2006 \****************************************************************************/ #include #include #include #include #define READ_END (0) #define WRITE_END (1) /* Function to perform the actions of the 'prisoner' child process */ int prisoner(int* in, /* FD pair for parent-to-child pipe */ int* out); /* and again for child-to-parent pipe */ int main(int argc, char** argv) { int i, child; /* loop indices */ int p_to_c[2][2], c_to_p[2][2]; /* File descriptors. p_to_c[0] = parent-to-child pipe for child 0 c_to_p[1] = child-to-parent pipe for child 1 etc. */ pid_t pids[2]; /* pids of children */ char responses[2]; /* temporary storage for responses from children */ double sentence[2] = {0.0, 0.0}; /* sentence[0] = length of child 0's sentence, etc. */ /* BEGIN by creating two pipes each for our two children... */ for( child = 0; child <= 1; child++ ) { if( pipe(p_to_c[child]) < 0 || pipe(c_to_p[child]) < 0 ) { perror("Pipe creation failed"); exit(1); } } /* Now create the children themselves */ for( child = 0; child <= 1; child++ ) { pids[child] = fork(); if( pids[child] == 0 ) { /* We're in the child; do child stuff */ exit(prisoner(p_to_c[child], c_to_p[child])); } else if( pids[child] < 0 ) { perror("Fork failed"); exit(1); } } /* We are in the parent now; time to close unneeded ends of pipes */ for( child = 0; child <= 1; child++ ) { if( close(p_to_c[child][READ_END]) < 0 || close(c_to_p[child][WRITE_END]) < 0 ) { perror("Close failed"); exit(1); } } /* It's time to play the game. The parent/child communication protocol is as follows: First, the parent writes a '?' to the child. Then the child responds by writing either a 't' (talk) or 's' (silent) back to the parent. The parent can command the child to exit by writing a 'q' (quit). */ for( i = 0; i < 10; i++ ) /* play 10 times */ { printf("Game %d:\n", i); /* Communicate with each child: */ for( child = 0; child <= 1; child ++ ) { /* Write the '?' */ if( write(p_to_c[child][WRITE_END], "?", 1) < 1 ) { perror("Write '?' to child failed"); exit(1); } /* Read the one-byte response */ if( read(c_to_p[child][READ_END], responses + child, 1) < 1 ) { perror("Read from child failed"); exit(1); } /* Print out the info */ printf("%d %s\n", pids[child], responses[child] == 't' ? "talked" : "remained silent"); } /* Figure out the results of the game: */ if( responses[0] == 't' ) { if( responses[1] == 't' ) { sentence[0] += 6.0; sentence[1] += 6.0; } else /* responses[1] == 's' */ { sentence[1] += 10.0; } } else /* responses[0] == 's' */ { if( responses[1] == 't' ) { sentence[0] += 10.0; } else /* responses[1] == 's' */ { sentence[0] += 0.5; sentence[1] += 0.5; } } } /* Done playing; ask the children to exit */ for( child = 0; child <= 1; child ++ ) { if( write(p_to_c[child][WRITE_END], "q", 1) < 1 ) { perror("Write 'q' to child failed"); exit(1); } } /* Summarize the results and exit */ printf("--------------------\nScore:\n%d: %.1f years\n%d: %.1f years\n", pids[0], sentence[0], pids[1], sentence[1]); return 0; } int prisoner(int* in, int* out) { char command; /* Close unneeded pipe ends */ if( close(in[WRITE_END]) < 0 || close(out[READ_END]) < 0 ) { perror("Close failed"); exit(1); } srand(time(NULL) * getpid()); /* Don't want children to have same seed */ /* Repeatedly read from parent and respond to the command. */ while(1) { if( read(in[READ_END], &command, 1) < 1 ) { perror("Read from parent failed"); exit(1); } if( command == '?' ) { if( write(out[WRITE_END], rand() > RAND_MAX/2 ? "s" : "t", 1) < 1 ) { perror("Write response to parent failed"); exit(1); } } if( command == 'q' ) { exit(0); } } return 0; }