This exercise is designed to cover the [kill](<https://man7.org/linux/man-pages/man2/kill.2.html>)
system call in C/C++, and to introduce some common errors and fixes that you may find useful in future projects. Please make sure that you do all your work in the Edlab environment, otherwise, there may be inconsistent results and you will not receive points. Please read through this exercise and follow the instructions. After you do that, visit Gradescope and complete the questions associated with this exercise by the assigned due date.
Once you have logged in to Edlab, you can clone this repo using
git clone <https://github.com/umass-cs-377/377-exercise-kill-errors.git>
Then you can use cd
to open the directory you just cloned:
cd 377-exercise-kill-errors
This repo includes a Makefile
that allows you to locally compile and run all the sample code listed in this tutorial. You can compile them by running make
. Feel free to modify the source files yourself, after making changes you can run make
again to build new binaries from your modified files. You can also use make clean
to remove all the built files, this command is usually used when
something went wrong during the compilation so that you can start fresh.
Last week, we learned about various commands to create and wait for new processes. Many of these tasks are accomplished through the user of a process ID (typically referred to as a "pid"). Another use of a process ID is for the invoking the kill
system call. As the name implies, this function sends a signal to a process, some signals like `SIGQUIT1 will terminate the process immediately in the operating system1. As an example, please look at the following code:
duality.cpp
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <thread>
#include <chrono>
int main() {
int pid = fork();
if (pid == 0){
int runs = 0;
while (runs < 10000){
runs += 1;
std::cout << "Run #" << runs << "\\n";
std::this_thread::sleep_for (std::chrono::milliseconds(1));
}
} else {
char test[3];
sprintf(test, "%d", pid);
char *arguments[4];
arguments[0] = (char*)"./kill";
arguments[1] = strdup(test);
arguments[2] = NULL;
arguments[3] = NULL;
//Question code goes here
std::cout << "finish them?\\n";
execvp(arguments[0], arguments);
}
}
kill.cpp
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
using namespace std;
int main(int argc, char *argv[]) {
cout << "finish them.\\n";
kill(atoi(argv[1]), SIGQUIT);
}
The code in duality.cpp
creates two processes. The child process loops infinitely, printing out how many times it has looped so far. The parent process invokes fork, using the child process’ pid as the parameter. Kill.cpp
simply invokes kill
giving it the first command line argument passed to main
and the [SIGQUIT
](https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#:~:text=The SIGQUIT signal is similar,“detected” by the user.) modifier which sends a quit signal to the process.
Note, we can use kill
on the currently running process from within itself. While this is very similar to the exit
function, it is not exactly the same, as the latter cleans up everything while closing and the former forcefully ends the task.
Errors are a common issue when coding in any language, but are especially hard to solve in languages such as C/C++. The segmentation fault is one of the most common and unspecific errors in all of coding. Generally, the error stems from memory corruption, such as attempting to access memory that is not available to the program (i.e. read-only or free). When modifying values in C/C++, it is vital to ensure that you are not attempting to overwrite read-only data/code, nor are you trying to access code/data that is not available to your process. As an example, please look at the following code:
word.cpp