Professional Documents
Culture Documents
11 UNIX Processes Including Select
11 UNIX Processes Including Select
1: Introduction
Overview
The UNIX Process Files in UNIX
What is a Process Directories and Paths
Representing a process
User vs. System Mode
States of a process
Creating and managing
UNIX I/O primitives
processes A simple example
fork()
The basic I/O system
wait()
calls
getpid()
Buffered vs. un-
exit()
etc.
buffered I/O
1: Introduction
UNIX Processes
A program that has started is manifested
in the context of a process.
A process in the system is represented:
Process Identification Elements
Process State Information
Process Control Information
User Stack
Private User Address Space, Programs and Data
Shared Address Space
1: Introduction
Process Control Block
Process Information, Process State Information,
and Process Control Information constitute the
PCB.
All Process State Information is stored in the
Process Status Word (PSW).
1: Introduction
States of a UNIX Process
• User running: Process executes in user mode
• Kernel running: Process executes in kernel mode
• Ready to run in memory: process is waiting to be scheduled
• Asleep in memory: waiting for an event
• Ready to run swapped: ready to run but requires swapping in
• Preempted: Process is returning from kernel to user-mode
but the system has scheduled another process instead
• Created: Process is newly created and not ready to run
• Zombie: Process no longer exists, but it leaves a record for
its parent process to collect.
1: Introduction
Process State Transitions
1 user running
sys-call return
interrupt/
kernel running interrupt return
2 sc
h
leep ed
u
s le
4 wakeup 3
asleep ready to run
1: Introduction
Creating a new process
In UNIX, a new process is created by means of the fork() -
system call. The OS performs the following functions:
• It allocates a slot in the process table for the new process
• It assigns a unique ID to the new process
• It makes a copy of process image of the parent (except
shared memory)
• It assigns the child process to the Ready to Run State
• It returns the ID of the child to the parent process, and 0
to the child.
Note, the fork() call actually is called once but returns twice -
namely in the parent and the child process.
1: Introduction
Fork()
Pid_t fork(void) is the prototype of the fork() call.
Remember that fork() returns twice
in the newly created (child) process with return value 0
in the calling process (parent) with return value = pid of
the new process.
A negative return value (-1) indicates that the call has
failed
1: Introduction
Basic Process Coordination
The exit() call is used to terminate a process.
Its prototype is: void exit(int status), where status is
used as the return value of the process.
exit(i) can be used to announce success and failure to the
calling process.
1: Introduction
more coordination
To wait for a particular child process to
terminate, we can use the waitpid() call.
Prototype: pid_t waitpid(pid_t pid, int *status, int opt)
1: Introduction
Orphans and Zombies or MIAs
A child process whose parent has terminated is
referred to as orphan.
1: Introduction
What is going on??
Who is getting to write to the standard output -
parent or child ??
Exercise: Go try it !!
1: Introduction
The exec() family
Why is the basic fork() facility not enough for a
serious system programmer?
1: Introduction
exec() example:
#include <unistd.h>
main()
{
printf(“executing ls\n”);
execl(“/bin/ls”, “ls”, “-l”, (char *)0);
1: Introduction
By Convention
Consider int execl ( const char *path, const char
*arg0 ... )
Example:
execl( “/bin/ls”, “ls”, “-l”, (char *)0 );
main()
{
char * const av[] = {“myecho”,”hello”,”world”, (char *)
0};
execvp(av[0], av);
1: Introduction
kill and killall
In order to communicate with an executing
process from the shell, you must send a signal to
that process.
The kill command sends a signal to the process.
You can direct the signal to a particular process
by using its pid
1: Introduction
more on kill
To terminate a process you can send the HUB
signal, which is signal number 9.
1: Introduction
Files
read()
Kernel Space kernel code
1: Introduction
Different types of files
UNIX deals with two different classes of files:
Special Files
Regular Files
1: Introduction
Access Primitives
UNIX provides access to files and devices
through a (very) small set of basic system
calls (primitives)
create()
open()
close()
read()
write()
ioctl()
1: Introduction
the open() call
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int flags, [mode_t mode]);
Please make it a habit to close all files that you program has
used as soon as you don’t need them anymore!
#include <unistd.h>
int close(int filedes);
Remember, closing resources timely can improve system
performance and prevent deadlocks from happening (more
later)
1: Introduction
A rudimentary example:
#include <fcntl.h> /* controls file attributes */
#include<unistd.h> /* defines symbolic constants */
main()
{
int fd; /* a file descriptor */
ssize_t nread; /* number of bytes read */
char buf[1024]; /* data buffer */
/* open the file “data” for reading */
fd = open(“data”, O_RDONLY);
/* read in the data */
nread = read(fd, buf, 1024);
/* close the file */
close(fd);
}
1: Introduction
Buffered vs unbuffered I/O
The system can execute in user mode or kernel mode!
Memory is divided into user space and kernel space!
What happens when we write to a file?
• the write call forces a context switch to the system.
What??
• the system copies the specified number of bytes from user
space into kernel space. (into mbufs)
• the system wakes up the device driver to write these mbufs
to the physical device (if the file-system is in synchronous
mode).
• the system selects a new process to run.
• finally, control is returned to the process that executed
the write call.
Discuss the effects on the performance of your program!
1: Introduction
Un-buffered I/O
Every read and write is executed by the kernel.
Hence, every read and write will cause a context
switch in order for the system routines to
execute.
Why do we suffer performance loss?
How can we reduce the loss of performance?
1: Introduction
Buffered I/O
explicit versus implicit buffering:
explicit - collect as many bytes as you can before writing
to file and read more than a single byte at a time.
However, use the basic UNIX I/O primitives
1: Introduction
The fcntl() system call
The fcntl() system call provides some
control over already open files. fcntl() can
be used to execute a function on a file
descriptor.
The prototype is: int fcntl(int fd, int
cmd, .......) where
fd is the corresponding file descriptor
cmd is a “pre-defined” command (integer const)
.... are additional parameters that depend on
what cmd is.
1: Introduction
The fcntl() system call
Two important commands are: F_GETFL and
F_SETFL
F_GETFL is used to instruct fcntl() to return
the current status flags
F_SETFL instructs fcntl() to reset the file
status flags
Example: int i = fcntl(fd, F_GETFL); or
int i = fcntl(fd, F_SETFL,
1: Introduction
Using fcntl() to change to
non-blocking I/O
We can use thefcntl() system call to
change the blocking behavior of the read()
and write():
Example:
#include <fcntl.h>
…..
if ( fcntl(filedes, F_SETFL, O_NONBLOCK) ==
-1)
perror(“fcntl”)
1: Introduction
The select() call
Suppose we are dealing with a server process that
is supporting multiple clients concurrently. Each of
the client processes communicates with the server
via a pipe.
1: Introduction
select() cont’d
What exactly is the problem?
If we are using the standard read() call, it will
block until data is available in the pipe.
if we start polling each of the pipes in
sequence, the server may get stuck on the first
pipe (first client), waiting for data.
other clients may, however, issued a request
that could be processed instead.
1: Introduction
fd_set and associated
functions
Dealing with bit masks in C, C++, and UNIX makes
programs less portable.
In addition, it is difficult to deal with individual bits.
Hence, the abstraction fd_set is available along with
macros (functions on bit masks).
Available macros are:
void FD_ZERO(fd_set *fdset) resets all the bits in fdset
to 0
void FD_SET(int fd, fd_set *fdset) set the bit
representing fd to 1
int FD_ISSET(int fd, fd_set *fdset) returns 1 if the fd bit
is set
void FD_CLR(int fd, fd_set *fdset) turn of the bit fd in
fdset
1: Introduction
a short example
#include .....
int fd1, fd2;
fd_set readset;
fd1 = open (“file1”, O_READONLY);
fd2 = open (“file2”, O_READONLY);
FD_ZERO(&readset);
FD_SET(fd1, &readset);
FD_SET(fd2, &readset);
select (5, &readset, NULL, NULL, NULL)
..........
1: Introduction
more select
1: Introduction