Recitation: Signaling 15213-S04, Recitation, Section A Debug Multiple Processes using GDB Dup2 Signaling L5 Due: This Wednesday.

Download Report

Transcript Recitation: Signaling 15213-S04, Recitation, Section A Debug Multiple Processes using GDB Dup2 Signaling L5 Due: This Wednesday.

Recitation: Signaling
15213-S04, Recitation, Section A
Debug Multiple Processes using GDB
Dup2
Signaling
L5 Due: This Wednesday
Debug Multiple Proc’s Using GDB
 attach pid

pid: the process id of a running process
 set follow_fork_mode <parent | child>


–2–
only work in HP-UX and GNU/Linux (kernel >= 2.5.60)
Fish machines: Linux with kernel 2.2.20
15-213, S’04
Attach to a Running Process
1. Run the parent code and create the process tsh


Directly in the shell
In GDB
2. Get the pid

$ ps [-e | axu] | grep tsh
3. Run gdb

$ gdb tsh
$ gdb tsh <pid>
4. Attach to the process

–3–
(gdb) attach <pid>
15-213, S’04
Really that Easy?
 The process must be started outside GDB

If you want to debug both the parent process and the child
process, you need start another gdb (in another xterm)
 You have to type in the gdb & attach commands fast
enough --- before the process actually finishes


You have to modify the source code to let it wait
Two methods
 sleep(10);
 int gdbf = 0; while (!gdbf);
 For Lab 5, it is more troublesome

–4–
sdriver  runtrace  tsh/tshref  mycat
Demo!
15-213, S’04
Attach to a Running Process
1. Run runtrace and create the process tsh


Directly in the shell
In GDB
2. Get the pid

$ ps [-e | axu] | grep tsh
3. Run gdb

$ gdb tsh
$ gdb tsh <pid>
4. Attach to the process

–5–
(gdb) attach <pid>
15-213, S’04
Dup2()
 Basic concepts on file handler

File descriptor, file table, v-node table
 File sharing --- dup2()
 Practice problems
–6–
15-213, S’04
How the Unix Kernel Represents
Open Files
Two descriptors referencing two distinct open disk
files. Descriptor 1 (stdout) points to terminal, and
descriptor 4 points to open disk file.
Descriptor table
[one table per process]
Open file table
[shared by all processes]
v-node table
[shared by all processes]
File A (terminal)
File access
File pos
File size
refcnt=1
File type
File B (disk)
File pos
refcnt=1
File access
File size
File type
...
...
–7–
Info in
stat
struct
...
...
stdin fd 0
stdout fd 1
stderr fd 2
fd 3
fd 4
15-213, S’04
How Processes Share Files
A child process inherits its parent’s open files. Here is
the situation immediately after a fork
Descriptor
tables
Open file table
(shared by
all processes)
Parent's table
File A
refcnt=2
File type
File B
File pos
refcnt=2
File access
File size
File type
...
–8–
File size
...
fd 0
fd 1
fd 2
fd 3
fd 4
File pos
...
Child's table
File access
...
fd 0
fd 1
fd 2
fd 3
fd 4
v-node table
(shared by
all processes)
15-213, S’04
File Sharing
Two distinct descriptors sharing the same disk file
through two distinct open file table entries

E.g., Calling open twice with the same filename argument
Descriptor table
(one table
per process)
Open file table
(shared by
all processes)
v-node table
(shared by
all processes)
File A
File access
File pos
File size
refcnt=1
File type
...
...
fd 0
fd 1
fd 2
fd 3
fd 4
File B
File pos
refcnt=1
...
–9–
15-213, S’04
I/O Redirection
dup2(oldfd, newfd)

