0% found this document useful (0 votes)
36 views

Systems Programming: P.K.Pattanayak

This document discusses systems programming concepts in Unix/Linux including system calls, processes, and inter-process communication (IPC). It describes system calls as the mechanism for programs to request services from the kernel, such as input/output. Common system calls for file I/O, process control, and IPC are provided as examples. Error handling for system calls using errno, perror, and strerror is also summarized. The concepts of processes, process IDs, and process creation using fork() are explained. Finally, it discusses process execution using one of the exec() system calls and waiting for a child process to finish using wait() or waitpid().

Uploaded by

ashish_mahana
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views

Systems Programming: P.K.Pattanayak

This document discusses systems programming concepts in Unix/Linux including system calls, processes, and inter-process communication (IPC). It describes system calls as the mechanism for programs to request services from the kernel, such as input/output. Common system calls for file I/O, process control, and IPC are provided as examples. Error handling for system calls using errno, perror, and strerror is also summarized. The concepts of processes, process IDs, and process creation using fork() are explained. Finally, it discusses process execution using one of the exec() system calls and waiting for a child process to finish using wait() or waitpid().

Uploaded by

ashish_mahana
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 43

Systems Programming

P.K.Pattanayak
An Introduction …
Unix Kernel: a large C program that
implements a general interface to a
computer to be used for writing programs
System Call
Well-defined entry point into kernel to request a
service

A system call is a request for service that a


program makes of the kernel

The service is generally something that only the


kernel has the privilege to do, such as doing I/O

System calls are sometimes called kernel calls.


System Call cont…
Unix Technique: For each system call,
have a function of same name such that:
– User process calls this function
– Function invokes appropriate kernel service
Example of system call
• System calls for low level file I/O
– creat(name, permissions)
– open(name, mode)
– close(fd)
– unlink(fd)
– read(fd, buffer, n_to_read)
– write(fd, buffer, n_to_write)
– lseek(fd, offest, whence)
Example of system call
• System Calls for process control
– fork()
– wait()
– execl(), execlp(), execv(), execvp()
– exit()
– signal(sig, handler)
– kill(sig, pid)
• System Calls for IPC
– pipe(fildes)
– dup(fd)
Error Handling in System Calls
All system calls return -1 if an error occurs
There are a number of helpful facilities to
diagnose the problem
– the errno global variable
– the perror library routine
– the strerror library routine
errno
• A global variable called errno in every process
• At process creation time, errno is initialized to 0
• When a system call error occurs, errno is set
• See /usr/include/sys/errno.h
• Remember:
– A successful system call never affects the current
value of errno
– A failed system call always overwrites the current
value of errno
perror()
Library routine (stdio.h)
– void perror (char* str)
perror displays str, then a colon(:), then an english
description of the last system call error, as
defined in the header file
/usr/include/sys/errno.h
Systems Programming Pattern:
– Check system calls for return values of -1
– Call perror() for an error description during
debugging
strerror()
• Library routine (string.h)
– char* strerror (int errcode)
• The error number that is stored in errno
can be passed to this function to retrieve a
string that specifies the error message
• Use strerror() instead of perror() when you
care about output formatting
What is a Process?

• Program: Executable file on disk

• Process: Executing instance of a program

• Process ID: Unique, non-negative integer


identifier; a handle by which to refer to a
process
Process IDs
• To obtain the process ID (PID) for the currently running
process, we use:
– int getpid()
• To obtain the PID of the parent, use:
– int getppid()
• What is the PPID of the init (PID 1) process? 1
• To be precise, PIDs can be int or long. We
typedef pid_t as the type of PIDS (thus, replace
int with pid_t like pid_t getpid() in the function definitions
above).
• Headers to include: sys/types.h and unistd.h
Example 1
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
pid_t mypid, myppid;
mypid = getpid();
myppid = getppid();
printf("PID: %d\n",mypid);
printf("PPID: %d\n",myppid);
return 0;
}
Process Creation

pid_t fork();

• Parent process executes fork


• It creates an (almost) identical copy of itself
• New (child) process inherits a new copy of the
parent’s whole state and context:
– Code, data, open files
– Program counter, stack
• Two clones exist immediately after fork
– Most systems employ “copy-on-write”
Fork
• The fork system call is used to create a duplicate
of the currently running program
• The duplicate (child process) and the original
(parent process) both proceed from the point of
the fork with exactly the same data
• The only difference between the two processes
is the fork return value
– Return value in parent is the PID of the
child process
– Return value in child is 0 if there was no
error
Process Creation: fork
Args, environment Args, environment
Stack parent Stack

fork
Heap Heap
Data Segment, bss Data Segment, bss
Program Text Program Text

Args, environment
Stack

child
Heap
Data Segment, bss
Program Text
Returning from fork
• fork() returns twice
– Once in parent and once in child
• Value returned by fork is different for each
process
– Returns 0 to child process
– Returns pid of child to parent
– Returns -1 to parent if error
• Both processes resume from same point after
fork(), but with different return values
Analogy: Fork ()
2

Under fork
Child has same age (progress) as parent!!!!

Folk

28 28

Tom Jack
Process Creation: fork()
pid_t child_pid;
int x=1;

child_pid=fork(); /* return twice */


if (child_pid==0)
/* This is child process */
printf (“I’m child process: x=%d\n”, x);
else if (child_pid>0)
/* This is parent process */
printf (“I’m parent process: x=%d\n”, x);
Process Creation Example 1
pid_t child_pid;
int i, n=3;

