0% found this document useful (0 votes)
1 views44 pages

ProcessAPI

서강대 운영체제및시스템프로그래밍 강의자료

Uploaded by

donggyuhun
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views44 pages

ProcessAPI

서강대 운영체제및시스템프로그래밍 강의자료

Uploaded by

donggyuhun
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

5.

Process API

1
Overview

 fork()

 exec()

 wait()

 Separation of fork() and exec()


 IO redirection

 pipe

Soon Hwang 2
Background: What is a Shell?

 Shell = the program that interprets your commands


 When you type 'ls -l' in terminal, the shell program does the work

 Shell reads your command, creates a new process, runs the program

 How shell executes a command:


 1. fork() - create a child process (copy of shell)

 2. exec() - replace the child with the new program (e.g., ls)

 3. wait() - shell waits for the child to finish

 Examples of shells: bash, zsh, sh

 This chapter: understanding fork/exec/wait that power the shell.

Soon Hwang 3
Creating a child process

fork()

 Create a child process


 child process is allocated separate memory space from the process. The child pro
cess has the same memory contents as the parents.

 The child process has its own registers, and program counter register(PC).

 The newly created process becomes independent after it is created.

 for parent, fork() returns PID of child process; for child process, fork() returns
0.

Soon Hwang 4
5
Soon Hwang
fork(): parent vs. child

6
Usage of fork()

p1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.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)
printf("hello, I am parent of %d (pid:%d)\n",
rc, (int) getpid());
}
return 0;
}

Soon Hwang 7
Let’s run it.

prompt> ./p1
hello world (pid:29146)
hello, I am parent of 29147 (pid:29146)
hello, I am child (pid:29147)
prompt>
or
prompt> ./p1
hello world (pid:29146)
hello, I am child (pid:29147)
hello, I am parent of 29147 (pid:29146)
prompt>

Soon Hwang 8
Create the dependency between bewteen the processes

wait()

 When the child process is created, wait() in the parent process


won’t return until the child has run and exited.

 The parent and the child does not have any dependency.

 In some cases, the application wants to enforce the order in which they
are executed, e.g. the parent exits only after the child finishes.

Soon Hwang 9
The usage of wait() System Call

p2.c

#include <stdio.h>
#include <stdlib.h>
#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;
}

Soon Hwang 10
1
Soon Hwang 1
The wait() System Call (Cont.)
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>

Soon Hwang 12
Does fork() immediately copy the entire process heap in Linux?

Does fork() immediately copy the entire process heap in Linux? - Unix & Linux Stack Exchange

Soon Hwang 13
Running a new program

exec()

 The caller wants to run a program that is different from the caller itself.
 Launch an editor

 % ls –l

 OS needs to load a new binary image, initialize a new stack, initialize a new heap
for the new program.

 two parameters
 The name of the binary file

 The array of arguemtns

Soon Hwang 14
char *argv[3];

argv[0] = “echo”;
argv[1] = “hello”;
argv[2] = 0;
exec(“/bin/echo”, argv);
printf(“exec error\n”);

1
Soon Hwang 5
Usage of exec()
p3.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.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());
char *myargs[3];
myargs[0] = strdup("wc"); // program: "wc" (word count)
myargs[1] = strdup("p3.c"); // argument: file to count
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
printf("this shouldn’t print out");
} 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;
}

Soon Hwang 16
When exec() is called,…

 Replace the existing contents of the memory with the new memory contents
from the new binary file.

 exec() does not return. It starts to execute the new program.

Soon Hwang 17
Usage of exec()

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>

Soon Hwang 18
Why separating fork() and exec()?

 Why don’t we just use something like “forkandexec(“ls”, “ls –l”)”?

 Via separating fork() and exec(), we can manipulate various settings just before
executing a new program and make the IO rediction and pipe possible.
 IO redirection

% cat w3.c > [Link]

 pipe

% echo hello world | wc

‘pipe’ is the heart of the shell programming.

Soon Hwang 19
IO redirection

% wc w3.c > [Link]

 Save the result of ’wc w3.c‘ to [Link].

 How?

 Shell is a program that fork() and exec() the command with argument.
 % ls –l  shell calls fork() and exec(“ls”, “ls—l”) ;

 Before calling exec(“wc”, “wc w3.c”), the shell closes STDOUT (close(1)) and opens
[Link] (open(“[Link])).

