Operating Systems Fundamentals and Processes, Lecture notes of Operating Systems

The fundamentals of operating systems, including the roles of an OS, address space, and process. It also covers the dual mode operation and system calls. likely to be useful as study notes or lecture notes for a course on operating systems.

Typology: Lecture notes

2021/2022

Uploaded on 05/11/2023

lalitlallit
lalitlallit 🇺🇸

4.1

(10)

226 documents

1 / 10

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Discussion 1: Operating Systems
January 27, 2023
Contents
1 Fundamentals of Operating Systems 2
1.1 ConceptCheck ............................................ 3
2 Processes 4
2.1 ForkandFriends ........................................... 5
2.2 SignalHandling............................................ 7
3 Pintos Lists 9
1
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Operating Systems Fundamentals and Processes and more Lecture notes Operating Systems in PDF only on Docsity!

Discussion 1: Operating Systems

 - January 27, 
  • 1 Fundamentals of Operating Systems Contents
    • 1.1 Concept Check
  • 2 Processes
    • 2.1 Fork and Friends
    • 2.2 Signal Handling
  • 3 Pintos Lists

1 Fundamentals of Operating Systems

While not a well-defined concept, operating systems (OS) provide hardware abstractions (e.g. file systems, processes) to software applications and manage hardware resources (e.g. memory, CPU). It can be seen as a special layer of software that provides application software access to hardware resources. An OS serves its purpose by taking on three roles.

Role Purpose Referee Manage protection, isolation, and sharing of resources Illusionist Provide clean, easy-to-use abstractions of physical resources Glue Provide common services

Address Space

An address space is the set of accessible addresses and the state associated with them. For a 32-bit processor, there are 2^32 ≈ 4 billion addresses.

The entire address space doesn’t necessarily represent real locations but rather potential spaces. A user program reading or writing to an address may result in a regular memory access, exception or fault if not allowed due to protection, I/O operation from a memory-mapped I/O device, or more. However, the kernel can access the entire address space without limitations.

In most modern operating systems, programs operate with virtual memory. Instead of accessing a physical memory directly, programs will request to access memory at a virtual memory address which is translated into a physical memory address.

Process

A process is an execution environment with restricted rights. Each process has its own address space and resources such as code, global data, and files.

Processes are protected from each other due to differing address spaces. If a bug were to corrupt a process, it would generally avoid compromising the entire system due to the protections from the address space.

Dual Mode Operation

The underlying hardware that the OS interfaces with provides at least two modes: kernel and user. Kernel mode, also known as supervisor or privileged mode, has the most privileges, meaning the kernel itself and other parts of the OS operate in this mode. On the other hand, user mode prohibits certain operations. This is where programs are normally executed. The restricted access is important in user mode to make sure processes running in user mode cannot maliciously corrupt another process.

There are three main ways the system switches from a user mode to kernel mode (mode transfer). When processes request a system service, this is known as a system call (syscall). While similar to a function call, syscalls occur ”outside” the process, meaning it is executed in the kernel mode. Therefore, syscalls encompass functionality that requires the privileges or abstractions of being in the kernel mode. Interrupts, sometimes referred to as hardware interrupts, are external asynchronous events (e.g. timer, I/O) that trigger a mode switch (from user mode to kernel mode). Traps, also known as exceptions or software interrupts, are internal synchronous events (e.g. segmentation fault, divide by zero) that trigger a mode switch.

All three types of mode transfers are unprogrammed control transfers. Instead of the process specifying the specific address like in a regular function call, the process specifies an index into the interrupt vector table (IVT), which is a table that contains the address and properties of each interrupt handler. The ”interrupt” in IVT is used as a general term that’s not just limited to the interrupts mentioned in the previous paragraph. The location of the IVT is stored in a designated processor register.

2 Processes

Processes are instances of a running program with their own protected address spaces.

Process Control Block

An OS needs to run many programs, meaning there will be many processes. As a result, basic mechanisms such as switching between user processes and the kernel, switching among user processes through the kernel, and protecting the OS from user processes and among themselves need to be present in an operating system. To accomplish this, the kernel represents each process with a process control block (PCB), a data structure that keeps track of the various properties of a process including (but not limited to) status, register state, process id (pid). The kernel scheduler allocates the CPU to different processes by maintaining a data structure containing the aforementioned PCBs. Other resources, such as memory and I/O, need to be managed and allocated as well, though not necessarily by the kernel scheduler.

Syscalls

