Title: System Calls: pipes
1System Calls pipes
2Review fork()
- int K
- main()
- int i int j
- j 200
- K 300
- printf("Before forking j d, K d\n", j,
K) - i fork()
- if (i gt 0)
- sleep(10)
- printf("After forking, parent j d, K
d\n", j, K) - else
- j K
- printf("After forking, child j d, K
d\n", j, K) -
-
3-
- main()
- int i int seekp int fd
- char s1
- char s21000
- fd open("tmpfile", O_WRONLY O_TRUNC
O_CREAT, 0666) - s1 "Before forking\n"
- write(fd, s1, strlen(s1))
-
- i fork()
- if (i gt 0)
- sleep(10) / Delay the parent by ten seconds /
- s1 "Parent"
-
- else
- s1 "Child"
-
- seekp lseek(fd, 0, SEEK_CUR)
- sprintf(s2, "s After forking Seek pointer
d\n", s1, seekp)
zhang_at_storm Demo ./a.out zhang_at_storm Demo
more tmpfile Before forking Child After forking
Seek pointer 15 Parent After forking Seek
pointer 55
4Zombie/defunct Process
- When child process terminates, it remains in
system until parent terminates or parent call
wait() - A parent normally must wait() for child processes
to exit. This allows all remnants of the child to
vanish. - Shell fork a process to execute a command, wait
until it ends, and then continue execute next
command - For command ending with ?
5Pipe
- Allow parent-child processes to communicate with
each other - Make pipeline in shell command script possible
- int pipe(int fd2)
- you pass it an array of two integers. It fills in
that array with two file descriptors, fd0,
fd1 - Anything that is written on fd1 can be read
from fd0. - Pipes are treated as files
- You can call read(), write(), close() on pipes
- fd0 is for reading, fd1 is for writing
6Simple example
- include ltstdio.hgt
- main()
- int pipefd2
- int i
- char s1000
- char s2
- if (pipe(pipefd) lt 0)
- perror("pipe")
- exit(1)
-
- s2 Hello World!"
- write(pipefd1, s2, strlen(s2))
- i read(pipefd0, s, 1000)
- si '\0'
- printf("Read d bytes from the pipe 's'\n", i,
s) -
- write() to a reading end of a pipe asks
operating system to hold those bytes in a buffer
until some process requests for them by
performing a read() on the read end of the pipe.
7Visualize pipes
program
File descriptors
Code, Globals stacks
0 1 2 pipefd0 pipefd1
Operating system
buffer
Hello World!
heap
8Pipe as inter-process communication method
- In Unix, all inter-process communication must
take place with help of operating system - Process is considered as primary unit of
isolation one process cannot crash whole system,
instead you get segmentation fault - Well, not quite, the forkbomb we saw last class
could halt whole system ! Be extremely careful! - Pipes are a nice clean IPC method
- One process write to the pipe, one process read
from it
9Pipe inter-process communication
else //child process i 0 line 1
while(read(pipefd0, si, 1) 1)
if (si '\n') si '\0'
printf("6d s\n", line, s)
line i 0 else
i // end of while loop // end
of else //end of main()
- main()
- int pipefd2
- int pid, i, line
- char s1000
- if (pipe(pipefd) lt 0)
- perror("pipe")
- exit(1)
-
- pid fork()
- if (pid gt 0)
- // parent process
- while(fgets(s, 1000, stdin) ! NULL)
- write(pipefd1, s, strlen(s))
-
- close(pipefd1)
-
10Visualize pipes
child
Parent process
File descriptors
Code, Globals stacks
Code, Globals Stacks
File descriptors
0 ?-------- 1 --------? 2 -------? pipefd0? pipe
fd1?
------? 0 ? ------1 ? ------ 2 ?
pipefd0 ?pipefd1
Operating system
heap
heap
11Experiment with the program
- Lets try it out (testpipe)
- ctrl-d to finish standard input
- Why the child process lingers ?
- OS does not know no one is writing to pipe
child
Parent process
File descriptors
Code, Globals stacks
Code, Globals Stacks
File descriptors
0 ?-------- 1 --------? 2 -------? pipefd0? pipe
fd1?
------? 0 ? ------1 ? ------ 2 ?
pipefd0 ?pipefd1
Operating system
heap
heap
12- main()
- int pipefd2
- int pid int i, line
- char s1000
- if (pipe(pipefd) lt 0)
- perror("pipe")
- exit(1)
-
- pid fork()
- if (pid gt 0)
- close(1)
- close(pipefd0)
- while(fgets(s, 1000, stdin) ! NULL)
- write(pipefd1, s, strlen(s))
-
- close(pipefd1)
else close(0) close(pipefd1) i 0
line 1 while(read(pipefd0, si, 1) 1)
if (si '\n') si '\0'
printf("6d s\n", line, s) line i
0 else i
//end of while //end of else
//end of main
13Handling broken pipes
- When read from a pipe that has no write end,
read() returns 0. - When write to a pipe that has no read end, a
SIGPIPE signal is generated. - If the signal isn't handled, program exits
silently - Example If you execute
- UNIXgt cat exec1.c head -5 tail -1
- and you kill the middle process (the head one),
- the other two will exit automatically
14Signals
- A signal is an interruption of program
- when you hit CNTL-C, SIGINT signal is sent to
your program. - When you hit CNTL-\, SIGQUIT signal is sent to
your program. - When you generate a segmentation violation, that
sends the SIGSEGV signal to your program. - By default, there are certain actions that take
place. - When you hit CNTL-C, program usually exits.
- When you hit CNTL-\ or get a segmentation
violation, your program dumps core and then exits
(default action for SIGQUIT and SIGSEGV)
15Register signal handler
- include lt signal.h gt
- void cntl_c_handler(int dummy)
- printf("You just typed cntl-c\n")
- signal(SIGINT, cntl_c_handler)
-
- main()
- int i, j
- signal(SIGINT, cntl_c_handler)
- for (j 0 j lt 40 j)
- for (i 0 i lt 1000000 i)
-
-
16Signal as IPC
- void parentdone(int signum)
- int main()
- int pid
- if ((pid fork()) -1)
- perror("fork() failed")
- exit(1)
-
- if (pid 0)
- / child process /
- signal(SIGUSR1, parentdone)
- pause()
- / sleep until a signal is received /
- printf("World!\n")
- fflush(stdout)
else / parent process / printf("Hello,
") fflush(stdout) kill(pid, SIGUSR1) /
send a signal to the child / wait(NULL) /
wait the child exit / exit(0) // end
of main()
17dup, dup2
- int dup(int oldfd)
- int dup2(int oldfd, int newfd)
- dup and dup2 create a copy of file descriptor
oldfd. - dup uses lowest-numbered unused descriptor for
new descriptor - dup2 makes newfd be copy of oldfd, closing newfd
first if necessary. - Old and new descriptors may be used
interchangeably, and they share locks, file
position pointers and flags.
18Example implement pipeline
- if (pipe(pipefd) lt 0)
- perror("pipe")
- exit(1)
-
- pid fork()
- if (pid0)
- retdup2 (pipefd1,1)
- close (pipefd1)
- if (ret-1)
- fprintf (stderr,"first child
cannot dup\n") - exit(1)
-
- close(pipefd0)
- execlp("ls","ls",0)
- fprintf (stderr,failed to execue ls)
- //end of else
19Pipe vs named pipe
- For two processes to communicate through pipes,
they need access to same pipe - Only possible if the pipe is created by their
common ancestors - Named pipe make it possible for two unrelated
processes to communicate in a similar way - Named-pipe has a name (like other files), process
can open the pipe to read or write
20Using named pipe
- Create a named pipe
- mkfifo myPipe
- ls l will show myPipe as
- prw-r--r-- 1 zhang staff 0 2008-04-25
0930 myPipe - In one terminal, type
- ls -l gt myPipe
- in another type
- cat lt myPipe
- Difference with using file
- You can start cat command first
- ls process will wait until cat pick up the
output - Remember that ls and cat program are not
aware of the fact that input/output is from/to a
named pipe
21Named pipes server
- define HALF_DUPLEX "/tmp/halfduplex"
- define MAX_BUF_SIZEgt 255
- int main(int argc, char argv)
- int fd, ret_val, count, numread
- char bufMAX_BUF_SIZE
- ret_val mkfifo(HALF_DUPLEX, 0666)
- if ((ret_val -1) (errno ! EEXIST))
- perror("Error creating the named pipe")
- exit (1)
-
- fd open(HALF_DUPLEX, O_RDONLY)
- numread read(fd, buf, MAX_BUF_SIZE)
- bufnumread '0'
- printf("Half Duplex Server Read From the pipe
sn", buf) - .
- printf("Half Duplex Server Converted String
sn", buf) -
22Named pipe client
- define HALF_DUPLEX "/tmp/halfduplex"
- define MAX_BUF_SIZE 255
- int main(int argc, char argv)
- int fd
- if (argc ! 2)
- printf("Usage s ltstring to be sent to the
servergtn", argv0) - exit (1)
-
- fd open(HALF_DUPLEX, O_WRONLY)
- write(fd, argv1, strlen(argv1))
-
23Some other topics not covered
- Thread programming
- Processes do not share data or stack
- Threads within a process share data and code,
each have separate stack space (programs need to
ensure data integrity) - Thread is a lighter-weight way of achieving
parallism
Parent process
Code, Globals Stacks
pthread_creat()
New thread stack
heap
24Some quizzes
- How would implement the functions of for a
shell ? - i.e., run the command in background ?
25Next and Last Class
- A lab class where each of you are asked to show
me your project