Copies (per-process) descriptor table entry oldfd to entry
newfd
Descriptor table
before dup2(4,1)
fd 0
fd 1
fd 0
a
fd 1
fd 2
fd 2
fd 3
fd 3
fd 4
– 10 –
Descriptor table
after dup2(4,1)
b
fd 4
b
b
15-213, S’04
I/O Redirection Example
Before calling dup2(4,1), stdout (descriptor 1) points
to a terminal and descriptor 4 points to an open disk
file.
Descriptor table
(one table
per process)
Open file table
(shared by
all processes)
v-node table
(shared by
all processes)
File A
File access
File pos
File size
refcnt=1
File type
File B
File pos
refcnt=1
File access
File size
File type
...
...
– 11 –
...
...
stdin fd 0
stdout fd 1
stderr fd 2
fd 3
fd 4
15-213, S’04
I/O Redirection Example (cont)
After calling dup2(4,1), stdout is now redirected to the
disk file pointed at by descriptor 4.
Descriptor table
(one table
per process)
Open file table
(shared by
all processes)
v-node table
(shared by
all processes)
File A
File access
File pos
File size
refcnt=0
File type
File B
File pos
refcnt=2
File access
File size
File type
...
...
– 12 –
...
...
fd 0
fd 1
fd 2
fd 3
fd 4
15-213, S’04
File Sharing
Descriptor table


Each process has its own
Child inherits from parents
File Table




set of all open files
Shared by all processes
Reference count of number of file descriptors pointing to
each entry
File position
V-node table


– 13 –
Contains information in the stat structure
Shared by all processes
15-213, S’04
Problem 11.2
Suppose that foobar.txt consists of the 6 ASCII
characters "foobar". Then what is the output of the
following program?
#include "csapp.h"
int main()
{
int fd1, fd2;
char c;
fd1 = Open("foobar.txt", O_RDONLY, 0);
fd2 = Open("foobar.txt", O_RDONLY, 0);
Read(fd1, &c, 1);
Read(fd2, &c, 1);
printf("c = %c\n", c);
exit(0);
}
– 14 –
15-213, S’04
Answer to 11.2
The descriptors fd1 and fd2 each have their own open
file table entry, so each descriptor has its own file
position for foobar.txt. Thus, the read from fd2
reads the first byte of foobar.txt, and the output is
c = f
and not
c = o
as you might have thought initially.
– 15 –
15-213, S’04
Problem 11.3
As before, suppose foobar.txt consists of 6 ASCII
characters "foobar". Then what is the output of the
following program?
#include "csapp.h"
int main()
{
int fd;
char c;
fd = Open("foobar.txt", O_RDONLY, 0);
if(Fork() == 0)
{Read(fd, &c, 1); exit(0);}
Wait(NULL);
Read(fd, &c, 1);
printf("c = %c\n", c);
exit(0);
}
– 16 –
15-213, S’04
Answer to 11.3
Child inherit’s the parent’s descriptor table. So child
and parent share an open file table entry (refcount = 2).
Hence they share a file position.
c = o
– 17 –
15-213, S’04
Problem 11.4
How would you use dup2 to redirect standard input to
descriptor 5?
int dup2(int oldfd, int newfd);

– 18 –
copies descriptor table entry oldfd to descriptor table entry
newfd
15-213, S’04
Answer to 11.4
dup2(5,0);
or
dup2(5,STDIN_FILENO);
– 19 –
15-213, S’04
Problem 11.5
Assuming that foobar.txt consists of 6 ASCII
characters “foobar”. Then what is the output of the
following program?
#include "csapp.h"
int main()
{
int fd1, fd2;
char c;
fd1 = Open("foobar.txt", O_RDONLY, 0);
fd2 = Open("foobar.txt", O_RDONLY, 0);
Read(fd2, &c, 1);
Dup2(fd2, fd1);
Read(fd1, &c, 1);
printf("c = %c\n", c);
exit(0);
}
– 20 –
15-213, S’04
Answer to 11.5
We are redirecting fd1 to fd2. (fd1 now points to the
same open file table entry as fd2). So the second Read
uses the file position offset of fd2.
c = o
– 21 –
15-213, S’04
Signaling
 Busy wait
 waitpid()
 Racing hazard
