Chap 2
Chap 2
Operating systems provide essential services that enable the execution of programs and facilitate interaction
between users and the system. Here’s an overview of key operating system services:
User-Oriented Services
User Interface (UI)
Manages input/output operations required by programs, interacting with files and devices.
File-System Manipulation
Enables processes to exchange information, either on the same machine or across networks.
Supports mechanisms like:Shared Memory: Processes share a memory space.
Message Passing: Data is transferred through messages.
Error Detection
Manages the allocation of resources (CPU cycles, memory, storage, I/O devices) among multiple users or
processes running concurrently.
Logging
Tracks resource usage by users and processes to facilitate management and accountability.
Protection and Security
Controls access to resources to protect user data and ensure system integrity.
Implements user authentication and defends against unauthorized access attempts.
Command Line Interpreter (CLI)
A component that allows users to enter commands directly.
Can be implemented in the kernel or as a separate system program, sometimes with multiple variations (shells).
Fetches and executes commands, which may be built-in or refer to external programs, allowing for flexibility in
adding new features without modifying the shell.
The Bourne Shell provides a text-based interface where users can type commands directly to interact with the
operating system.
Basic Functions:
Executing Commands: Users can enter commands to run programs, manage files, or perform other tasks.
Scripting: Users can write scripts (a series of commands in a file) to automate tasks. This is useful for repetitive
jobs, like backups or system monitoring.
User Interaction:
When you open a terminal window, you're usually greeted with a prompt (like $ or #). This is where you type
your commands.
The shell interprets your input, executing commands and providing feedback (like error messages or the output
of a command).
Features:
Variables: You can create variables to store information (like paths to files).
Control Structures: Supports loops and conditionals (if statements), which allow for more complex scripts.
Job Control: You can run processes in the background or foreground, allowing for multitasking.
Legacy and Usage:
The Bourne Shell is one of the original Unix shells, created by Stephen Bourne in the 1970s. While newer shells
like Bash (Bourne Again Shell) have become popular, many systems still use the Bourne Shell for compatibility.
User Operating System Interface - GUI
Graphical User Interface (GUI):
GUIs are designed to be user-friendly, allowing interaction with the computer through visual elements like
icons, buttons, and windows instead of text commands.
Commonly used devices include a mouse, keyboard, and monitor.
Desktop Metaphor:
The interface mimics a physical desktop, where files are represented as icons. Users can click on these icons to
open files or applications.
Interactivity:
Actions can be performed using mouse clicks, like double-clicking to open a program or right-clicking to see
more options.
Integration:
Many operating systems (like Windows and macOS) offer both GUI and CLI, allowing users to choose their
preferred method of interaction.
Touchscreen Interfaces
Adaptation for Touch:
Touchscreen devices require interfaces that respond to finger gestures rather than a mouse.
Users can tap, swipe, or pinch to interact with the system.
Virtual Keyboard:
Text entry is done using an on-screen keyboard that appears when needed.
Voice Commands:
Many devices also support voice commands for hands-free operation.
System Calls
Programming Interface:
System calls are how programs request services from the operating system. They provide a way for applications
to interact with hardware and system resources.
Access via APIs:
Most programs access system calls through higher-level Application Programming Interfaces (APIs), making it
easier to write software without dealing with complex low-level calls directly.
Common APIs:
A system call is made to create or open the destination file where the content will be copied.
Read from the Source File:
The program uses a system call to read a chunk of data from the source file into memory.
Write to the Destination File:
Another system call writes the read data into the destination file.
Close Both Files:
System calls are made to close both the source and destination files to free up resources.
Example of Standard API
An API (Application Programming Interface) acts as a bridge between the program and the OS, allowing
developers to use predefined functions without needing to understand the intricate details of the system calls.
c
Copy code
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *source, *destination;
char buffer[1024];
fclose(source);
fclose(destination);
return 0;
}
In this code:
fopen, fgets, fputs, and fclose are API functions that internally use system calls to perform their tasks.
System Call Implementation
System Call Numbers:
Each system call is assigned a unique number. The operating system maintains a table of these numbers for
reference.
Invoking System Calls:
When a program makes a system call, it uses this number to index into the system call table. The OS then
performs the requested operation and returns the result.
Hiding Complexity:
Programmers only need to understand the API; they don’t need to know how the OS implements each system
call.
System Call Parameter Passing
When a system call requires additional information (like file names, buffer sizes, etc.), parameters must be
passed from the program to the OS. There are several methods for this:
Registers:
The simplest method involves passing parameters directly through CPU registers. However, there may be more
parameters than available registers.
Memory Block:
Parameters can be stored in a block of memory, and the address of this block is passed to the OS. This method is
common in systems like Linux and Solaris.
Stack:
Parameters can be pushed onto the stack by the program and popped off by the OS when needed. This method
allows for a flexible number of parameters.
1. Process Control
Create Process: Initiate a new process.
Terminate Process: End a running process.
Load/Execute: Load a program into memory and run it.
Get/Set Attributes: Retrieve or modify process characteristics.
Wait Events: Wait for specific conditions or events to occur.
Memory Management: Allocate and free memory for processes.
Debugging: Tools for diagnosing errors and single-stepping through code.
Locks: Manage access to shared resources among processes.
2. File Management
Create/Delete Files: Handle file creation and deletion.
Open/Close Files: Access and release file resources.
Read/Write: Perform input/output operations on files.
Reposition: Change the current position in a file.
Get/Set Attributes: Manage file properties (e.g., size, permissions).
3. Device Management
Request/Release Devices: Access and free up devices.
Read/Write Devices: Perform operations on devices.
Get/Set Attributes: Manage device properties.
4. Information Maintenance
Get/Set Time/Date: Retrieve or modify the system clock.
Get/Set System Data: Manage system-level information.
5. Communications
Create/Delete Connections: Set up and tear down communication links.
Send/Receive Messages: Transfer information between processes or systems.
Shared Memory: Manage access to shared memory areas for communication.
6. Protection
Control Access: Ensure that users and processes have the correct permissions to resources.
Get/Set Permissions: Manage user access rights.
Examples of System Calls in Windows and Unix
In Windows, system calls can involve functions like CreateProcess, ReadFile, and WriteFile.
In Unix-like systems, similar calls might include fork, open, read, and write.
Standard C Library Example
When a C program uses a function like printf(), it eventually calls a system call like write() to perform the actual
output operation. This interaction demonstrates how high-level library functions serve as an interface to the
more complex system calls that directly communicate with the OS.
Summary
Understanding these system calls and their types is crucial for grasping how operating systems manage
processes, files, devices, and security. The use of structured parameter passing via tables helps streamline these
interactions, making system programming more efficient and manageable.
Example: Arduino
Single-Tasking: Arduino operates on a single-tasking model, meaning it can only run one program at a time.
No Operating System: Instead of a full operating system, Arduino uses a simple bootloader to load programs
directly.
Program Loading: Programs, known as sketches, are uploaded via USB into flash memory.
Single Memory Space: There’s no separation between user space and kernel space; everything runs in a single
memory area.
Bootloader: At startup, the bootloader initializes and loads the user program.
Program Exit: Once the program completes or if it’s reset, the bootloader is reloaded, waiting for the next
sketch.
Example: FreeBSD
Unix Variant: FreeBSD is a Unix-based operating system known for its multitasking capabilities.
User Login: Users log in and can choose their preferred shell, which serves as the command interface.
Process Creation: The shell uses the fork() system call to create new processes.
Program Execution: After forking, it uses exec() to load a new program into the created process.
Waiting for Termination: The shell can either wait for the process to finish or continue accepting user
commands while the process runs.
Exit Codes: When a process exits, it returns a code. A return code of 0 indicates success, while any positive
number signifies an error.
System Services
System programs provide essential functionalities for program development and execution. They can be
categorized into several areas:
1. File Manipulation
Tools for creating, deleting, copying, renaming, and listing files and directories.
2. Status Information
Programs that retrieve information from the system, such as current time, available memory, and system
performance metrics.
3. Programming Language Support
Includes compilers, assemblers, debuggers, and interpreters to aid in software development.
4. Program Loading and Execution
Utilities like loaders and linkers manage the loading of programs into memory and prepare them for execution.
5. Communications
Mechanisms that facilitate virtual connections among processes, allowing for messaging, file transfers, remote
logins, and other network activities.
Summary
Understanding the differences between systems like Arduino and FreeBSD highlights the range of operating
system architectures—from simple, single-tasking systems to complex, multitasking environments. System
services play a critical role in user interactions with the OS, providing a user-friendly interface for managing
files, executing programs, and facilitating communication.
The linker combines multiple object files into a single binary executable file.
It also includes any necessary libraries that the program needs to run.
Executable Files:
The loader assigns final memory addresses to various parts of the program and adjusts the code and data to
match these addresses.
Dynamic Linking:
Modern systems often use dynamically linked libraries (like DLLs in Windows), which means libraries are loaded
into memory only when needed and shared across multiple applications using the same version.
Standard Formats: Object and executable files follow standard formats so the operating system knows how to
load and execute them correctly.
Some applications can be written in interpreted languages (like Python or Ruby), which have interpreters
available on multiple systems.
Others may use a virtual machine (like Java) that allows the same code to run on different platforms.
Applications written in standard languages (like C) may need to be compiled separately for each OS to work
correctly.
Application Binary Interface (ABI):
The ABI is the equivalent of an API for binary code, defining how different components of compiled code can
interface within a specific operating system and hardware architecture. This ensures compatibility and proper
function across different system components.
The choice of hardware and the type of system (e.g., desktop, server, embedded) significantly influence design
decisions.
User Goals vs. System Goals
User Goals:
The OS should be:Convenient to Use: Intuitive interfaces and easy access to functions.
Easy to Learn: Simple for new users to pick up.
Reliable: Consistent performance without crashes.
Safe: Protecting user data and privacy.
Fast: Efficient performance and responsiveness.
System Goals:
The OS should be:Easy to Design, Implement, and Maintain: Streamlined processes for developers.
Flexible: Capable of adapting to various tasks and environments.
Reliable: Minimizing errors and downtime.
Error-Free: Robust against bugs.
Efficient: Optimal use of system resources.
Creative Process
Specifying and designing an OS involves significant creativity and innovation in software engineering, requiring
a balance between user needs and system capabilities.
It's essential to separate policy from mechanism. This allows changes to be made to policy decisions without
needing to redesign the underlying mechanisms. For example, if the requirement changes from interrupting
every 100 seconds to every 200 seconds, only the policy needs to be updated, not the mechanism.
Implementation
Variability in Implementation:
Early operating systems were often written in assembly language, which is hardware-specific.
Later systems started using higher-level programming languages like Algol and PL/1.
Today, the most common languages for OS development include C and C++, although a mix of languages is often
used.
Language Choices:
Using high-level languages can make an OS easier to port to different hardware architectures, although this
may come at the cost of performance (it tends to be slower than assembly language).
Emulation: This technique allows an OS designed for one hardware architecture to run on another, providing
flexibility in deployment and testing.
1. General Structure
General-Purpose OS: Typically a large program that handles a wide range of tasks and services.
2. Types of Structures
Simple Structure:
Example: MS-DOS
Characterized by a straightforward design without much abstraction.
More Complex Structure:
Example: UNIX
Offers more features and capabilities than simpler systems but can still be seen as somewhat monolithic.
Layered Structure:
The OS is divided into multiple layers (levels), each built on top of the previous one.
Layer 0 (bottom) interacts directly with hardware, while the highest layer (Layer N) provides the user interface.
Microkernel Structure:
Example: Mach
A minimal kernel that handles only the most fundamental tasks, with additional services provided by user-space
processes.
Layered Approach
Divided into Layers:The OS is divided into a number of layers, where each layer is built on the previous
one:Layer 0: Hardware
Layer N: User Interface
Each layer only interacts with the layers directly below it, promoting modularity and simplifying design and
debugging. This structure makes it easier to modify or replace layers without affecting others, facilitating
system maintenance and updates.
Microkernels
A microkernel architecture moves most functionalities from the kernel into user space, allowing only the most
essential services to run in kernel mode. Here’s a closer look:
Key Features
Example: Mach is a well-known microkernel. The macOS kernel (Darwin) is partly based on Mach.
Communication: User modules interact through message passing rather than direct function calls, enhancing
modularity.
Benefits
Easier Extensibility: New features can be added without modifying the core kernel.
Portability: Microkernels can be adapted to new hardware architectures more easily.
Reliability: With less code running in kernel mode, there’s a reduced chance of crashes affecting the entire
system.
Security: Fewer processes in kernel mode mean better isolation and protection against vulnerabilities.
Detriments
Performance Overhead: Communication between user space and kernel space can introduce latency, impacting
performance.
Modules
Modern operating systems often implement Loadable Kernel Modules (LKMs), which enable a more flexible
and modular kernel structure:
Object-Oriented Approach: Core components are separate modules that communicate through defined
interfaces.
Dynamic Loading: Modules can be loaded and unloaded as needed, allowing for on-the-fly updates and
improvements.
Examples: Linux and Solaris utilize this approach, offering both modularity and the benefits of a monolithic
kernel.
Hybrid Systems
Most contemporary operating systems employ a hybrid structure, combining different models to optimize
performance, security, and usability:
Combination: Hybrid systems mix monolithic and microkernel designs. For instance:Linux and Solaris:
Monolithic kernels with modular capabilities for dynamic loading.
Windows: Primarily monolithic but incorporates microkernel elements for different subsystem functionalities.
Apple macOS: A hybrid design that features:A layered structure with the Aqua user interface and Cocoa
programming environment.
The underlying kernel consists of the Mach microkernel, BSD Unix components, and an I/O kit, plus dynamically
loadable modules called kernel extensions.
Android
Development: Created by the Open Handset Alliance, primarily Google, Android is an open-source operating
system.
Kernel: Built on a modified Linux kernel that manages processes, memory, and device drivers, with added power
management features.
Runtime Environment:
Android Architecture
Android's architecture is structured to provide a robust operating environment, primarily consisting of several
key layers:
Linux Kernel: At the core is the Linux kernel, which handles core system services like security, memory
management, and process management. It also provides drivers for hardware components.
Hardware Abstraction Layer (HAL): This layer offers a standard interface to the hardware, allowing Android to
interact with various hardware components in a consistent way.
Android Runtime (ART): The ART executes applications and includes core libraries that provide most of the
functionalities for Android apps. It replaced the older Dalvik virtual machine, improving performance and
efficiency.
Application Framework: This layer provides APIs for application developers, enabling them to interact with
hardware and system services. It supports application components like activities, services, content providers,
and broadcast receivers.
Applications: At the top level are the user-installed apps and system apps. These are built using the application
framework and provide the user interface and functionalities.
System Boot
Boot Process
Power On: When the system powers on, execution begins at a fixed memory location.
Bootstrap Loader: A small piece of code (bootstrap loader, often stored in ROM or EEPROM) initializes the
system by locating and loading the kernel into memory.
Two-Step Process: Often, the boot block at a fixed location is loaded first, which then loads the full bootstrap
loader from disk.
UEFI: Modern systems use Unified Extensible Firmware Interface (UEFI) instead of traditional BIOS for
booting.
Boot Loaders: Common loaders like GRUB allow users to select from multiple kernels and configurations.
Kernel Loads: Once loaded, the kernel starts the operating system.
Operating-System Debugging
Debugging involves identifying and resolving bugs and optimizing performance. Here are key elements:
Performance Tuning
Bottleneck Removal: Identify and eliminate performance bottlenecks.
System Behavior Measurement: The OS should provide tools to compute and display performance metrics.
Tools: Use programs like top (Linux) or Task Manager (Windows) to monitor system performance.
Tracing
Event Data Collection: Tracing involves gathering data for specific events, such as system call invocations.
Tools:strace: Traces system calls made by a process.
gdb: Source-level debugger for in-depth analysis.
perf: A collection of Linux performance analysis tools.
tcpdump: Captures network packet data for analysis.
Key Features
Tracing: BCC includes numerous scripts and tools to trace various activities within the operating system,
making it easier to understand system behavior.
Integration: It works closely with both user space and kernel space, providing a unified view of interactions
between the two.
Performance Monitoring: Helps identify performance bottlenecks and optimize system resource usage.
Example Tool: disksnoop.py
One specific tool, disksnoop.py, is used to trace disk I/O activity. It can provide insights into how disk operations
are being performed, including the latency of requests and their completion times.
Conclusion
The BPF Compiler Collection (BCC) is a valuable resource for developers and system administrators seeking to
enhance their debugging capabilities and performance monitoring in Linux environments. Its ability to trace
and analyze both user and kernel interactions makes it a vital tool in system performance tuning and
troubleshooting.