Soon Hwang 20
Details of IO 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("./[Link]", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
// now exec "wc"...
char *myargs[3];
myargs[0] = strdup("wc"); // program: "wc" (word count)
myargs[1] = strdup("p4.c"); // argument: file to count
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
} else { // parent goes down this path (main)
int wc = wait(NULL);
}
return 0;
}

Soon Hwang 21
IO redirection

Result
prompt> ./p4
prompt> cat [Link]
32 109 846 p4.c
prompt>

Soon Hwang 22
Background: File Descriptors

 Everything in UNIX is a file (or behaves like one)


 Regular files, directories, keyboards, screens, network sockets, pipes

 File Descriptor (fd): a small integer that identifies an open file


 Think of it as a 'ticket number' for accessing a file

 Every process starts with 3 file descriptors:


 fd 0 = STDIN: keyboard input (where scanf/read gets data)

 fd 1 = STDOUT: screen output (where printf/write sends data)

 fd 2 = STDERR: error output (also goes to screen by default)

 Key insight: I/O redirection works by swapping these fd entries.

Soon Hwang 23
File descriptor and file descriptor table
 File descriptor
 an integer that represents a file, a pipe, a directory and a device

 A process uses a file descriptor to open a file and directory.

 each process has its own file descriptor table.

 File descriptor 0 (Standard Input), 1 (Standard Output), 2 (Standard Error)

File Descriptor
Process A File Struct
offset STDIN
0 n=open(“file”);
1 read(n, buf, size);
offset STDOUT
2 write(n, buf, size);
3 close(n);
4 offset STDERR
5
Array of file descriptors offset

Buf

Soon Hwang 24
File offset

Soon Hwang 25
File structure (struct file in Linux)

26
file descriptor and system calls
 open()
 Allocate a new file object, allocate new file descriptor and set the newly allocated file descript
or to point to the new file object.

 When allocating the new file descriptor, it uses the smallest ‘free’ file descriptor from the file
descriptor table.

 close()
 deallocate the file descriptor ‘fd’.

 Deallocate the file object if there is no file descriptor associated with it.

 fork()
 copies the file descriptor table from the parent to child process.

 exec()
 retains the file descriptor table.

Soon Hwang 27
fork() and file descriptors

if(fork() == 0) {
write(1, “hello “, 6);
exit();
} else {
wait();
write(1, “world\n”, 6);
}

28
Soon Hwang 29
cat and IO redirection

% cat [Link]

char *argv[2];
char buf[512];
argv[0] = “cat”; int n;
argv[1] = 0;
if(fork() == 0) { for(;;) { Standard Input
close(0); n = read(0, buf, sizeof(buf));
open(“[Link]”, O_RDONLY); if(n == 0)
exec(“cat”, argv); break;
} if(n < 0) { Standard Error
fprintf(2, “read error\n”);
exit();
} Standard Output
if(write(1, buf, n) != n) {
fprintf(2, “write error\n”);
exit();
}
}

Soon Hwang 30
pipe: ‘|’

% echo hello world | wc

pipe

• Output to STDOUT of one process is fed to STDIN of another process.


• Implemented with dup() and pipe().
• Key innovation of UNIX shell.

Soon Hwang 31
dup(fd)

 duplicate file descriptor: dup() system call

fd = dup(1);
write(1, “hello “, 6);
write(fd, “world\n”, 6);

Soon Hwang 32
pipe()

 special type of file, a kernel buffer that is exposed to a process via a pair
of file descriptors: p[0] for read end and p[1] for write end.

 The reader blocks when there is no data to read.

Soon Hwang 33
Ordinary Pipe

 Unidirectional byte streams which connect one process into the other
process.
 The data written at one end of the channel is read at the other end.

 From a logical point of view, a pipe can be compared to a FIFO queue of


characters.
write read

Process A Process B

Communication Pipe

 No structured communication : it is not possible to know the size,


sender/receiver of data contained in the pipe.

 Access to pipes is achieved by reading/writing from/to file descriptors.

34
Pipe Used by Commands

 One current usage of the pipe mechanism is performed by means of the


command line interpreter when commands are linked: (e.g., > ps -aux |
grep root | tail)

 [ /home/parksy ] ps -aux | grep root | tail


root 9232 0.0 0.1 1392 664 ? S Aug26 0:00 [Link] -e –o
root 9233 0.0 0.1 1392 664 ? S Aug26 0:00 [Link] -e –o
…..
root 16763 0.2 0.1 1704 876 ? S 10:32 0:00 [Link]
root 16764 0.1 0.2 2320 1232 pts/0 S 10:32 0:00 login – parksy
parksy 16800 0.0 0.1 2236 528 pts/0 S 10:33 0:00 grep root