– 22 –
15-213, S’04
Busy Wait
if(fork() != 0) { /* parent */
addjob(…);
while(fg process still alive){
/* do nothing */
}
}
– 23 –
15-213, S’04
Pause
if(fork() != 0) { /* parent */
addjob(…);
while(fg process still alive){
pause();
}
}
If signal handled before call to pause,
then pause will not return when
foreground process sends SIGCHLD
– 24 –
15-213, S’04
Sleep
if(fork() != 0) { /* parent */
addjob(…);
while(fg process still alive){
sleep(1);
}
}
– 25 –
15-213, S’04
waitpid ()
pid_t waitpid(pid_t pid, int *status, int options)

pid: wait until child process with pid has terminated
 -1: wait for any child process


status: tells why child terminated
options:
 WNOHANG: return immediately if no children zombied
» returns -1
 WUNTRACED: report status of stopped children too
– 26 –
15-213, S’04
Status in Waitpid
int status;
waitpid(pid, &status, NULL);
Macros to evaluate status:






– 27 –
WIFEXITED(status): child exited normally
WEXITSTATUS(status): return code when child exits
WIFSIGNALED(status): child exited because of a signal
not caught
WTERMSIG(status): gives the terminating signal number
WIFSTOPPED(status): child is currently stopped
WSTOPSIG(status): gives the stop signal number
15-213, S’04
Race Hazard
 A data structure is shared by two pieces of code that
can run concurrently
 Different behaviors of program depending upon how
the schedule interleaves the execution of code.
– 28 –
15-213, S’04
eval & sigchld_handler Race Hazard
sigchld_handler() {
pid = waitpid(…);
deletejob(pid);
}
eval() {
pid = fork();
if(pid == 0)
{ /* child */
execve(…);
}
/* parent */
/* signal handler might run BEFORE addjob() */
addjob(…);
}
– 29 –
15-213, S’04
An OK Schedule
time
Shell
Signal Handler
Child
fork()
addjob()
execve()
exit()
sigchld_handler()
deletejobs()
– 30 –
15-213, S’04
A Problematic Schedule
time
Shell
Signal Handler
Child
fork()
execve()
exit()
sigchld_handler()
deletejobs()
addjob()
Job added to job list after the signal handler tried to delete it!
– 31 –
15-213, S’04
Blocking Signals
sigchld_handler() {
pid = waitpid(…);
deletejob(pid);
}
More details 8.5.6 (page 633)
eval() {
sigprocmask(SIG_BLOCK, …)
pid = fork();
if(pid == 0)
{ /* child */
sigprocmask(SIG_UNBLOCK, …)
execve(…);
}
/* parent */
/* signal handler might run BEFORE addjob() */
addjob(…);
sigprocmask(SIG_UNBLOCK, …)
}
– 32 –
15-213, S’04
Blocking Signals
x
sigprocmask(SIG_BLOCK, (sigset_t *)SIGCHLD, NULL);
sigprocmask(SIG_BLOCK, (sigset_t *)SIGINT, NULL);
sigprocmask(SIG_BLOCK, (sigset_t *)SIGTSTP, NULL);
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_BLOCK, &mask, NULL);
– 33 –
15-213, S’04
Blocking Signals
if (sigemptyset(&mask) < 0)
unix_error("sigemptyset error");
if (sigaddset(&mask, SIGCHLD))
unix_error("sigaddset error");
if (sigaddset(&mask, SIGINT))
unix_error("sigaddset error");
if (sigaddset(&mask, SIGTSTP))
unix_error("sigaddset error");
if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
unix_error("sigprocmask error");
– 34 –
15-213, S’04
Summary
 Debug Multiple Processes using GDB
 Dup2
 Signaling
– 35 –
15-213, S’04