Signals

Due prior to midnight on Wednesday, February 4

Please create a directory in your repository named signals for your work.

This assignment will provide you experience using the following system function.

  • signal()
  • kill()
  • fork()
  • execl()
  • wait()

Program Description

Below are descriptions of two executables. The first, named player, is a program that will act as autonomous agent in a game environment. The second, named game_engine, will create child processes that each run the player program. Please write each program in c and include a make file named Makefile. All files should also include the following:

  • Your name and the date at the beginning of each source code file
  • Proper style, including proper variable names and indentation

player.c

The player program should have a global variable named health_level that holds an integral value between 0 and 5, initially 3. The program should have two signal handlers. One named decrease_health and one named increase_health.

The decrease_health method should decrease the value of health_level by 1. After decrementing the value, the program should print to the screen “HEALTH: XX”, where XX is the value of health_level. If the value of health_level reaches 0, the current process should print to standard out “Player killed: PID” where PID is the pid of the current process. The process should then terminate.

The increase_health method should increase the value of health_level by 1 if the current value of health_level is less than 5. After incrementing the value, the program should print to the screen “HEALTH: XX”, where XX is the value of health_level.

The program should register decrease_health as a signal handler for SIGUSR1 and register increase_health as a signal handler for SIGUSR2.

The program should run in a loop until terminated. While in the loop, the program should pause until a signal is received. After processing the signal, the program should continue in the loop.

Testing the Player

On the AWS Linux instance, the numeric values for each signals can be found in /usr/include/asm/signal.h (verify this).  There SIGUSR1 has a value of 10 and SIGUSR2 has a value of 12. You can test your player executable independently of the game engine by starting an instance of the player on the command line and then, using a different terminal window, finding the pid of the player process and issuing a kill signal to it.

Terminal Window 1

$ ./player                     // start up a player

Terminal Window 2

$ ps ax | grep your_user_name  // find the pid of your player process

$ kill -10 player_pid          // send your player process SIGUSR1
$ kill -12 player_pid          // send your player process SIGUSR2

game_engine.c

This program should run a loop and at the top of the loop display the following menu to the user:

  1. Spawn player
  2. Injure player
  3. Heal player
  4. List players
  5. Quit

When the user presses 1, the program should create a child process and run the player executable within it using an exec function.

When the user presses 2, the program should display a list of the engine’s child pids and prompt the user to enter a pid. The program should then send a SIGUSR1 signal to the child with the entered pid.

When the user presses 3, the program should display a list of the engine’s child pids and prompt the user to enter a pid. The program should then send a SIGUSR2 signal to the child with the entered pid.

When the user presses 4, the program should print out a list of the engine’s child pids.

When the user presses 5, the program kills all child processes, prints to the screen “GAME OVER”, and then terminates.

Updating the List of Players When a Player Terminates

When the process’ state has changed (e.g. a player process has terminated) a SIGCHLD signal is sent to the parent process.  In order for the game engine to recognize when a player has terminated the game engine should register a signal handler for the SIGCHLD signal.  In that handler call the wait() function to get the pid of the terminated child process.

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);

Note that you can pass 0 (NULL) to wait() if you don’t care about the status, which is probably the case in your program.

With the pid of the terminated player process known, you can update your list of active players.

© 2019, Eric. All rights reserved.