ps -aux grep root tail

out in ou in
t

35
Anonymous Pipe

 Created by a process and the transmission for associated descriptors is a


chieved only by inheritance by its descendants. (i.e., by creating a child p
rocess using fork() system call)

 Restrictive in that it only allows communication between processes with a


common ancestor which is a creator of a pipe.

 Creation of an anonymous pipe :


 int pipe(int filesdes[2]);

-> filesdes[0] : read descriptor, filesdes[1] : write descriptor.

write(filesdes[1]) read(filesdes[0])

Writing Readin
g

Anonymous Pipe

Soon Hwang 36
Use of Pipe - Example

 #include <stdio.h>
 #include <unistd.h>
 int main(void) {
 inr n, fd[2], pid; char line[100];
Parent Child
 if (pipe(fd) < 0) exit(-1);
fork
fd[0] fd[1] fd[0] fd[1]  if ((pid = fork()) < 0) exit(-1);
 else if (pid > 0) { /*parent */
 close(fd[0]);
 write(fd[1], “Hello World\n”, 12);
 wait(NULL);
PIPE  }
 else { /* child */
Kernel  close(fd[1]);
 n = read(fd[0], line, MAXLINE);
 write(STDOUT_FILENO, line, n);
 }
 }

37
Limitation of Ordinary Pipe

 Ordinary pipes only allow a pair of processes to communicate.

 Ordinary pipes exit only while the processes are communicating with one
another.
 Once the processes have finished communicating and have terminated, the
ordinary pipe ceases to exit.

 Named Pipe?
 Provide a much more powerful communication tool

38
Named Pipe (FIFO)

 Communication is bi-directional, and no parent-child relationship.

 Entries related pipes are managed in the file system.

 A named pipe can have several writers.

 Named pipes continue to exist after communicating processes have finished.

 Has a name and handled exactly like files with respect to file operations
(e.g., open, close, read, write).

 Created by mkfifo or mknod commands.

 Can be created by C functions : mkfifo().


 int mkfifo(const char *path, mode_t mode);

 Reading from / writing to a named pipe can be achieved by using standard


read() and write() system calls.

39
Named Pipe (Producer and Consumer)

writer.c reader.c

#include <fcntl.h> #include <fcntl.h>


#include <sys/stat.h> #include <stdio.h>
#include <sys/types.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
int main() #define MAX_BUF 1024
{ int main()
int fd; char * myfifo = "/tmp/myfifo"; {
int fd; char * myfifo = "/tmp/myfifo";
/* create the FIFO (named pipe) */ char buf[MAX_BUF];
mkfifo(myfifo, 0666);

/* write "Hi" to the FIFO */ /* open, read, and display the message
fd = open(myfifo, O_WRONLY); from the FIFO */
write(fd, "Hi", sizeof("Hi")); fd = open(myfifo, O_RDONLY);
close(fd); read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
/* remove the FIFO */ close(fd);
unlink(myfifo);
return 0; return 0;
}
}

40
Open Write-Only with and without O_NONBLOCK

 Write-Only without O_NONBLOCK


 open blocks and wait until another process opens the FIFO for reading.

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> Waiting for another process
int main() to open the FIFO
{ Output
int fd; char * myfifo = "/tmp/myfifo";

/* create the FIFO (named pipe) */


mkfifo(myfifo, 0666);

/* write "Hi" to the FIFO */


printf("open without O_NONBLOCK\n");
fd = open(myfifo, O_WRONLY);
write(fd, "Hi", sizeof("Hi"));
close(fd);

/* remove the FIFO */


unlink(myfifo);
return 0;
}

41
42
pipe vs. IO redirection

 advantages of pipes over using redirection with temporary files


echo hello world | wc

vs.

echo hello world > ttmp/xyz ; wc </tmp/xyz

 pipe automatically clean themselves up. When using temporary file, the user
has to explicitly delete it.

 pipe can pass arbitrarily long data while file redirection requires sufficient
available disk space.

 In pipe, reader and write can proceed in parallel while in redirection, the one
has to finish for the others to start.

Soon Hwang 43
Summary

 process
 Process API
 fork()
 exec()
 wait()
 separation of fork() and exec()
 IO redirection
 pipe

44

You might also like