Title: Tutorial: CSI 3310
1Tutorial CSI 3310
- Dewan Tanvir Ahmed
- SITE, UofO
2Todays Objective
- Go through the last lab
- Play with
- exec()
- fork()
- Dup2
- pipe
3Process
- A process in Unix terms is an instance of an
executing program. - Each process incorporates program code, the data
values within program variables, and values held
in hardware registers, program stack etc. - Associated with each process is a process control
block (PCB) which stores all the information
related to the process. - fork .... Creates a new process.
- exec .... Overlays the memory space of the
process with a new program. - wait .... synchronizes processes.
- exit .... Terminates a process
4fork()
- fork() creates a new child process
- Points to note
- the OS copies the current program into the new
process, - resets the program pointer to the start of the
new program (child fork location), and - both processes continue execution independently
as two separate processes - The child gets its own copy of the parents
- data segments
- heap segment
- stack segment
- file descriptors
5fork() Return Values
- fork() is the one Unix function that is called
once but returns twice!! - If fork() returns 0
- youre in the new child process
- If fork() returns gt 1 (i.e., the pid of the new
child process) - youre back in the parent process
6fork()
7Waiting on Our Children
- Unlike life, parents should always hang around
for their childrens lives (runtimes) to end,
that is to say - Parent processes should always wait for their
child processes to end - When a child process dies, a SIGCHLD signal is
sent to the parent as notification - The SIGCHLD signals default disposition is to
ignore the signal - A parent can find out the exit status of a child
process by calling one of the wait() functions
8Problem ChildrenOrphans and Zombies
- If a child process exits before its parent has
called wait(), it would be inefficient to keep
the entire child process around, since all the
parent is going to want to know about is the exit
status - A zombie is a child process that has exited
before its parents has called wait() for the
childs exit status - A zombie holds nothing but the childs exit
status (held in the program control block) - Modern Unix systems have init (pid 1) adopt
zombies after their parents die, so that zombies
do not hang around forever as they used to, in
case the parent never did get around to calling
wait
9Points to note
- include ltsys/types.hgt
- include ltunistd.hgt
- include ltstdio.hgt
- int main(void)
- pid_t fork_pid
- FILE my_file
- my_filefopen("MY_FORK_FILE.txt","w")
- fprintf(my_file," Hello from main \n")
- fork_pidfork()
- fprintf(my_file," After fork d\n",fork_pid)
- return 0
-
Hello from main After fork 0 Hello from main
After fork 14818
The first thing you should note is that the
output from the child process appears in the
same file as the parent process.
One characteristic of fork is that all file
descriptors that are open in the parent are
duplicated in the child.
10Exec
- The only way in which
- a program is executed in Unix is for an existing
program to issue an exec system call. - The exec calls overlays the memory space of the
calling process with a new program. - When used together, fork and exec provides the
means for the programmer to start another
program, yielding multitasking.
11Exec()..
12The exec() FunctionsOut with the old, in with
the new
- The exec() functions all replace the current
program running within the process with another
program - There are two families of exec() functions,
- the l family (list), and
- the v family (vector)
- What is the return value of an exec() call?
13The execl... functions
- int execl(const char path, const char arg0,
...) - executes the command at path,
- passing it the environment as a list arg0 ...
argn - thus, the execl family breaks down argv into its
individual constituents, and then passes them as
a list to the execl? - int execlp(const char path, const char arg0,
...) - same as execl, but
- uses PATH resolution for locating the program in
path, thus an absolute pathname is not necessary - int execle(const char path, const char arg0,
... char envp) - allows you to specifically set the new programs
environment, which replaces the default current
programs environment
14The execv... functions
- int execv(const char path, char const argv)
- executes the command at path,
- passing it the environment contained in a single
argv vector - int execvp(const char path, char const
argv) - same as execv,
- but uses PATH resolution for locating the
program in path - int execve(const char path, char const argv,
char const envp) - note that this is the only system call of the lot
15File Descriptor
- Contains
- reference to system file structure
- Denoted by small integer
- passed to system calls to specify which
process-to-file connection should be affected - Created by open( ), dup( ), dup2( ), pipe( ),
socket( ) - Removed by close( )
- Duplicated by fork()
- Retained across exec() (unless FD_CLOEXEC)
16Standard File Descriptors
- Each process normally has file descriptors for
standard input, standard output, standard error - Denoted by
- STDIN_FILENO
- STDOUT_FILENO
- STDERR_FILENO
- Older programs use 0, 1, 2
- Provide unbuffered access to data in files via
- read( ), write( ), lseek( )
- Buffered FILE structures stdin (scanf), stdout
(printf), stderr are layered on unbuffered files
17Inter Process Communication (IPC)
- For processes to cooperate in performing a task,
they need to share data. - The fundamentals of network programming lies in
processes' ability to share data among
themselves. - Unix allows concurrent processes to communicate
by using a variety of IPC methods - Signals
- message queues
- shared memory
- semaphores and
- sockets.
18Pipe
- Pipe is called with a two integer array
- hold the file descriptors associated with the
pipe - the first element in the array (p0) opens the
pipe for reading - while the other file descriptor (p1) opens the
pipe for writing. - Once created we can use pipes to communicate with
the process itself or with any child process.
19Concept
Stage 1 The original process A (the shell for
example) creates a pipe, receiving descriptors on
each end.
Stage 2 Process A forks twice, creating child
processes B and C. The children inherit the
parent's open descriptors, including those on the
two ends of the pipe, so at this stage, all three
processes have descriptors on both ends of the
pipe.
20Concept
Stage 3 Each process closes the descriptors it
doesn't need. B closes the downstream end, C
closes the upstream end, and A closes both. Note
that B and C inherit their own copies of A's
descriptors, so that closing a descriptor in the
parent doesn't affect the child's descriptors.
21Concept
Stage 4 Processes B and C exec() the programs
they need to run. Again, the descriptors remain
intact across the exec() call. B can then write
to the upstream end of the pipe, and C can read
from the downstream end. Inter Process
communication!!!
22Pipe
- Note A buffer is a system maintained data
structure accessible to both ends of the pipe. - The writer writes on to the buffer while the
reader reads from it. - How do we access the pipe?
- Obviously the array is not going to exist after
the exec(), so how do we access the pipe? - Before the exec(), we have to reassign the
standard output of the process to the pipe. - We can do this using a system call to duplicate
file descriptors called dup2()
23dup2()
- dup2(target, new)
- The file descriptor new will point to the same
file as target after the call. - If our target is the standard output stream of
the process, then we will redirect the standard
output to the pipe. - The standard output will survive the exec() call.
24close()
- The close() system call is used to close pipes
and files. - We need to close() the open pipes in the child
process before we exec() the new process. - If not, the open pipes may be destroyed by the
exec() call, also destroying our newly created
connection.
25Example ls gt temp
Create a subprocess from program ls redirect
standard output of ls into file named temp
Unix shell notation ls gt temp
int main(int argc, char argv)
pid fork() if (pid 0) fd
open("temp", O_WRONLYO_CREATO_TRUNC, S_IRWXU)
dup2(fd, STDOUT_FILENO) if
(execl(/bin/ls, ls, NULL) -1)
perror("execl") else close(fd)
wait(status)
26Example Execl/Execlp
- include ltunistd.hgt
- include ltstdio.hgt
- int main(void)
- int status
- if (fork())
- // Parent Do you know why?
- else
- // Child
- printf(" HELLO from Child \n")
- statusexecl("/bin/ls","ls","-l","-t",'\0')
- if (status ! 0)perror("execl error")
-
- return 0
27Output
- HELLO from Child
- ncitl0dahmed(61) total 664
- -rwx------ 1 dahmed grad 5082 May 15 1737
a.out - -rw-r--r-- 1 dahmed grad 352 May 15 1737
exels.c - -rw-r--r-- 1 dahmed grad 528 May 15 1706
pipe.c - -rwx------ 1 dahmed grad 6371 May 15 1701
mymon - -rw-r--r-- 1 dahmed grad 1938 May 15 1701
mymon.c - -rw------- 1 dahmed grad 289 May 15 1608
sat.c - -rw-r--r-- 1 dahmed grad 478 May 15 1607
redir.c - -rw------- 1 dahmed grad 75 May 15 1528
exeSleep.c - -rwx------ 1 dahmed grad 4831 May 15 1512 sat
- -rwx------ 1 dahmed grad 5779 May 15 1400 pt
- -rw-r--r-- 1 dahmed grad 561 May 15 1400
pt.c - -rwx------ 1 dahmed grad 6272 May 15 1227
procmon - -rw-r--r-- 1 dahmed grad 2379 May 15 0515
procmon.c - drwx------ 3 dahmed grad 512 May 15 0450
lab1 - -rw------- 1 dahmed grad 521096 May 14 1112
Trash - -rw-r--r-- 1 dahmed grad 61440 May 9 1417
lab1.tar - drwxr-xr-x 18 dahmed grad 1024 May 8 1643
public_html
28Question?
- Modify the above code so that it works when
"/bin/ls" is replaced with "ls", i.e. which
version of exec should you now be using?
statusexeclp("ls","ls","-l","-t",'\0')
29Simple pipe Example
- int main()
-
- int i,j,p2
- char s100
- char s2100
-
- ipipe(p)
- printf("pipe returned d d d\n",i,p0,p1)
- for (j0 jlt5 j)
- sprintf(s,"I am a string d\n",j)
- iwrite(p1,s,strlen(s))
- printf("Write completed id\n",i)
- iread(p0,s2,100)
- printf("Read from the pipe completed
id\n\ts\n",i,s2) -
30Sample output
- pipe returned 0 3 4
- Write completed i16
- Read from the pipe completed i16
- I am a string 0
- Write completed i16
- Read from the pipe completed i16
- I am a string 1
- Write completed i16
- Read from the pipe completed i16
- I am a string 2
- Write completed i16
- Read from the pipe completed i16
- I am a string 3
- Write completed i16
- Read from the pipe completed i16
31Example dup2 and pipe
- include ltstdio.hgt
- include ltunistd.hgt
- define MSGSIZE 4096
- main()
- char inbufMSGSIZE
- int p2, j
- pid_t pid
- if (pipe(p) -1)
- printf("Error opening pipe\n")
- exit(1)
-
- switch(pid fork())
- case -1
- perror("Error with the fork()\n")
- exit(2)
-
case 0 close(p0) dup2(p1,
1) close(p1) execlp("ls", "ls", (char
)0) break default
read(p0, inbuf, MSGSIZE) printf("s",
inbuf) close(p0) close(p1)
32Pipe drawbacks
- Pipes can only be used to connect processes that
have a common ancestry, eliminating the
possibility for a true client-server application
to exist. - Pipes cannot be permanent, as they have to be
created and destroyed with the process.
33Thank You!