syscalls

Work in Progress

Summary

POSIX syscalls for spawning processes

SyscallIncludeFunction
fork()<unistd.h>duplicates the current process
returns 0 in the child and child’s pid in the parent
execl(path, arg...)<unistd.h>replace the current process image with a new one
returns -1 only if error
exit(status)<unistd.h>terminate the current process
does not return, passes status to the parent process
wait(status)<unistd.h>wait for one child process to terminate and stores it’s status
returns the pid of the child process that terminates
getpid()<unistd.h>returns the pid of the current process

Concept

System calls

  • API to the OS
  • calling services in the kernel
  • change to kernel mode
  • UNIX:
    • POSIX standards
    • ~100 calls
  • Windows:
    • Win API
    • ~1000 calls

Invocation

  • function wraper
    • library provides a version with the same name and parameters
    • passes parameters 1-to-1 to the syscall
  • function adapter
    • library provides a more user friendly version
    • handles more complicated setup for the syscall
c
char msg[] = "Hello world!";
// wrapper
write(1, msg, 13); // 1 is the fd for stdout
// adapter
printf(msg); // other parameters are handled by the function

use strace on the binary to see the syscalls made by adapters

Mechanism

  • user mode: program sets syscall register
  • kernel mode: dispatcher checks the value and calls the corresponding handler
  • user mode: return to program

Process hierachy

Master process

  • init process
  • pid = 1
  • spawns all other processes via fork() + exec()

Zombie processes

  • process that has terminated
  • hold onto process data until wait() in the parent
  • parent terminates before child -> init becomes parent, init calls wait()
  • child terminates but parent doesn’t call wait() -> child remains a zombie
    zombie.png

Application

Forking

c
int result;
result = fork(); // A
if (result==0)
	fork(); // B
else {
	fork(); // C
	fork(); // D
}
printf("Hello\n"); //how many? 6
return 0;
p0p0fork=cpidp0p0p4p2p2p5p1fork=0p1p3ABCD

Waiting

  • assuming that wait doesn’t block when there are no child processes
c
int main() {
	// This is process P
	if (fork() == 0) {
		// This is process Q
		if (fork() == 0) {
			// This is process R
			......
			return 0;
		}
		<Point α>
	}
	<Point β>
	return 0;
}
// breaking down into processes
// process P
if (fork() == 0) // parent, so skip
<Point β>
// process Q
if (fork() == 0) { // child, so enter
	if (fork() == 0) // parent, so skip
	<Point α>
}
<Point β>
// process R
if (fork() == 0) { // child, so enter
	if (fork() == 0) { // child, so enter
		......
		return 0; // exit
Point αPoint βBehaviour
wait(NULL)P waits for Q
Q waits for R
wait(NULL)P doesn’t wait
Q waits for R
wait(NULL)wait(NULL)P waits for Q
Q waits for R
execl(...)wait(NULL)P waits for Q
Q may no longer wait
wait(NULL)execl(...)P may no longer wait
Q waits for R

execl() replaces the process image, so any original code after it is replaced

Forking factorial

  • scope is irrelevant, whole process is duplicated
c
int factorial(int n) {
	if (n == 0) {
		fork();       // forked up, only on the last iteration
		return 1;
	}
	return factorial(n‐1) * n;
}
int main() {
	printf("fac(2) = %d\n", factorial(2));
	return 0;
}
// output
// fac(2) = 2
// fac(2) = 2