for (i=0; i<n; i++)


{
child_pid=fork();
if (child_pid == 0)
break;
}
Process Creation Example 2
pid_t child_pid;
int i, n=3;

for (i=0; i<n; i++)


{
child_pid=fork();
if (child_pid != 0)
break;
}
Process Creation Example 2
pid_t child_pid;
int i, n=3;

for (i=0; i<n; i++)


{
child_pid=fork();
if (child_pid != 0)
break;
}
Denial of service attack!
int main() { while(1) fork(); }

Fork bomb !!
Example 2
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int i, pid;
i = 5;
printf("%d (pid %d,ppid %d)\n",i,getpid(),getppid());
pid = fork();
if (pid != 0)
i = 6; /* only the parent gets here */
else
i = 4; /* only the child gets here */
printf("%d (pid %d,ppid %d)\n",i,getpid(),getppid());
}
Process Execution: exec
• fork creates identical clones
• But what if the child wants to execute some
other program?

int execv(char *path, char *argv[]);

• 6 variations of exec
– Use the same system call execve
– Differ in parameters

exec variations
There are several front-ends to execve:
– int execv(char *path, char *argv[]);
uses the environment vars of the current process
– int execl(char *path,
char *arg1, char *arg2, ... NULL);
takes arguments as separate parameters
– int execle(char *path,
char *arg1, ... NULL, char *envp[]);
like execl but with explicit environment
– int execvp(char *filename, char *argv[]);
like execv but searches PATH
– int execlp(char *filename,
char *arg1, char *arg2, ... NULL);
like execl but searches PATH

P for path; l for list and V for array e for environ


Process Execution: exec
• exec overwrites the memory image
inherited from the parent
• Process starts from scratch with a new
state:
– New code, program counter, data, stack
– New arguments, (sometimes) environment
• Retains some things from before exec:
– Open files, signals
Process Execution: exec
Args, env1
parent Stack 1

Heap 1

Data Segment 1, bss 1


Program Text 1

Args, env1 Args, env2


Stack 1 Stack 2
exec
Heap 2
child Heap 1
Data Segment 2, bss 2
Data Segment 1, bss 1
Program Text 2
Program Text 1
Analogy: Fork-exec
2

0
Folk
28 28
Process Execution: exec
pid_t child_pid;
int x=1;

child_pid=fork();
if (child_pid==0)
/* This is child process */
{
execv(“/bin/ls”, “ls –l”);
printf (“I’m child process: x=%d\n”, x);
}
else if (child_pid>0)
/* This is parent process */
printf (“I’m parent process: x=%d\n”, x);
How to collect information
from child process
Uses of wait
• Synchronization
– Allows parent to synchronize its execution
with the child/children
– Useful for interactive applications like the shell
• Reaping
– OS removes a process only when its parent
waits for it
– Need to notify the exit status of the process
Waiting for a Child: wait
• Sometime parent wants to wait for the child to
finish execution
• Example: “ls –l”
– Shell waits until command is executed
#include
#include <unistd.h>
<unistd.h>
pid_t
pid_t wait(int
wait(int *status);
*status);

• The parent suspends execution


• wait() returns when a child exits
– Returns pid of exited child
– status is pointer to child’s exit status
Waiting for a Child: wait

wait
parent

fork
exit
child
exec
Waiting for a Specific Child:
waitpid
• A process may have many children, but
may want to wait for a specific child
pid_t
pid_t waitpid(pid_t
waitpid(pid_t pid,
pid, int
int *status,
*status,
int
int opt);
opt);

– pid: process id of specific child


– status: exit status of child
– opt: WNOHANG means no waiting, return 0 if
child still running
Process Groups
• Process group: Multiple processes having
a single group leader
– By default, each process belongs to the
process group of its parent
• waitpid allows you to wait for any
process belonging to a process group:
– Negative pid indicates group_pid
waitpid(-group_pid,
waitpid(-group_pid, NULL,
NULL, 0);
0);
Dead Children become
Zombies

• When a process terminates but


its parent does not wait for it?

– Zombie (pid entry remains in


system process table)

– Zombies unlike
orphans do not
consume many
resources.
Zombie Removal

– Professional code installs signal handler for signal


SIGCHLD … which issues a wait() call
Process with Dead parents
becomes orphan
• When the parent process terminates first?
– “Child is orphaned”
– Child is “re-parented” to init process
– Child continues to consume resources
– init process (id=1) waits for children
Background Processes
• Shell spawns a process but does not wait for it
– E.g.: “mozilla &”
• Here, the parent does not wait for the child

parent

fork

child
exec
Daemons
• Forever running background processes
• Similar to shell
– Get some input
– Do something useful
– Print results, log errors if required
• Differences from shell:
– Each implements specific service
– May not be interactive
• Examples: Web server (httpd), print server
(lpd), ssh daemon (sshd)
How to kill a process using signal
• A signal is a notification of some
"'unexpected" occurrence.
• Synchronous signals arise from inside your
program: segmentation fault, divide by
zero, etc.
• Asynchronous signals arise outside your
program: user hits ^C, I/O completion, for
example.
• kill -s <signal> <pid> sends signal to
process pid. From a C program:
#include
#include <signal.h>
<signal.h>
int
int kill(pid_t
kill(pid_t pid,
pid, int
int signal);
signal);
What we learned
• Difference between program and process
• What are the resources related to
processes?
• How we can access them?
• How we can manipulate them?
• How to create processes?
• How to control the running states of
processes?

You might also like