2.1.process
2.1.process
Topic: Process
Endadul Hoque
Acknowledgement
Process P
CPU
# code
…
…
…
eax
esp registers
PC
How to virtualize CPUs? – The crux
Process P
CPU
# code
…
…
…
eax
esp
PC
How to virtualize CPUs? – The crux
Process P
CPU
# code
…
…
…
eax
esp
PC
How to virtualize CPUs? – The crux
Process P
CPU time
# code Process Q
…
# code
…
…
…
…
eax …
esp
PC
Q after P – sequential,
but not interesting.
Why not concurrent?
But how?
How to virtualize CPUs? – The crux
Process P
CPU time
# code
… Process Q
…
… # code
…
eax …
…
esp
PC
Time sharing
How to virtualize CPUs? – The crux
Process P
CPU time
# code
… Process Q
…
… # code
…
eax …
…
esp
PC
Time sharing
Process P
CPU time
# code Δ𝑡
… Process Q
add %eax, 10
mov (%esp), %eax Because
# code %eax has
mov %eax, 2
wrong data…
eax …
So
… what to do?
esp
PC
Executing the
Sol: Save all intermediate dataExecuting
add instruction before theswitching
Timeto Q
sharing
and restore it beforemov
moving to P
instruction
Executing the
mov instruction
How to virtualize CPUs? – The crux
• CPU virtualizing
– The OS can promote the illusion that many virtual
CPUs exist.
– Time sharing: Running one process, then stopping it
and running another
• The potential cost is performance.
Space sharing:
the counterpart
How to implement (e.g., disk space)
virtualization of the CPU?
OS needs
• Some low-level machinery (mechanisms)
• Some high-level intelligence (policies)
Policy vs. Mechanism
• In many OSes, a common design paradigm
– Separate high-level policies from low-level
mechanisms
• Policy: provides answer to which/what question
– E.g., which process should the OS run now?
– E.g., only Alice should read file f
• Mechanism: provides answer to how question
– E.g., how does OS perform a context switch?
– E.g., encrypt file f
• A general software design principle: modularity
A Process
A process is a running program
stack
Process
Loading:
code Takes on-disk program
static data and reads it into the
address space of process
Program
Disk
Process Creation
1. Load a program code into memory, into the
address space of the process.
– Programs initially reside on disk in executable format.
– OS perform the loading process lazily.
• Loading pieces of code or data only as they are needed
during program execution.
Descheduled
Running Ready
Scheduled
Blocked
Tracing Process State
Tracing Process State
Data Structures
• The OS has some key data structures that track
various relevant pieces of information.
– Process list
• Ready processes
• Blocked processes
• Current running process
– Register context
OR
prompt> ./p1
hello world (pid:29146)
hello, I am child (pid:29147)
hello, I am parent of 29147 (pid:29146)
prompt>
wait()
• This system call won’t return until the child has run and exited
#include <stdio.h>
#include <stdlib.h> p2.c
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // child (new process)
printf("hello, I am child (pid:%d)\n", (int) getpid());
} else { // parent goes down this path (main)
int wc = wait(NULL);
printf("hello, I am parent of %d (wc:%d) (pid:%d)\n",
rc, wc, (int) getpid());
}
return 0;
}
wait()
Result (Deterministic)
prompt> ./p2
hello world (pid:29266)
hello, I am child (pid:29267)
hello, I am parent of 29267 (wc:29267) (pid:29266)
prompt>
More on wait()
• wait() vs waitpid()
• When to use waitpid()?
• Some cases where wait() returns before the
child exits
– What is a process group? How is this related to
wait()?
• Relationship between wait() and child processes
running in background?
Result
prompt> ./p3
hello world (pid:29383)
hello, I am child (pid:29384)
29 107 1030 p3.c
hello, I am parent of 29384 (wc:29384) (pid:29383)
prompt>
exec() family
• On Linux, there are six variants of exec()
– execl(), execlp(), execle(),
execv(), execvp(), execvpe()
A pictorial presentation:
https://gist.github.com/fffaraz/8a250f896a2297db06c4
I/O Redirection
p4.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
int
main(int argc, char *argv[]){
int rc = fork();
if (rc < 0) { // fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) { // child: redirect standard output to
a file
close(STDOUT_FILENO);
open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
…
I/O Redirection
p4.c
#include <stdio.h>
…
#include <stdlib.h>
// now exec "wc"...
#include <unistd.h>
char *myargs[3];
#include <string.h>
myargs[0] = strdup("wc"); // program: "wc" (word count)
#include <fcntl.h>
myargs[1] = strdup("p4.c"); // argument: file to count
#include <sys/wait.h>
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
int
} else { // parent goes down this path (main)
main(int argc, char *argv[]){
int wc = wait(NULL);
int rc = fork();
}
if (rc < 0) { // fork failed; exit
return 0;
fprintf(stderr, "fork failed\n");
}
exit(1);
} else if (rc == 0) { // child: redirect standard output to
a file
close(STDOUT_FILENO);
open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
…
I/O Redirection
p4.c
#include <stdio.h>
…
#include <stdlib.h>
// now exec "wc"...
prompt>
#include ./p4
<unistd.h>
char *myargs[3];
#include <string.h>
prompt> cat
myargs[0] p4.output// program: "wc" (word count)
= strdup("wc");
#include <fcntl.h>
Result
myargs[1] = strdup("p4.c"); // argument: file to count
32 109
#include 846= p4.c
<sys/wait.h>
myargs[2] NULL; // marks end of array
int prompt>
execvp(myargs[0], myargs); // runs word count
} else { // parent goes down this path (main)
main(int argc, char *argv[]){
int wc = wait(NULL);
int rc = fork();
}
if (rc < 0) { // fork failed; exit
return 0;
fprintf(stderr, "fork failed\n");
}
exit(1);
} else if (rc == 0) { // child: redirect standard output to
a file
close(STDOUT_FILENO);
open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
…
Other Process API
• pipe()
– E.g., grep -o foo file | wc -l
– the output of one process (i.e., grep) is connected to an in-
kernel pipe (i.e., queue), and the input of another process (i.e.,
wc) is connected to that same pipe
• kill()
– send signals to a process (e.g., pause, die, terminate and so on)
– Control-c sends a SIGINT (interrupt) to the process to normally
terminate it
– Control-z sends a SIGTSTP (stop) to the process to pause it