15-213 Recitation 11
Processes, Signals, IO
November 8, 2021 Your TAs
Copyright By PowCoder代写 加微信 powcoder
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 1
⬛ Logistics
⬛ Process Lifecycle
⬛ Signal Handling
⬛ IO and File Descriptors
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 2
Learning Objectives
⬛ Expectations:
▪ Basic understanding of signals & processes
▪ Better understanding of signals & processes
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 3
⬛ Shell Lab due Nov 16th
▪ Code Review Signup due Nov 18th
▪ Check Website for updated code review signups deadlines in the
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 4
⬛ Due date: Nov 16th
⬛ Simulate a Linux-like shell
⬛ Review the write-up carefully.
▪ Review once before starting, and again when halfway through ▪ This will save you a lot of style points and a lot of grief!
⬛ Read Chapter 8 in the textbook:
▪ Process lifecycle and signal handling
▪ How race conditions occur, and how to avoid them
▪ Be careful not to use code from the textbook without understanding it first.
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 5
Process Graphs
⬛ How many different lines are printed?
int main(void) {
char *tgt = “child”;
sigset_t mask, old_mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigprocmask(SIG_SETMASK, &mask, &old_mask); // Block pid_t pid = fork();
if (pid == 0) {
pid = getppid(); // Get parent pid
tgt = “parent”;
kill(pid, SIGINT);
sigprocmask(SIG_SETMASK, &old_mask, NULL); // Unblock
printf(“Sent SIGINT to %s:%d\n”, tgt, pid);
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 6
Process Graphs
⬛ How many different lines are printed?
int main(void) {
char *tgt = “child”;
sigset_t mask, old_mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigprocmask(SIG_SETMASK, &mask, &old_mask); // Block pid_t pid = fork();
if (pid == 0) {
pid = getppid(); // Get parent pid
tgt = “parent”;
kill(pid, SIGINT);
sigprocmask(SIG_SETMASK, &old_mask, NULL); // Unblock
printf(“Sent SIGINT to %s:%d\n”, tgt, pid);
0 or 1 line. The parent and child try to terminate each other.
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 7
Signals and Handling
⬛ Signals can happen at any time
▪ Control when through blocking signals
⬛ Signals also communicate that events have occurred ▪ What event(s) correspond to each signal?
⬛ Write separate routines for receiving (i.e., signals)
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 8
Counting with signals
⬛ Will this code terminate? volatile int counter = 0;
void handler(int sig) { counter++; }
int main(void) {
signal(SIGCHLD, handler);
for (int i = 0; i < 10; i++) {
if (fork() == 0) { exit(0); } }
while (counter < 10) { mine_bitcoin();
return 0; }
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 9
Counting with signals (you can’t)
⬛ Will this code terminate? volatile int counter = 0;
void handler(int sig) { counter++; }
int main(void) {
signal(SIGCHLD, handler);
for (int i = 0; i < 10; i++) {
if (fork() == 0) { exit(0); } }
while (counter < 10) { mine_bitcoin();
(Don't use signal, use Signal or sigaction instead!)
return 0; }
(Don't busy-wait, use
sigsuspend instead!) Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
It might not, since signals can coalesce.
sigsuspend
int sigsuspend(const sigset_t *mask);
- Suspend current process until a signal is received, you can specify which one using a mask
This is an atomic version of:
sigprocmask(SIG_SETMASK, &mask, &prev)
sigprocmask(SIG_SETMASK, &prev, NULL);
- This still doesn’t fix the issue of signals coalescing!
- Don’t use pause() in your own code
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 11
Proper signal handling
⬛ How can we fix the previous code?
▪ Remember that signals will be coalesced, so the number of times a signal handler has executed is not necessarily the same as number of times a signal was sent.
▪ We need some other way to count the number of children.
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 12
Proper signal handling
⬛ How can we fix the previous code?
▪ Remember that signals will be coalesced, so the number of times a signal handler has executed is not necessarily the same as number of times a signal was sent.
▪ We need some other way to count the number of children.
void handler(int sig) { pid_t pid;
while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { counter++;
(This instruction isn’t atomic. Why
won’t there be a race condition?)
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 13
Blocking signals
⬛ Surround blocks of code with calls to sigprocmask.
▪ Use SIG_BLOCK to block signals at the start.
▪ Use SIG_SETMASK to restore the previous signal mask at the end.
⬛ Don’t use SIG_UNBLOCK.
▪ We don’t want to unblock a signal if it was already blocked.
▪ This allows us to nest this procedure multiple times.
sigset_t mask, prev;
sigemptyset(&mask, SIGINT);
sigaddset(&mask, SIGINT);
sigprocmask(SIG_BLOCK, &mask, &prev);
sigprocmask(SIG_SETMASK, &prev, NULL);
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 14
Writing signal handlers
⬛ G1. Call only async-signal-safe functions in your handlers.
▪ Do not call printf, sprintf, malloc, exit! Doing so can cause deadlocks, since these
functions may require global locks.
▪ We’ve provided you with sio_printf which you can use instead.
⬛ G2. Save and restore errno on entry and exit.
▪ If not, the signal handler can corrupt code that tries to read errno.
▪ The driver will print a warning if errno is corrupted.
⬛ G3. Temporarily block signals to protect shared data.
▪ This will prevent race conditions when writing to shared data.
⬛ Avoid the use of global variables in tshlab.
▪ They are a source of pernicious race conditions!
▪ You do not need to declare any global variables to complete tshlab.
▪ Use the functions provided by tsh_helper.
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 15
Error and signals : Recap
⬛ You can’t expect people to block signals around all error handling logic
⬛ Hence, your signal handler shouldn’t interfere with them
⬛ Solution:
▪ Do not make any system call that could set errno
▪ Save and restore errno (store at beginning of handler and restore after)
▪ Think about what would work for the case you are using, not one rule
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 16
IO functions Needed for tshlab
⬛ int open(const char *pathname, int flags, mode_t mode); ▪ Can pass bitwise-or of flags:
▪ File Creation: O_CREAT, O_TRUNC, etc.
▪ Access Modes (must include one): O_RDONLY, O_WRONLY, O_RDWR
– O_RDONLY|O_WRONLY doesn’t work! Use O_RDWR
▪ Mode: specifies who else can read/write the new file
▪ Required argument when O_CREAT is used
▪ Use 0666 unless you have a specific reason to do something else
⬛ int close(int fd);
⬛ int dup2(int oldfd, int newfd);
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 17
Permissions for open()
Read (R) Write (W) Executable (X) All (RWX)
User (USR) S_IRUSR S_IWUSR S_IXUSR S_IRWXU
Group (GRP) S_IRGRP S_IWGRP S_IXGRP S_IRWXG
Other (OTH) S_IROTH S_IWOTH S_IXOTH S_IRWXO
⬛ These constants can be bitwise-OR’d and passed to the third argument of open()
⬛ What does S_IRWXG | S_IXUSR | S_IXOTH mean?
⬛ How to create a file which everyone can read from but
only the user can write to it or execute it?
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 18
STD File Descriptors
STDIN_FILENO STDOUT_FILENO STDERR_FILENO
stdin, stdout, stderr are opened automatically and closed by normal termination or exit()
open file table
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
File descriptors (File A != File B)
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 20
File descriptors after dup2(4,1); Closed
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 21
File Descriptors (File A == File B)
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 22
File Descriptors after a fork()
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 23
IO and Fork()
⬛ File descriptor management can be tricky.
⬛ How many file descriptors are open in the parent process at the indicated point?
⬛ How many does each child have open at the call to execve?
int main(int argc, char** argv)
for (i = 0; i < 4; i++)
int fd = open(“foo”, O_RDONLY);
pid_t pid = fork();
if (pid == 0)
int ofd = open(“bar”, O_RDONLY);
execve(...);
// How many file descriptors are open in the parent?
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 24
Redirecting IO
⬛ At the two points (A and B) in main, how many file descriptors are open?
int main(int argc, char** argv)
int i, fd;
fd = open(“foo”, O_WRONLY);
dup2(fd, STDOUT_FILENO);
// Point A
close(fd);
// Point B
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 25
Redirecting IO
⬛ File descriptors can be directed to identify different open files.
int main(int argc, char** argv) {
for (i = 0; i < 4; i++)
int fd = open(“foo”, O_RDONLY); pid_t pid = fork();
if (pid == 0)
int ofd = open(“bar”, O_WRONLY); dup2(fd, STDIN_FILENO); dup2(ofd, STDOUT_FILENO); execve(...);
// How many file descriptors are open in the parent?
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 26
File IO Activity
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 27
Activity Question
What is the possible output given contents of foo.txt are “ABCDEFG”?
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
read_and_print_one(fd1);
read_and_print_one(fd2);
if(!fork()) {
void read_and_print_one(int
read_and_print_one(fd2);
read_and_print_one(fd2);
close(fd2);
fd2 = dup(fd1);
read_and_print_one(fd2);
wait(NULL);
read_and_print_one(fd1);
read_and_print_one(fd2);
printf("\n");
close(fd1);
close(fd2);
read(fd, &c, 1);
printf("%c", c);
fflush(stdout);
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
File Descriptors after open() of fd2 Open File Table
refcnt = 1
Descriptor Tables
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
V Node Table
File access
refcnt = 1
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
Parent Table
File Descriptors after fork()
Descriptor Tables
Open File Table
refcnt = 2
V Node Table
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
read_and_print_one(fd1);
read_and_print_one(fd2);
if(!fork()) {
File access
refcnt = 2
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
What has been printed so far? ?
Child Table Parent Table
File Descriptors after fork()
Descriptor Tables
Open File Table
refcnt = 2
V Node Table
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
read_and_print_one(fd1);
read_and_print_one(fd2);
if(!fork()) {
File access
refcnt = 2
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
What has been printed so far? AA
Child Table Parent Table
Output after child prints
Descriptor Tables
Open File Table
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
read_and_print_one(fd1);
read_and_print_one(fd2);
if(!fork()) {
read_and_print_one(fd2);
read_and_print_one(fd2);
close(fd2);
fd2 = dup(fd1);
read_and_print_one(fd2);
refcnt = 3
V Node Table
File access
refcnt = 1
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
What has been printed so far? ?
Child Table Parent Table
Output after child prints
Descriptor Tables
Open File Table
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
read_and_print_one(fd1);
read_and_print_one(fd2);
if(!fork()) {
read_and_print_one(fd2);
read_and_print_one(fd2);
close(fd2);
fd2 = dup(fd1);
read_and_print_one(fd2);
refcnt = 3
V Node Table
File access
refcnt = 1
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
What has been printed so far? AABCB
Child Table Parent Table
Output after parent prints
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
read_and_print_one(fd1);
read_and_print_one(fd2);
if(!fork()) {
read_and_print_one(fd2);
read_and_print_one(fd2);
close(fd2);
fd2 = dup(fd1);
read_and_print_one(fd2);
wait(NULL);
Descriptor Tables
Open File Table
refcnt = 1
V Node Table
File access
read_and_print_one(fd1);
read_and_print_one(fd2);
printf("\n");
refcnt = 1
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
What has been printed so far?
Parent Table
Output after parent prints
int main(int argc, char *argv[]) {
int fd1 = open("foo.txt", O_RDONLY);
int fd2 = open("foo.txt", O_RDONLY);
read_and_print_one(fd1);
read_and_print_one(fd2);
if(!fork()) {
read_and_print_one(fd2);
read_and_print_one(fd2);
close(fd2);
fd2 = dup(fd1);
read_and_print_one(fd2);
wait(NULL);
Descriptor Tables
Open File Table
refcnt = 1
V Node Table
File access
read_and_print_one(fd1);
read_and_print_one(fd2);
printf("\n");
refcnt = 1
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
What has been printed so far?
Parent Table
If you get stuck on tshlab
⬛ Read the writeup!
⬛ Do manual unit testing before runtrace and sdriver!
⬛ Post private questions on piazza!
⬛ Read the man pages on the syscalls. ▪ Especially the error conditions
▪ What errors should terminate the shell? ▪ What errors should be reported?
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 36
man 2 wait
Taken from http://man7.org/linux/man-pages/man2/wait.2.html
WAIT(2) Linux Programmer's Manual
wait, waitpid, waitid - wait for process to change state
#include
#include
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); /* This is the glibc and POSIX interface; see
NOTES for information on the raw system call. */
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 37
man pages (probably) cover all you need
⬛ What arguments does the function take? ▪ read SYNOPSIS
⬛ What does the function do? ▪ read DESCRIPTION
⬛ What does the function return? ▪ read RETURN VALUE
⬛ What errors can the function fail with? ▪ read ERRORS
⬛ Is there anything I should watch out for? ▪ read NOTES
⬛ Different categories for man page entries with the same name
⬛ Looking up man pages online is not an academic integrity violation
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 38
Function arguments
⬛ Should I do dup2(old, new) or dup2(new, old)?
⬛ Read the man page:
$ man dup2
#include
int dup2(int oldfd, int newfd);
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 39
Function behavior
⬛ How should I write my format string when I need to print a long double in octals with precision 5 and zero-padded?
⬛ Read the man page $ man printf
DESCRIPTION
Flag characters
The character % is followed by zero or more of the following flags:
# 0 – ‘ ‘ +
The value should be converted…
The value should be zero padded…
The converted value is to be left adjusted…
(a space) A blank should be left before…
A sign (+ or -) should always …
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 40
Function return
⬛ What does waitpid() return with and without WNOHANG?
⬛ Read the man page:
$ man waitpid
RETURN VALUE
waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed state, then 0 is returned. On error, -1 is returned.
Each of these cal
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com