Generally, an OS provides a library or API that implements process management syscalls. For Unix-based operating systems, this usually resides as part of the C standard library (libc). As a result, full documentation is available through the man pages. void exit(int status) terminates the calling process with the exit code specified by status. Generally speaking, exit code 0 means the code executed without any error, while non-zero exit codes indicate otherwise. Rarely will you see a C program where main directly calls exit since the OS library will call exit for you once main returns. pid t fork(void) creates a new process by copying the current process. Typically, the process created from fork is known as the child process, while the process calling fork is known as the parent process. The parent and child processes are identical in many ways (e.g. address space) except for the PID. More differences are listed on the man pages. The return type of fork is pid t, which is a signed integer. If the return value is greater than 0, this means the current process is the parent process. On the other hand, if the return value is 0, this means the current process is the child process. When the return value is -1, an error has occurred; the current process remains (i.e. no new child process has been created). A typical workflow you might see is 1 int main() { 2 pid_t fork_ret = fork(); 3 if (fork_ret > 0) { 4 /* parent process logic / 5 } else if (fork_ret == 0) { 6 / child process logic / 7 } else { 8 / error handling */ 9 } 10 }

fork simple.c

exec changes the program being run by the current process. A key distinction is that unlike fork, exec does not create a new process. In Unix-based operating systems, exec is a family of functions with different parameters, which is why a full method header is not given. For a full list, visit the man page. pid t wait(int *wstatus) waits for a child process to finish. On success, it returns the PID of the terminated child process, while returning -1 on an error. wstatus is used to store status information if not NULL. int kill(pid t pid, int sig) sends a signal, an interrupt-like notification, to another process. SIGINT (ctrl-C), SIGTERM (kill on command line), and SIGSTOP (ctrl-Z) are all types of signals you may be familiar

with. When a process receives a signal, it has a defined behavior known as the signal handler. A custom signal handler can be defined for most signals except for SIGKILL and SIGSTOP using sigaction.

2.1 Fork and Friends

  1. How many new processes (not including the original process) are created when the following program is run? Assume all fork calls succeed. 1 int main(void) { 2 for (int i = 0; i < 3; i++) 3 pid_t fork_ret = fork(); 4 return 0; 5 } fork loop.c
  2. What are the possible outputs when the following program is run? 1 int main(void) { 2 int stuff = 5; 3 pid_t fork_ret = fork(); 4 printf("The last digit of pi is %d\n", stuff); 5 if (fork_ret == 0) 6 stuff = 6; 7 return 0; 8 } fork stack.c
  3. What are the possible outputs when the following program is run? 1 int main(void) { 2 int* stuff = malloc(sizeof(int)); 3 *stuff = 5; 4 pid_t fork_ret = fork(); 5 printf("The last digit of pi is %d\n", *stuff); 6 if (fork_ret == 0) 7 *stuff = 6; 8 return 0; 9 } fork heap.c

2.2 Signal Handling

The following are a list of standard POSIX signals.

Signal Value Action Comment

SIGHUP 1 Terminate Hangup detected on controlling terminal or death of controlling process SIGINT 2 Terminate Interrupt from keyboard (Ctrl - c) SIGQUIT 3 Core Dump Quit from keyboard (Ctrl - ) SIGILL 4 Core Dump Illegal Instruction SIGABRT 6 Core Dump Abort signal from abort(3) SIGFPE 8 Core Dump Floating point exception SIGKILL 9 Terminate Kill signal SIGSEGV 11 Core Dump Invalid memory reference SIGPIPE 13 Terminate Broken pipe: write to pipe with no readers SIGALRM 14 Terminate Timer signal from alarm(2) SIGTERM 15 Terminate Termination signal SIGUSR1 30,10,16 Terminate User-defined signal 1 SIGUSR2 31,12,17 Terminate User-defined signal 2 SIGCHLD 20,17,18 Ignore Child stopped or terminated SIGCONT 19,18,25 Continue Continue if stopped SIGSTOP 17,19,23 Stop Stop process SIGTSTP 18,20,24 Stop Stop typed at tty SIGTTIN 21,21,26 Stop tty input for background process SIGTTOU 22,22,27 Stop tty output for background process

  1. Overriding SIGSTOP and SIGKILL is disabled. Why?
  1. What are the different ways you can use the keyboard to cause the program to exit? Assume the program is run in a bash shell. 1 void sigquit_handler(int sig) { 2 if (sig == SIGINT || sig == SIGQUIT) 3 exit(1); 4 } 5 void sigint_handler(int sig) { 6 if (sig == SIGINT) 7 signal(SIGINT, sigquit_handler); 8 } 9 int main() { 10 signal(SIGQUIT, sigquit_handler); 11 signal(SIGINT, sigint_handler); 12 while (1) { 13 printf("Sleeping for a second ...\n"); 14 sleep(1); 15 } 16 } exit signals.c

If you need more help with Pintos Lists abstraction, check out lib/kernel/list.h in your Pintos source code. For a deeper dive into the design, check out this article^1 on Linux’s doubly linked lists, which are what Pintos lists are based off of.

(^1) https://medium.com/@414apache/kernel-data-structures-linkedlist-b13e4f8de4bf