CSC 374: Computer Systems II: 2022 Fall, Assignment #2
Last Modified 2022 October 10
Purpose:
To practice creating processes and signal handling.
Computing
Please ssh into one of the following:
· cdmlsrvprd01.dpu.depaul.edu
or use your own Un*x machine (e.g. Linux or MacOS)
Overview:
We will write a program that "recursively" calls itself 2 times called selfCaller. Thus, there will be three processes running the same program. In one window I run the program:
$ ./selfCalle
In a second window I monitor the processes:
$ ps aux| grep selfCalle
ps aux |grep selfCalle
instruc XXXXXXXXXX XXXXXXXXXXpts/3 S+ 09:51 0:00 ./selfCalle
instruc XXXXXXXXXX XXXXXXXXXXpts/3 S+ 09:51 0:00 selfCaller 1
instruc XXXXXXXXXX XXXXXXXXXXpts/3 S+ 09:51 0:00 selfCaller 0
instruc XXXXXXXXXX XXXXXXXXXXpts/0 S+ 09:52 0:00 grep --color=auto selfCalle
· Process number 8009 is the one I directly created by running ./selfCaller.
· Processes 8010 was created by 8009.
· Process 8011 was created by 8010.
· Process 8069 is not running selfCaller. Instead, it is the grep selfCaller process that is looking for the selfCaller processes.
All selfCaller processes have a level value, which is an integer telling how many more "recursive" calls to do.
· For 8009 it is 2, the default value.
· For 8010 it is 1 (the value on the command line)
· For 8011 it is 0 (the value on the command line)
All processes receive signals from themselves and (if they have one) their child. Also, all process count the number of signals they receive.
Received signal:
Action:
SIGALRM
(Every process sends SIGALRM to itself.)
· Do printf("Process %d: called level 0\n",level);
· Tell the OS to send another SIGALRM to yourself rand() % 10 + 1 seconds in the future
· Increment numTimesCalled[0]
· If level is not 2 then send SIGUSR1 to its parent.
SIGUSR1
· Do printf("Process %d: called level 1\n",level);
· Increment numTimesCalled[1]
· If level is not 2 then send SIGUSR2 to its parent.
SIGUSR2
· Do printf("Process %d: called level 2\n",level);
· Increment numTimesCalled[2]
SIGINT
Have the program stop running by setting global var shouldRun to 0.
Assignment:
1. Copy and paste the following file:
2. /*-------------------------------------------------------------------------*
3. *--- ---*
4. * XXXXXXXXXXselfCaller.c ---*
5. *--- ---*
6. * XXXXXXXXXXThis program demonstrates process programming and ---*
7. *--- signalling by "recursively" calling itself a limited number of ---*
8. *--- and selectively signally its parent process. ---*
9. *--- ---*
10. *--- ---- ---- ---- ---- ---- ---- ---- ---- ---*
11. *--- ---*
12. *--- Version 1a XXXXXXXXXXJoseph Phillips ---*
13. *--- ---*
14. *-------------------------------------------------------------------------*
15.
16. #include
17. #include
18. #include
19. #include
20. #include
21.
22. const int TEXT_LEN = 16;
23.
24. const int NUM_SECS_TO_RUN = 30;
25.
26. #define PROGNAME "selfCaller"
27.
28. int numTimesCalled[3]
29. = {0,0,0};
30.
31. pid_t pidToSignal = -1;
32.
33. pid_t childPid = -1;
34.
35. int level = +2;
36.
37. int shouldRun = 1;
38.
39.
YOUR SIGNAL HANDLERS HERE
40.
41.
42. int main (int argc,
43. char* argv[]
44. )
45. {
46. srand(getpid());
47.
48.
YOUR CODE HERE
49.
50.
51.
52.
53.
54. printf("Level %d: %d %d %d\n",level,
55. numTimesCalled[0],numTimesCalled[1],numTimesCalled[2]
56. );
57.
58. return(EXIT_SUCCESS);
}
59. Write the signal handlers
A description of what they do is given in the table above the code.
60. Finish main()
a. It should check the command line arguments.
If there is a command line argument then it should set level to the integer value of that string.
If there is no command line argument, or the given command line argument is neither 0 nor 1, then set level to 2.
. If level is greater than 0 then it should create a new child to "recursively" call PROGNAME.
The child process should give itself the command line argument value of level-1 as a string. One way to do that is with:
c. char text[TEXT_LEN];
d.
snprintf(text,TEXT_LEN,"%d",level-1);
Now text contains the integer level-1 as a string.
If the program named PROGNAME cannot be run then the child process should do:
fprintf(stde
,"Cannot find %s\n",PROGNAME);
exit(EXIT_FAILURE);
e. Install your signal handlers for SIGALRM, SIGUSR1, SIGUSR2 and SIGINT.
f. Tell the OS to send SIGALRM to this process rand() % 10 + 1 seconds in the future.
g. Do this:
h. if (level == 2)
i. {
j. int i;
k.
l. for (i = 0; i < NUM_SECS_TO_RUN; i++)
m. {
n. sleep(1);
o. }
p. }
q. else
. {
s. pidToSignal = getppid();
t.
u. while (shouldRun)
v. {
w. sleep(1);
x. }
}
What that means is:
· If you are the original parent (level == 2) then hang out for 30 seconds.
· otherwise, note who your parent is, and keep running until told to quit.
y. Only if this process has a child process then send SIGINT to that process and wait() for it to finish.
z. Print the signal counts, and return EXIT_SUCCESS to the OS (already done).
How to make the program:
$ gcc selfCaller -o selfCalle
In one window call it:
$ ./selfCalle
In another window moniter it:
$ ps aux| grep selfCalle
Very important! During debugging, you may have rogue processes. You must kill them with
$ kill -9 processIdNumbe
ecause if you make too many the OS will not let you make any more, and not even let you login!
Sample output:
$ ./selfCaller
Process 2: called level 0
Process 2: called level 0
Process 1: called level 0
Process 2: called level 1
Process 0: called level 0
Process 1: called level 1
Process 2: called level 2
Process 1: called level 0
Process 2: called level 1
Process 0: called level 0
Process 1: called level 1
Process 2: called level 2
Process 1: called level 0
Process 2: called level 1
Process 2: called level 0
Process 2: called level 0
Process 0: called level 0
Process 1: called level 1
Process 2: called level 2
Process 1: called level 0
Process 2: called level 1
Process 2: called level 0
Level 0: 3 0 0
Level 1: 4 3 0
Level 2: 5 4 3
This means that:
· Level 0 sent SIGALRM to itself and SIGUSR1 to its parent 3 times.
· Level 1 received SIGUSR1 and sent SIGUSR2 to its parent 3 times.
· Level 2 received SIGUSR2 3 times.
· Level 1 sent SIGALRM to itself and SIGUSR1 to its parent 4 times.
· Level 2 received SIGUSR1 4 times.
· Level 2 sent SIGALRM to itself 5 times.