266 Matching Annotations
  1. Last 7 days
    1. The continuing advent of new technologies brings about new forms of networks. For example, a metropolitan-area network (MAN) could link buildings within a city. BlueTooth and 802.11 devices use wireless technology to communicate over a distance of several feet, in essence creating a personal-area network (PAN) between a phone and a headset or a smartphone and a desktop computer.

      This text emphasizes the variety of network types made possible by technological progress. Illustrations consist of:

      Metropolitan-Area Networks (MANs): This link has the several structures that is throughout the urban area.

      Personal-Area Networks (PANs): Compact wireless networks, such as the Bluetooth or the Wi-Fi (802.11), that connect the devices across the short ranges, for instance, connecting a smartphone to a headset or a computer.

      It demonstrates how the networks can be extended from the urban infrastructures to the highly localized, device-to-device connections.

    2. Some systems support proprietary protocols to suit their needs. For an operating system, it is necessary only that a network protocol have an interface device—a network adapter, for example—with a device driver to manage it, as well as software to handle data. These concepts are discussed throughout this book.

      This passage emphasizes that distributed systems can use both standard and proprietary network protocols. For an operating system, the main requirement is that the protocol has:

      1. A hardware interface, such as a network adapter.
      2. A device driver to manage the interface.
      3. Supporting software to handle data transfer and communication.

      These components ensure that the OS can interact with the network regardless of the specific protocol in use. The details of managing different network protocols are explored throughout the book.

    3. A distributed system is a collection of physically separate, possibly heterogeneous computer systems that are networked to provide users with access to the various resources that the system maintains. Access to a shared resource increases computation speed, functionality, data availability, and reliability. Some operating systems generalize network access as a form of file access, with the details of networking contained in the network interface's device driver. Others make users specifically invoke network functions. Generally, systems contain a mix of the two modes—for example FTP and NFS. The protocols that create a distributed system can greatly affect that system's utility and popularity.

      This passage explains how the distributed system as a network for physically seperating (and sometimes heterogeneous) computers which work together to provide the users access to their shared resources. The benefits of such systems include:

      1.Increased computation speed – multiple machines can process tasks in parallel. 2.Enhanced functionality – access to diverse resources across the network. 3.Higher data availability and reliability – resources remain accessible even if some nodes fail.

      Operating systems handle networked resource access in different ways: some abstract it as file access (hiding networking details via the device driver), while others require users to explicitly invoke network functions. Common protocols like FTP and NFS illustrate this mix. The choice and implementation of these protocols significantly influence the system's utility, performance, and adoption.

    4. Generally, systems contain a mix of the two modes—for example FTP and NFS. The protocols that create a distributed system can greatly affect that system's utility and popularity.

      This paragraph highlights that the distributed systems are frequently used to employ a mix of communication or the operational methods. For example:

      1. FTP (File Transfer Protocol): A standard protocol for transferring the files over a network between the computers.

      2. NFS (Network File System): A protocol which is used for the enabling of a computer for retrieving the files across the network as though they were said to be stored locally.

      The selection of these protocols will affect both the performance and the acceptance of the distributed system. An appropriately selected combination of the protocols can be used to enhance the system's efficiency, reliability, and the user-friendliness, and also consequently boosting its appeal.

    5. Broadly speaking, virtualization software is one member of a class that also includes emulation. Emulation, which involves simulating computer hardware in software, is typically used when the source CPU type is different from the target CPU type. For example, when Apple switched from the IBM Power CPU to the Intel x86 CPU for its desktop and laptop computers, it included an emulation facility called “Rosetta,” which allowed applications compiled for the IBM CPU to run on the Intel CPU. That same concept can be extended to allow an entire operating system written for one platform to run on another. Emulation comes at a heavy price, however. Every machine-level instruction that runs natively on the source system must be translated to the equivalent function on the target system, frequently resulting in several target instructions. If the source and target CPUs have similar performance levels, the emulated code may run much more slowly than the native code.

      This passage explains about the virtualization from the emulation, though both allow software designed for one system to run on another:

      Emulation: It simulates the hardware of one of the system in the software on another system.

      Use case: Running the software which is compiled for one of the CPU on the different CPU architecture (e.g., Apple’s Rosetta translating the PowerPC instructions for the Intel x86).

      Drawback: Performance overhead is said to be high because every source instruction must be translated into one or more of the target instructions, slowing execution compared to the native code.

      Virtualization vs. Emulation: Unlike the emulation, the virtualization typically runs on the same CPU architecture as the host, so the performance overhead is said to be lower. Emulation is very essential when the host and the guest architectures differ.

    6. Virtualization allows operating systems to run as applications within other operating systems. At first blush, there seems to be little reason for such functionality. But the virtualization industry is vast and growing, which is a testament to its utility and importance.

      This passage introduces virtualization, which lets an operating system run as a guest within another host operating system.

      Purpose: While it may seem unnecessary at first, virtualization provides major benefits:

      1. Resource efficiency: The multiple OS instances can be used to run on the same physical hardware.
      2. Testing and the development: Developers can be able to experiment without affecting any of the host system.
      3. Isolation and the security: Guest systems are isolated from each other and from the host.

      The rapid growth of the virtualization industry highlights its importance in modern computing, including cloud computing, server consolidation, and software testing.

    7. Protection and security require the system to be able to distinguish among all its users. Most operating systems maintain a list of user names and associated user identifiers (user IDs). In Windows parlance, this is a security ID (SID). These numerical IDs are unique, one per user. When a user logs in to the system, the authentication stage determines the appropriate user ID for the user. That user ID is associated with all of the user's processes and threads. When an ID needs to be readable by a user, it is translated back to the user name via the user name list.

      This passage explains how operating systems implement user-level protection and security using unique identifiers:

      1. User identification: Every user has a different unique numeric identifier—called a user ID in most of the systems or the security ID (SID) in their Windows.

      2. Authentication: When a user logs in, the system authenticates them and assigns the corresponding ID to all processes and threads they run.

      3. Mapping to names: When a user-visible name is needed, the system translates the numeric ID back to the username using the maintained list.

      In short, user IDs allow the OS to consistently track and enforce access permissions for each user** across all processes and system resources.

    8. A system can have adequate protection but still be prone to failure and allow inappropriate access. Consider a user whose authentication information (her means of identifying herself to the system) is stolen. Her data could be copied or deleted, even though file and memory protection are working. It is the job of security to defend a system from external and internal attacks. Such attacks spread across a huge range and include viruses and worms, denial-of-service attacks (which use all of a system's resources and so keep legitimate users out of the system), identity theft, and theft of service (unauthorized use of a system). Prevention of some of these attacks is considered an operating-system function on some systems, while other systems leave it to policy or additional software. Due to the alarming rise in security incidents, operating-system security features are a fast-growing area of research and implementation. We discuss security in Chapter 16.

      This text highlights the difference between the protection and the security:

      1. Protection versus security: Defensive measures (such as access limitations on files or memory) prevent unauthorized actions inside the system, yet they cannot avert attacks if a user's credentials are breached. Security tackles these wider risks.

      2. Attack categories: These instances encompass the viruses, worms, denial-of-service (DoS) assaults, identity fraud, and service theft—each one taking advantage of vulnerabilities outside the fundamental security protocols.

      3. Function of the operating system: Certain operating systems include the inherent safeguards, whereas the others depend on the protocols or the extra applications for the of handling security. With such increasing threats, the security has emerged as the primary emphasis in the study and the creation of the operating systems.

      Essentially, protection involves creating regulations within the system, while security focuses on safeguarding the system from internal and external threats.

    9. Protection can improve reliability by detecting latent errors at the interfaces between component subsystems. Early detection of interface errors can often prevent contamination of a healthy subsystem by another subsystem that is malfunctioning. Furthermore, an unprotected resource cannot defend against use (or misuse) by an unauthorized or incompetent user. A protection-oriented system provides a means to distinguish between authorized and unauthorized usage, as we discuss in Chapter 17.

      This text describes how safeguarding improves the dependability and safety of a system.

      1.Error detection: By monitoring the interactions between the subsystems, the protection can quickly detect concealed interface errors, preventing a malfunctioning component from affecting the system's functional areas.

      1. Access control: The measures are implemented to restrict unauthorized or by implementing the improper access to the resources, ensuring that only the legitimate users or the processes can be used to interact with their sensitive information or their devices.

      In conclusion, protecting guarantees safety while enhancing the reliability and steadiness of the system.

    10. Protection, then, is any mechanism for controlling the access of processes or users to the resources defined by a computer system. This mechanism must provide means to specify the controls to be imposed and to enforce the controls.

      This passage defines protection in computer systems as the mechanism that regulates access to system resources by processes or users. Protection has two key aspects:

      1. Specification – defining what access rights or restrictions each process or user has.
      2. Enforcement – ensuring that the defined controls are actually applied, preventing unauthorized access or actions.

      In essence, protection is the foundation of system security and resource management.

    11. If a computer system has multiple users and allows the concurrent execution of multiple processes, then access to data must be regulated. For that purpose, mechanisms ensure that files, memory segments, CPU, and other resources can be operated on by only those processes that have gained proper authorization from the operating system. For example, memory-addressing hardware ensures that a process can execute only within its own address space. The timer ensures that no process can gain control of the CPU without eventually relinquishing control. Device-control registers are not accessible to users, so the integrity of the various peripheral devices is protected.

      This passage highlights the importance of the one key role of the operating system is that of the hardware abstraction—hiding the low-level differences among the devices from both the users and the higher-level system components. In UNIX, this is achieved using the I/O subsystem, which is normalizes the communication with its various kinds of devices. The operating system offers a consistent interface, enabling programs to execute I/O operations without requiring knowledge of the specific characteristics of each device

    12. One of the purposes of an operating system is to hide the peculiarities of specific hardware devices from the user. For example, in UNIX, the peculiarities of I/O devices are hidden from the bulk of the operating system itself by the I/O subsystem. The I/O subsystem consists of several components:

      This passage highlights the importance of the one key role of the operating system is that of the hardware abstraction—hiding the low-level differences among the devices from both the users and the higher-level system components. In UNIX, this is achieved using the I/O subsystem, which is normalizes the communication with its various kinds of devices. The operating system offers a consistent interface, enabling programs to execute I/O operations without requiring knowledge of the specific characteristics of each device

    13. In a distributed environment, the situation becomes even more complex. In this environment, several copies (or replicas) of the same file can be kept on different computers. Since the various replicas may be accessed and updated concurrently, some distributed systems ensure that, when a replica is updated in one place, all other replicas are brought up to date as soon as possible. There are various ways to achieve this guarantee, as we discuss in Chapter 19.

      This passage extends the discussion of the data consistency to the distributed systems, where the multiple copies of the same file exist on the different computers. When the updates are occurring on one replica, the system should synchronize all the other replicas to prevent the inconsistencies. Ensuring this requires such specialized replication and the consistency protocols, which are used to handle the concurrent updates and also maintain a coherent view of the data across the network. This highlights the added complexity of maintaining the data integrity in the distributed environments compared to a single, multitasking system.

    14. In a computing environment where only one process executes at a time, this arrangement poses no difficulties, since an access to integer A will always be to the copy at the highest level of the hierarchy. However, in a multitasking environment, where the CPU is switched back and forth among various processes, extreme care must be taken to ensure that, if several processes wish to access A, then each of these processes will obtain the most recently updated value of A.

      This passage highlights the challenge of maintaining the data consistency in the multitasking systems. When the multiple processes may be able to access the same data A, each process must see the most recent value, regardless of which level of the memory hierarchy currently holds it. Unlike the single-process systems, where the highest-level copy suffices, the multitasking systems are said to require the mechanisms—such as the cache coherence protocols or the memory barriers—to prevent the processes from reading such stale data. This ensures that the correctness when the CPU time is shared among processes.

    15. In a hierarchical storage structure, the same data may appear in different levels of the storage system. For example, suppose that an integer A that is to be incremented by 1 is located in file B, and file B resides on hard disk. The increment operation proceeds by first issuing an I/O operation to copy the disk block on which A resides to main memory. This operation is followed by copying A to the cache and to an internal register. Thus, the copy of A appears in several places: on the hard disk, in main memory, in the cache, and in an internal register (see Figure 1.15). Once the increment takes place in the internal register, the value of A differs in the various storage systems. The value of A becomes the same only after the new value of A is written from the internal register back to the hard disk.

      This passage illustrates data replication across the storage hierarchy. An individual data element, like the integer A, can be considered to exist at the same time across various storage levels: on the disk, in the main memory, in the cache, and within the CPU register. Changes happen initially in the quickest storage (register) before moving back to slower layers. The final value of A is consistent across all levels only after it is written back from the register to memory and disk. This demonstrates the principle of temporal locality and consistency management in hierarchical storage systems.

    16. The movement of information between levels of a storage hierarchy may be either explicit or implicit, depending on the hardware design and the controlling operating-system software. For instance, data transfer from cache to CPU and registers is usually a hardware function, with no operating-system intervention. In contrast, transfer of data from disk to memory is usually controlled by the operating system.

      Data movement in a storage hierarchy can be used either by the automatic (hardware-controlled) or managed by the operating system. For example, transfers from the CPU caches to the registers happen to be automatically via hardware, while the transfers from the disk to the main memory are usually initiated and managed by the operating system. This distinction highlights how some storage operations are transparent to software, whereas others require OS intervention.

    17. Other caches are implemented totally in hardware. For instance, most systems have an instruction cache to hold the instructions expected to be executed next. Without this cache, the CPU would have to wait several cycles while an instruction was fetched from main memory. For similar reasons, most systems have one or more high-speed data caches in the memory hierarchy. We are not concerned with these hardware-only caches in this text, since they are outside the control of the operating system.

      Some caches exist entirely in hardware and are transparent to the operating system. Examples include the instruction caches, which are used to store the upcoming instructions for preventing the CPU delays, and the high-speed data caches within the memory hierarchy. These caches are used to improve the performance by reducing the time the CPU waits for the memory accesses, but their management is handled by the hardware, not the operating system.

    18. In addition, internal programmable registers provide a high-speed cache for main memory. The programmer (or compiler) implements the register-allocation and register-replacement algorithms to decide which information to keep in registers and which to keep in main memory.

      Registers act as the fastest form of memory within a CPU, providing a high-speed cache for main memory. Programmers or compilers manage which values are kept in registers versus main memory using register-allocation and register-replacement algorithms. This careful management optimizes performance by keeping the most frequently accessed data in the fastest storage.

    19. Caching is an important principle of computer systems. Here's how it works. Information is normally kept in some storage system (such as main memory). As it is used, it is copied into a faster storage system—the cache—on a temporary basis. When we need a particular piece of information, we first check whether it is in the cache. If it is, we use the information directly from the cache. If it is not, we use the information from the source, putting a copy in the cache under the assumption that we will need it again soon.

      Caching improves the system performance by storing the frequently used data in a faster, smaller memory (the cache). When a program is meant to need the information, the system is used to first check the cache—if the data is present (cache hit), how it can be used immediately, saving time. If the data is said to be absent (cache miss), then it is fetched from the slower main memory or the storage and also copied into the cache, thus anticipating future use. This principle reduces the access time for the repeatedly used data.

    20. Tertiary storage is not crucial to system performance, but it still must be managed. Some operating systems take on this task, while others leave tertiary-storage management to application programs. Some of the functions that operating systems can provide include mounting and unmounting media in devices, allocating and freeing the devices for exclusive use by processes, and migrating data from secondary to tertiary storage.

      Tertiary storage—such as the magnetic tapes or the optical disks—is slower and also used mainly for its backup or the archival purposes, so that it has less impact on the system performance than the primary or the secondary storage. Operating systems may be used to manage the tertiary storage by mounting/unmounting media, controlling access, and moving data between secondary and tertiary storage, though some systems leave these tasks to applications. This ensures proper organization and availability of less frequently accessed data.

    21. Because secondary storage is used frequently and extensively, it must be used efficiently. The entire speed of operation of a computer may hinge on the speeds of the secondary storage subsystem and the algorithms that manipulate that subsystem.

      Secondary storage performance has the direct impact on the overall system efficiency. Since the programs are frequently used for reading from and writing to these devices, both the hardware speed (HDD, SSD, etc.) and the operating system algorithms that are used to manage the data placement, retrieval, and the caching are critical. Efficient use of the secondary storage can greatly affect the computer’s overall speed and its responsiveness.

    22. As we have already seen, the computer system must provide secondary storage to back up main memory. Most modern computer systems use HDDs and NVM devices as the principal on-line storage media for both programs and data. Most programs—including compilers, web browsers, word processors, and games—are stored on these devices until loaded into memory. The programs then use the devices as both the source and the destination of their processing. Hence, the proper management of secondary storage is of central importance to a computer system. The operating system is responsible for the following activities in connection with secondary storage management:

      Secondary storage (like HDDs and NVM devices) serves as persistent storage for programs and data, backing up the volatile main memory. Programs—such as compilers, browsers, and games—reside on these devices until loaded into RAM and continue to read from or write to them during execution.

    23. The operating system implements the abstract concept of a file by managing mass storage media and the devices that control them. In addition, files are normally organized into directories to make them easier to use. Finally, when multiple users have access to files, it may be desirable to control which user may access a file and how that user may access it (for example, read, write, append).

      The operating system turns the abstract idea of a file into a practical system by managing storage devices and the data on them. To improve the usability, the files are usually organized into the directories (or folders). When the multiple users share the system, the OS also provides the access control, specifying who can read, write, or modify each of the file.

    24. A file is a collection of related information defined by its creator. Commonly, files represent programs (both source and object forms) and data. Data files may be numeric, alphabetic, alphanumeric, or binary. Files may be free-form (for example, text files), or they may be formatted rigidly (for example, fixed fields such as an mp3 music file). Clearly, the concept of a file is an extremely general one.

      A file is a structured collection of related information created by a user or program. Files can store programs (source or executable) or data in various forms—numeric, text, or binary. They may be free-form, like plain text, or structured, like an MP3 or database record. The idea of a file is broad, serving as the primary means to organize, store, and access information in a computer system.

    25. To make the computer system convenient for users, the operating system provides a uniform, logical view of information storage. The operating system abstracts from the physical properties of its storage devices to define a logical storage unit, the file. The operating system maps files onto physical media and accesses these files via the storage devices.

      Operating systems are used to simplify the data storage for the users by providing the logical, uniform view of the storage. They abstract away the physical details of the disks or the other devices and also organize the data into the files. The OS handles the mapping of these files onto the physical storage and manages its access, so that the users and the programs are there to interact with the files without needing to know how or where the data is physically being stored.

    26. To improve both the utilization of the CPU and the speed of the computer's response to its users, general-purpose computers must keep several programs in memory, creating a need for memory management. Many different memory-management schemes are used. These schemes reflect various approaches, and the effectiveness of any given algorithm depends on the situation. In selecting a memory-management scheme for a specific system, we must take into account many factors—especially the hardware design of the system. Each algorithm requires its own hardware support.

      Modern computers improve CPU utilization and responsiveness by keeping multiple programs in memory simultaneously, which necessitates memory management. Various types of the memory-management schemes exist, each with its advantages and their limitations. Choosing the right scheme depends on system hardware and the requirements of the operating system, as every scheme often needs the specific hardware support to function efficiently.

    27. For a program to be executed, it must be mapped to absolute addresses and loaded into memory. As the program executes, it accesses program instructions and data from memory by generating these absolute addresses. Eventually, the program terminates, its memory space is declared available, and the next program can be loaded and executed.

      Before the execution, a program’s instructions and the data are assigned the absolute memory addresses and loaded into the main memory. During its execution, the CPU accesses these types of instructions and the data by using those addresses. When the program gets finished , the operating system reclaims the memory, making it available for the next program.

    28. A process is the unit of work in a system. A system consists of a collection of processes, some of which are operating-system processes (those that execute system code) and the rest of which are user processes (those that execute user code). All these processes can potentially execute concurrently—by multiplexing on a single CPU core—or in parallel across multiple CPU cores.

      A process serves as the fundamental unit of operation within a computer system. Systems execute multiple processes simultaneously, encompassing operating-system processes (that oversee the system) and user processes (that run user applications). On a single CPU, processes take turns quickly through multiplexing, whereas on multiple CPU cores, they can execute simultaneously, performing various tasks concurrently

    29. A process needs certain resources—including CPU time, memory, files, and I/O devices—to accomplish its task. These resources are typically allocated to the process while it is running. In addition to the various physical and logical resources that a process obtains when it is created, various initialization data (input) may be passed along. For example, consider a process running a web browser whose function is to display the contents of a web page on a screen. The process will be given the URL as an input and will execute the appropriate instructions and system calls to obtain and display the desired information on the screen. When the process terminates, the operating system will reclaim any reusable resources.

      A process needs the resources such as the CPU time, memory, files, and the I/O devices to execute its functions. These resources are assigned when the process executes, and it may also obtain the input data to direct its operation—for example, a web browser process receives the URL to show the web page. Once the process is complete, the OS retrieves its resources for use by other processes

    30. A program can do nothing unless its instructions are executed by a CPU. A program in execution, as mentioned, is a process. A program such as a compiler is a process, and a word-processing program being run by an individual user on a PC is a process. Similarly, a social media app on a mobile device is a process. For now, you can consider a process to be an instance of a program in execution, but later you will see that the concept is more general. As described in Chapter 3, it is possible to provide system calls that allow processes to create subprocesses to execute concurrently.

      A process is merely the program that is actively executing on the CPU. For instance, the PC's word processor, a compiler, or a social media application on a phone are all processes while they run. Fundamentally, a process represents an active occurrence of a program, and processes are capable of generating subprocesses that operate simultaneously, enabling multiple tasks to be performed concurrently

    31. Before turning over control to the user, the operating system ensures that the timer is set to interrupt. If the timer interrupts, control transfers automatically to the operating system, which may treat the interrupt as a fatal error or may give the program more time. Clearly, instructions that modify the content of the timer are privileged.

      Before running the user program, the OS sets the timer which can interrupt the program after a certain time. When the timer is said to goes off, then the control returns to the OS, which can decide whether the program has used too much time or needs more. Only the OS can modify the timer because changing it could let a user program bypass CPU control, so instructions that alter the timer are privileged.

    32. System calls provide the means for a user program to ask the operating system to perform tasks reserved for the operating system on the user program's behalf. A system call is invoked in a variety of ways, depending on the functionality provided by the underlying processor. In all forms, it is the method used by a process to request action by the operating system. A system call usually takes the form of a trap to a specific location in the interrupt vector. This trap can be executed by a generic trap instruction, although some systems have a specific syscall instruction to invoke a system call.

      System calls are used to allow the user programs to request the operating system for executing the tasks such that the program cannot be used to perform alone, like accessing files or sending data across the network. They function by triggering the trap that briefly switches the CPU from user mode to kernel mode, allowing the OS to securely execute the requested operation. Depending on the processor, this trap may use the general instruction or a specific system call instruction.

    33. The concept of modes can be extended beyond two modes. For example, Intel processors have four separate protection rings, where ring 0 is kernel mode and ring 3 is user mode. (Although rings 1 and 2 could be used for various operating-system services, in practice they are rarely used.) ARM v8 systems have seven modes. CPUs that support virtualization (Section 18.1) frequently have a separate mode to indicate when the virtual machine manager (VMM) is in control of the system. In this mode, the VMM has more privileges than user processes but fewer than the kernel. It needs that level of privilege so it can create and manage virtual machines, changing the CPU state to do so.

      Some processors support more than just kernel and user modes. For example, Intel CPUs use four “protection rings,” with ring 0 being full-access kernel mode and ring 3 being restricted user mode. Rings 1 and 2 exist but are rarely used. ARM v8 has seven modes, and CPUs that run virtual machines often include a virtual machine manager (VMM) mode, which sits between user and kernel privileges. This allows the VMM to safely control virtual machines without having full kernel access.

    34. At system boot time, the hardware starts in kernel mode. The operating system is then loaded and starts user applications in user mode. Whenever a trap or interrupt occurs, the hardware switches from user mode to kernel mode (that is, changes the state of the mode bit to 0). Thus, whenever the operating system gains control of the computer, it is in kernel mode. The system always switches to user mode (by setting the mode bit to 1) before passing control to a user program.

      Upon booting, the computer initiates in kernel mode, granting the OS complete authority over the hardware. Once the OS is said to be loaded, the user applications operate in the user mode, which has the limited access. When an interrupt or the trap occurs (such as an error or system call), the hardware returns to the kernel mode, allowing the OS to manage it securely. Before handing control back to a user program, the system reverts to user mode

    35. Since the operating system and its users share the hardware and software resources of the computer system, a properly designed operating system must ensure that an incorrect (or malicious) program cannot cause other programs—or the operating system itself—to execute incorrectly. In order to ensure the proper execution of the system, we must be able to distinguish between the execution of operating-system code and user-defined code. The approach taken by most computer systems is to provide hardware support that allows differentiation among various modes of execution.

      Since the operating system and the user applications are said to utilize the same computer, it is essential for the OS to safeguard itself and the other programs from the faulty or the harmful code. To achieve this, the majority of the systems are meant to utilize hardware-supported execution modes that distinguish operating-system code from user code. This guarantees that user applications cannot inadvertently—or deliberately—disturb the OS or other applications, maintaining the system's stability and also security

    36. In a multitasking system, the operating system must ensure reasonable response time. A common method for doing so is virtual memory, a technique that allows the execution of a process that is not completely in memory (Chapter 10). The main advantage of this scheme is that it enables users to run programs that are larger than actual physical memory. Further, it abstracts main memory into a large, uniform array of storage, separating logical memory as viewed by the user from physical memory. This arrangement frees programmers from concern over memory-storage limitations.

      Virtual memory is like giving each of the program the illusion of having its own huge memory space, even if the computer’s physical RAM is said to be limited. It allows the system to temporarily use the disk storage to the extend memory, so that the larger programs can run without worrying about the fitting into the actual RAM. This not only makes the multitasking smoother (faster response times) but also frees programmers from needing to manage memory details themselves.

    37. Multitasking is a logical extension of multiprogramming. In multitasking systems, the CPU executes multiple processes by switching among them, but the switches occur frequently, providing the user with a fast response time. Consider that when a process executes, it typically executes for only a short time before it either finishes or needs to perform I/O. I/O may be interactive; that is, output goes to a display for the user, and input comes from a user keyboard, mouse, or touch screen. Since interactive I/O typically runs at “people speeds,” it may take a long time to complete. Input, for example, may be bounded by the user's typing speed; seven characters per second is fast for people but incredibly slow for computers. Rather than let the CPU sit idle as this interactive input takes place, the operating system will rapidly switch the CPU to another process.

      Multitasking builds on the multiprogramming by making the process switching much faster and also more frequent. This gives the illusion such that the multiple programs are running at the same time, even though the CPU is just switching rapidly betweenthem. For example, while one program is waiting for the slow input from the keyboard or the mouse (at human speed), the CPU quickly moves to the another program instead of just sitting idle.

    38. This idea is common in other life situations. A lawyer does not work for only one client at a time, for example. While one case is waiting to go to trial or have papers typed, the lawyer can work on another case. If she has enough clients, the lawyer will never be idle for lack of work. (Idle lawyers tend to become politicians, so there is a certain social value in keeping lawyers busy.)

      The book uses a lawyer as an analogy for multiprogramming. Just like the lawyer doesn’t have to handle only one case at a time—she switches between the cases while waiting on paperwork or trial dates—a computer doesn’t run just one program at once. When one program is waiting, the CPU works on another. This ensures the system (and the lawyer) is always busy and productive.

    39. One of the most important aspects of operating systems is the ability to run multiple programs, as a single program cannot, in general, keep either the CPU or the I/O devices busy at all times. Furthermore, users typically want to run more than one program at a time as well. Multiprogramming increases CPU utilization, as well as keeping users satisfied, by organizing programs so that the CPU always has one to execute. In a multiprogrammed system, a program in execution is termed a process.

      A major task of the operating system is to ensure the computer stays active and doesn't remain idle. One program cannot constantly engage both the CPU and input/output devices. This is why contemporary systems support multiprogramming—executing multiple programs simultaneously. In this manner, while one program is idle (for instance, awaiting data from the disk), the CPU can process another. This maintains system efficiency and ensures user satisfaction

    40. If there are no processes to execute, no I/O devices to service, and no users to whom to respond, an operating system will sit quietly, waiting for something to happen. Events are almost always signaled by the occurrence of an interrupt. In Section 1.2.1 we described hardware interrupts. Another form of interrupt is a trap (or an exception), which is a software-generated interrupt caused either by an error (for example, division by zero or invalid memory access) or by a specific request from a user program that an operating-system service be performed by executing a special operation called a system call.

      If nothing is happening—no programs to run, no input/output to handle, no user activity—the operating system just waits. Something new usually starts with an interrupt. Hardware interrupts come from the devices (like a keyboard press), but there are also software interrupts, called the traps (or exceptions). Traps are said to happen when the program causes an error (like dividing by zero or accessing the memory it shouldn’t) or when the program requests the help from an operating system. That request is called a system call, which is like the program raising its hand and asking the OS to step in.

    41. Once the kernel is loaded and executing, it can start providing services to the system and its users. Some services are provided outside of the kernel by system programs that are loaded into memory at boot time to become system daemons, which run the entire time the kernel is running. On Linux, the first system program is “systemd,” and it starts many other daemons. Once this phase is complete, the system is fully booted, and the system waits for some event to occur.

      Once the kernel has completed loading, the operating system starts providing its services. Some of the services are reported to stem from the system programs (referred to as daemons) which start right after the boot process. These daemons keep on functioning in the background as long as the system remains to be active. In Linux, for example, the main system program is programmed, which is then starts various other daemons crucial for the system's functionality. Once all configurations are complete, the computer is considered fully functional and merely awaits events (like user interactions or assignments) to take place.

    42. Now that we have discussed basic information about computer-system organization and architecture, we are ready to talk about operating systems. An operating system provides the environment within which programs are executed. Internally, operating systems vary greatly, since they are organized along many different lines. There are, however, many commonalities, which we consider in this section.

      Having discussed the construction and arrangement of computers, we can now turn our attention to the operating system (OS) itself. The operating system is the software framework that creates the environment for all applications to operate. Despite the differences in appearance and functionality, operating systems have numerous similar characteristics. This part will emphasize the common characteristics and describe the function an OS serves in enabling the overall computer system to be functional

    43. Other forms of clusters include parallel clusters and clustering over a wide-area network (WAN) (as described in Chapter 19). Parallel clusters allow multiple hosts to access the same data on shared storage. Because most operating systems lack support for simultaneous data access by multiple hosts, parallel clusters usually require the use of special versions of software and special releases of applications. For example, Oracle Real Application Cluster is a version of Oracle's database that has been designed to run on a parallel cluster. Each machine runs Oracle, and a layer of software tracks access to the shared disk. Each machine has full access to all data in the database. To provide this shared access, the system must also supply access control and locking to ensure that no conflicting operations occur. This function, commonly known as a distributed lock manager (DLM), is included in some cluster technology.

      Clusters may appear in various configurations, including parallel clusters and WAN-based clusters. A parallel cluster enables several computers (hosts) to access identical data located on shared storage. However, because most operating systems don’t inherently permit multiple machines to access the same data simultaneously, specialized software is required. For example, the Oracle Real Application Cluster (RAC) serves this purpose, allowing different servers to work together with Oracle and access the same kind of database.To avoid problems (like two servers trying to alter the same data at once), the system employs a distributed lock manager (DLM)—a method that guarantees data changes take place in an organized way

    44. Since a cluster consists of several computer systems connected via a network, clusters can also be used to provide high-performance computing environments. Such systems can supply significantly greater computational power than single-processor or even SMP systems because they can run an application concurrently on all computers in the cluster. The application must have been written specifically to take advantage of the cluster, however. This involves a technique known as parallelization, which divides a program into separate components that run in parallel on individual cores in a computer or computers in a cluster

      Clusters are utilized not just to boost the reliability but also for the high-performance computing (HPC). By connecting the different systems, clusters can offer much higher computing power when compared to the single machine or even the symmetric multiprocessing (SMP) setup. This method is considered effective only when the application is crafted for the parallel processing, meaning it involves the breaking the program into smaller pieces that can run simultaneously on the different cores or machines in the cluster

    45. Clustering can be structured asymmetrically or symmetrically. In asymmetric clustering, one machine is in hot-standby mode while the other is running the applications. The hot-standby host machine does nothing but monitor the active server. If that server fails, the hot-standby host becomes the active server. In symmetric clustering, two or more hosts are running applications and are monitoring each other. This structure is obviously more efficient, as it uses all of the available hardware. However, it does require that more than one application be available to run.

      This part evaluates asymmetric and symmetric clustering. In asymmetric clustering, one server operates actively while another remains on standby, prepared to assume control if the active server experiences a failure. In symmetric clustering, every server operates applications while observing one another, which is more effective as all hardware is utilized, though it necessitates several applications to distribute the workload.

    46. High availability provides increased reliability, which is crucial in many applications. The ability to continue providing service proportional to the level of surviving hardware is called graceful degradation. Some systems go beyond graceful degradation and are called fault tolerant, because they can suffer a failure of any single component and still continue operation. Fault tolerance requires a mechanism to allow the failure to be detected, diagnosed, and, if possible, corrected.

      This passage describes high availability, graceful degradation, and fault tolerance. Improved availability increases system reliability. Graceful degradation allows for the system to be able to function based on the hardware which is said to be accessible. Fault-tolerant systems are capable of enduring the failure of any individual component by utilizing techniques to detect, assess, and rectify problems

    47. Clustering is usually used to provide high-availability service—that is, service that will continue even if one or more systems in the cluster fail. Generally, we obtain high availability by adding a level of redundancy in the system. A layer of cluster software runs on the cluster nodes. Each node can monitor one or more of the others (over the network). If the monitored machine fails, the monitoring machine can take ownership of its storage and restart the applications that were running on the failed machine. The users and clients of the applications see only a brief interruption of service.

      This section describes clustered multiprocessor architectures, comprising several individual systems (nodes), frequently multicore, linked to function collaboratively. They are loosely interconnected, usually share storage, and exchange information through a LAN or high-speed connection such as InfiniBand. Cluster definitions differ, but the main difference lies in the node-based architecture compared to closely integrated multiprocessors.

    48. Another type of multiprocessor system is a clustered system, which gathers together multiple CPUs. Clustered systems differ from the multiprocessor systems described in Section 1.3.2 in that they are composed of two or more individual systems—or nodes—joined together; each node is typically a multicore system. Such systems are considered loosely coupled. We should note that the definition of clustered is not concrete; many commercial and open-source packages wrestle to define what a clustered system is and why one form is better than another. The generally accepted definition is that clustered computers share storage and are closely linked via a local-area network LAN (as described in Chapter 19) or a faster interconnect, such as InfiniBand.

      This text describes clustered multiprocessor systems, which comprise several individual systems (nodes), typically multicore, linked to function collaboratively. They are weakly linked, usually share storage, and interact through a LAN or fast interconnect such as InfiniBand. Cluster definitions differ, but the main difference lies in the node-based architecture as opposed to closely integrated multiprocessors.

    49. Finally, blade servers are systems in which multiple processor boards, I/O boards, and networking boards are placed in the same chassis. The difference between these and traditional multiprocessor systems is that each blade-processor board boots independently and runs its own operating system. Some blade-server boards are multiprocessor as well, which blurs the lines between types of computers. In essence, these servers consist of multiple independent multiprocessor systems.

      This passage explains blade servers, where multiple processor, I/O, and networking boards reside in a single chassis. Each blade boots independently and runs its own OS. Some blades are multiprocessor systems, effectively creating multiple independent multiprocessor systems within one chassis, blurring traditional system classifications.

    50. A potential drawback with a NUMA system is increased latency when a CPU must access remote memory across the system interconnect, creating a possible performance penalty. In other words, for example, CPU0 cannot access the local memory of CPU3 as quickly as it can access its own local memory, slowing down performance. Operating systems can minimize this NUMA penalty through careful CPU scheduling and memory management, as discussed in Section 5.5.2 and Section 10.5.4. Because NUMA systems can scale to accommodate a large number of processors, they are becoming increasingly popular on servers as well as high-performance computing systems.

      This section highlights a possible limitation of NUMA architectures: retrieving remote memory via the system interconnect results in greater latency than accessing local memory. Operating systems are used to mitigate this penalty through the effective CPU scheduling and the memory management. Nonetheless, NUMA is being utilized more frequently in servers and high-performance computing because of its scalability

    51. Adding additional CPUs to a multiprocessor system will increase computing power; however, as suggested earlier, the concept does not scale very well, and once we add too many CPUs, contention for the system bus becomes a bottleneck and performance begins to degrade. An alternative approach is instead to provide each CPU (or group of CPUs) with its own local memory that is accessed via a small, fast local bus. The CPUs are connected by a shared system interconnect, so that all CPUs share one physical address space. This approach—known as non-uniform memory access, or NUMA—is illustrated in Figure 1.10. The advantage is that, when a CPU accesses its local memory, not only is it fast, but there is also no contention over the system interconnect. Thus, NUMA systems can scale more effectively as more processors are added.

      This section describes the NUMA (Non-Uniform Memory Access) method, which tackles scaling constraints in multiprocessor systems. Every CPU (or group of CPUs) possesses local memory that can be accessed through a rapid local bus, minimizing contention. All CPUs utilize a system interconnect for the global address space, enhancing scalability and performance as additional processors are included

    52. In Figure 1.9, we show a dual-core design with two cores on the same processor chip. In this design, each core has its own register set, as well as its own local cache, often known as a level 1, or L1, cache. Notice, too, that a level 2 (L2) cache is local to the chip but is shared by the two processing cores. Most architectures adopt this approach, combining local and shared caches, where local, lower-level caches are generally smaller and faster than higher-level shared caches. Aside from architectural considerations, such as cache, memory, and bus contention, a multicore processor with N cores appears to the operating system as N standard CPUs. This characteristic puts pressure on operating-system designers—and application programmers—to make efficient use of these processing cores, an issue we pursue in Chapter 4. Virtually all modern operating systems—including Windows, macOS, and Linux, as well as Android and iOS mobile systems—support multicore SMP systems.

      This excerpt outlines a dual-core processor design, where each core possesses its own registers and L1 cache, but they both have access to a common L2 cache. Multicore processors are recognized as several CPUs by the OS, necessitating meticulous resource and process management to enhance efficiency. The majority of contemporary operating systems accommodate this multicore SMP architecture

    53. The definition of multiprocessor has evolved over time and now includes multicore systems, in which multiple computing cores reside on a single chip. Multicore systems can be more efficient than multiple chips with single cores because on-chip communication is faster than between-chip communication. In addition, one chip with multiple cores uses significantly less power than multiple single-core chips, an important issue for mobile devices as well as laptops.

      This passage explains that multicore systems are now considered multiprocessors. Multiple cores on a single chip improve efficiency due to faster on-chip communication and lower power consumption compared with multiple single-core chips, making them ideal for mobile devices and laptops.

    54. The benefit of this model is that many processes can run simultaneously—N processes can run if there are N CPUs—without causing performance to deteriorate significantly. However, since the CPUs are separate, one may be sitting idle while another is overloaded, resulting in inefficiencies. These inefficiencies can be avoided if the processors share certain data structures. A multiprocessor system of this form will allow processes and resources—such as memory—to be shared dynamically among the various processors and can lower the workload variance among the processors. Such a system must be written carefully, as we shall see in Chapter 5 and Chapter 6.

      This excerpt emphasizes the benefits and difficulties of multiprocessor systems. Although multiple CPUs enable the concurrent execution of various processes, distinct processors may result in uneven load distribution. Dynamic sharing of data structures and resources aids in evenly distributing the workload, yet demands meticulous design to prevent inefficiencies and uphold system stability

    55. The most common multiprocessor systems use symmetric multiprocessing (SMP), in which each peer CPU processor performs all tasks, including operating-system functions and user processes. Figure 1.8 illustrates a typical SMP architecture with two processors, each with its own CPU. Notice that each CPU processor has its own set of registers, as well as a private—or local—cache. However, all processors share physical memory over the system bus.

      This passage introduces symmetric multiprocessing (SMP), where each CPU handles both OS and user tasks. Each processor has its own registers and local cache, but all share the system’s physical memory, allowing coordinated access and parallel execution.

    56. On modern computers, from mobile devices to servers, multiprocessor systems now dominate the landscape of computing. Traditionally, such systems have two (or more) processors, each with a single-core CPU. The processors share the computer bus and sometimes the clock, memory, and peripheral devices. The primary advantage of multiprocessor systems is increased throughput. That is, by increasing the number of processors, we expect to get more work done in less time. The speed-up ratio with N processors is not N, however; it is less than N. When multiple processors cooperate on a task, a certain amount of overhead is incurred in keeping all the parts working correctly. This overhead, plus contention for shared resources, lowers the expected gain from additional processors.

      This passage discusses multiprocessor systems, which use two or more CPUs to increase overall throughput. While adding processors can speed up work, the speed-up is less than linear due to overhead in coordination and contention for shared resources like memory and buses.

    57. All of these special-purpose processors run a limited instruction set and do not run processes. Sometimes, they are managed by the operating system, in that the operating system sends them information about their next task and monitors their status. For example, a disk-controller microprocessor receives a sequence of requests from the main CPU core and implements its own disk queue and scheduling algorithm. This arrangement relieves the main CPU of the overhead of disk scheduling. PCs contain a microprocessor in the keyboard to convert the keystrokes into codes to be sent to the CPU. In other systems or circumstances, special-purpose processors are low-level components built into the hardware. The operating system cannot communicate with these processors; they do their jobs autonomously. The use of special-purpose microprocessors is common and does not turn a single-processor system into a multiprocessor. If there is only one general-purpose CPU with a single processing core, then the system is a single-processor system. According to this definition, however, very few contemporary computer systems are single-processor systems.

      This text describes the function of specialized processors in single-processor systems. These processors manage particular functions (e.g., disk scheduling, keyboard input) either with OS oversight or independently. Their presence does not convert the system into a multiprocessor configuration, which needs multiple general-purpose CPU cores. The majority of contemporary computers are not solely single-processor systems anymore

    58. Many years ago, most computer systems used a single processor containing one CPU with a single processing core. The core is the component that executes instructions and registers for storing data locally. The one main CPU with its core is capable of executing a general-purpose instruction set, including instructions from processes. These systems have other special-purpose processors as well. They may come in the form of device-specific processors, such as disk, keyboard, and graphics controllers.

      This passage describes single-processor systems, where one CPU with a single core executes general-purpose instructions. These systems may also include special-purpose processors for tasks like disk, keyboard, or graphics control, supplementing the main CPU.

    59. Interrupts are an important part of a computer architecture. Each computer design has its own interrupt mechanism, but several functions are common. The interrupt must transfer control to the appropriate interrupt service routine. The straightforward method for managing this transfer would be to invoke a generic routine to examine the interrupt information. The routine, in turn, would call the interrupt-specific handler. However, interrupts must be handled quickly, as they occur very frequently. A table of pointers to interrupt routines can be used instead to provide the necessary speed. The interrupt routine is called indirectly through the table, with no intermediate routine needed. Generally, the table of pointers is stored in low memory (the first hundred or so locations). These locations hold the addresses of the interrupt service routines for the various devices. This array, or interrupt vector, of addresses is then indexed by a unique number, given with the interrupt request, to provide the address of the interrupt service routine for the interrupting device. Operating systems as different as Windows and UNIX dispatch interrupts in this manner.

      This section explains how interrupts are effectively handled in computer systems. Rather than employing a standard procedure for managing every interrupt, the CPU utilizes the interrupt vector—a low-memory pointer table—to swiftly find and execute the relevant interrupt service routine. This approach enables rapid and regular management of device requests, a strategy employed by operating systems such as Windows and UNIX

    60. In Section 1.2, we introduced the general structure of a typical computer system. A computer system can be organized in a number of different ways, which we can categorize roughly according to the number of general-purpose processors used.

      This passage introduces the idea that computer systems can be organized based on processor count. The structure of a system—single-processor or multi-processor—affects how resources are managed and how tasks are executed concurrently.

    61. Recall from the beginning of this section that a general-purpose computer system consists of multiple devices, all of which exchange data via a common bus. The form of interrupt-driven I/O described in Section 1.2.1 is fine for moving small amounts of data but can produce high overhead when used for bulk data movement such as NVS I/O. To solve this problem, direct memory access (DMA) is used. After setting up buffers, pointers, and counters for the I/O device, the device controller transfers an entire block of data directly to or from the device and main memory, with no intervention by the CPU. Only one interrupt is generated per block, to tell the device driver that the operation has completed, rather than the one interrupt per byte generated for low-speed devices. While the device controller is performing these operations, the CPU is available to accomplish other work.

      This text describes Direct Memory Access (DMA), enhancing efficiency for large data transfers. Rather than having the CPU manage each byte (causing numerous interrupts), the device controller moves whole blocks of data straight between the device and memory. This minimizes CPU load and enables it to handle additional tasks during the transfer.

    62. A large portion of operating system code is dedicated to managing I/O, both because of its importance to the reliability and performance of a system and because of the varying nature of the devices.

      This passage highlights that a significant part of an operating system focuses on I/O management. The diversity of devices and the critical role of I/O in system performance and reliability make it a major responsibility of the OS.

    63. The design of a complete storage system must balance all the factors just discussed: it must use only as much expensive memory as necessary while providing as much inexpensive, nonvolatile storage as possible. Caches can be installed to improve performance where a large disparity in access time or transfer rate exists between two components.

      This text describes that creating a storage system involves finding a balance among cost, speed, and capacity. Costly, quick memory is utilized sparingly, whereas more extensive, affordable nonvolatile storage retains the majority of data. Caches assist in reducing delays in access times or transfer speeds across memory levels to enhance performance

    64. Electrical. A few examples of such storage systems are flash memory, FRAM, NRAM, and SSD. Electrical storage will be referred to as NVM. If we need to emphasize a particular type of electrical storage device (for example, SSD), we will do so explicitly.

      This passage describes electrical (nonvolatile) storage, including flash memory, FRAM, NRAM, and SSDs, collectively referred to as NVM. These devices store data electronically without moving parts, offering faster access than mechanical storage.

    65. Mechanical. A few examples of such storage systems are HDDs, optical disks, holographic storage, and magnetic tape. If we need to emphasize a particular type of mechanical storage device (for example, magnetic tape), we will do so explicitly.

      This passage introduces mechanical storage devices, which include HDDs, optical disks, holographic storage, and magnetic tape. These devices typically rely on moving parts and are distinguished from semiconductor-based memory by their mechanical operation and generally slower speed.

    66. The top four levels of memory in the figure are constructed using semiconductor memory, which consists of semiconductor-based electronic circuits. NVM devices, at the fourth level, have several variants but in general are faster than hard disks. The most common form of NVM device is flash memory, which is popular in mobile devices such as smartphones and tablets. Increasingly, flash memory is being used for long-term storage on laptops, desktops, and servers as well.

      This passage describes semiconductor-based memory in the top levels of the storage hierarchy. Nonvolatile memory (NVM), particularly flash memory, is faster than hard disks and widely used in mobile devices, with growing adoption in laptops, desktops, and servers for long-term storage.

    67. The wide variety of storage systems can be organized in a hierarchy (Figure 1.6) according to storage capacity and access time. As a general rule, there is a trade-off between size and speed, with smaller and faster memory closer to the CPU. As shown in the figure, in addition to differing in speed and capacity, the various storage systems are either volatile or nonvolatile. Volatile storage, as mentioned earlier, loses its contents when the power to the device is removed, so data must be written to nonvolatile storage for safekeeping.

      This part outlines the storage hierarchy that arranges memory according to speed and storage capacity. The faster, compact memory is claimed to be situated closer to the CPU, while the slower and larger memory is said to be placed further away. Storage can be volatile (loses information when powered off) or nonvolatile (retains information), highlighting the importance of saving essential data to nonvolatile storage

    68. In a larger sense, however, the storage structure that we have described—consisting of registers, main memory, and secondary storage—is only one of many possible storage system designs. Other possible components include cache memory, CD-ROM or blu-ray, magnetic tapes, and so on. Those that are slow enough and large enough that they are used only for special purposes—to store backup copies of material stored on other devices, for example—are called tertiary storage. Each storage system provides the basic functions of storing a datum and holding that datum until it is retrieved at a later time. The main differences among the various storage systems lie in speed, size, and volatility.

      This text expands the perspective on storage architectures beyond just registers, primary memory, and auxiliary storage. It presents tertiary storage (e.g., magnetic tapes, CD-ROMs) utilized for backup or specific uses. All storage systems have the fundamental role of keeping data, yet they vary in speed, capacity, and volatility.

    69. All forms of memory provide an array of bytes. Each byte has its own address. Interaction is achieved through a sequence of load or store instructions to specific memory addresses. The load instruction moves a byte or word from main memory to an internal register within the CPU, whereas the store instruction moves the content of a register to main memory. Aside from explicit loads and stores, the CPU automatically loads instructions from main memory for execution from the location stored in the program counter.

      This passage explains how memory is organized and accessed. Memory is an array of bytes, each with a unique address. The CPU uses load instructions to bring data from memory into registers and store instructions to write data back. Instructions themselves are also automatically loaded from memory based on the program counter for execution.

    70. Computers use other forms of memory as well. For example, the first program to run on computer power-on is a bootstrap program, which then loads the operating system. Since RAM is volatile—loses its content when power is turned off or otherwise lost—we cannot trust it to hold the bootstrap program. Instead, for this and some other purposes, the computer uses electrically erasable programmable read-only memory (EEPROM) and other forms of firmware—storage that is infrequently written to and is nonvolatile. EEPROM can be changed but cannot be changed frequently. In addition, it is low speed, and so it contains mostly static programs and data that aren't frequently used. For example, the iPhone uses EEPROM to store serial numbers and hardware information about the device.

      This text discusses nonvolatile memory such as EEPROM and additional firmware, which preserves information even when the power is turned off. Due to the volatility of RAM, essential programs such as the bootstrap program and static data (e.g., device serial numbers) are kept in EEPROM. Despite being slow and rarely updated, this memory is crucial for system startup and permanent configuration information.

    71. The CPU can load instructions only from memory, so any programs must first be loaded into memory to run. General-purpose computers run most of their programs from rewritable memory, called main memory (also called random-access memory, or RAM). Main memory commonly is implemented in a semiconductor technology called dynamic random-access memory (DRAM).

      This passage explains that the CPU executes programs directly from memory, so programs must be loaded into main memory (RAM) before running. Main memory is typically implemented using DRAM, which allows fast, rewritable access for general-purpose computing.

    72. In summary, interrupts are used throughout modern operating systems to handle asynchronous events (and for other purposes we will discuss throughout the text). Device controllers and hardware faults raise interrupts. To enable the most urgent work to be done first, modern computers use a system of interrupt priorities. Because interrupts are used so heavily for time-sensitive processing, efficient interrupt handling is required for good system performance.

      This text outlines the function of interrupts in contemporary operating systems. Interrupts enable the system to react to asynchronous events, such as device signals and hardware errors. By assigning priority levels, urgent tasks are addressed first, and effective interrupt management is vital for preserving overall system efficiency.

    73. The interrupt mechanism also implements a system of interrupt priority levels. These levels enable the CPU to defer the handling of low-priority interrupts without masking all interrupts and makes it possible for a high-priority interrupt to preempt the execution of a low-priority interrupt.

      This passage describes interrupt priority levels, which allow the CPU to handle more critical interrupts first. Low-priority interrupts can be deferred without blocking all others, while high-priority interrupts can preempt lower-priority ones, ensuring timely responses to urgent events.

    74. Recall that the purpose of a vectored interrupt mechanism is to reduce the need for a single interrupt handler to search all possible sources of interrupts to determine which one needs service. In practice, however, computers have more devices (and, hence, interrupt handlers) than they have address elements in the interrupt vector. A common way to solve this problem is to use interrupt chaining, in which each element in the interrupt vector points to the head of a list of interrupt handlers. When an interrupt is raised, the handlers on the corresponding list are called one by one, until one is found that can service the request. This structure is a compromise between the overhead of a huge interrupt table and the inefficiency of dispatching to a single interrupt handler.

      This passage explains vectored interrupts and how they handle multiple devices efficiently. Since there are often more devices than vector entries, interrupt chaining links multiple handlers to a single vector entry. When an interrupt occurs, handlers are checked in order until the correct one services the request, balancing speed and memory usage.

    75. The basic interrupt mechanism works as follows. The CPU hardware has a wire called the interrupt-request line that the CPU senses after executing every instruction. When the CPU detects that a controller has asserted a signal on the interrupt-request line, it reads the interrupt number and jumps to the interrupt-handler routine by using that interrupt number as an index into the interrupt vector. It then starts execution at the address associated with that index. The interrupt handler saves any state it will be changing during its operation, determines the cause of the interrupt, performs the necessary processing, performs a state restore, and executes a return_from_interrupt instruction to return the CPU to the execution state prior to the interrupt. We say that the device controller raises an interrupt by asserting a signal on the interrupt request line, the CPU catches the interrupt and dispatches it to the interrupt handler, and the handler clears the interrupt by servicing the device. Figure 1.4 summarizes the interrupt-driven I/O cycle.

      This section describes the I/O cycle driven by interrupts. The CPU tracks an interrupt-request line; when a device sends a signal, the CPU refers to the interrupt number to find the matching interrupt handler in the interrupt vector. The handler preserves the existing state, manages the interrupt, reinstates the state, and hands control back to the interrupted program, ensuring smooth functionality.

    76. The interrupt architecture must also save the state information of whatever was interrupted, so that it can restore this information after servicing the interrupt. If the interrupt routine needs to modify the processor state—for instance, by modifying register values—it must explicitly save the current state and then restore that state before returning. After the interrupt is serviced, the saved return address is loaded into the program counter, and the interrupted computation resumes as though the interrupt had not occurred.

      This passage explains that interrupt handling requires saving and restoring CPU state. When an interrupt occurs, the current execution context—like register values and the program counter—is saved so that after the interrupt service routine runs, the CPU can resume the original task seamlessly, as if nothing had been interrupted.

    77. When the CPU is interrupted, it stops what it is doing and immediately transfers execution to a fixed location. The fixed location usually contains the starting address where the service routine for the interrupt is located. The interrupt service routine executes; on completion, the CPU resumes the interrupted computation. A timeline of this operation is shown in Figure 1.3.

      This text showcases the procedure for managing the interrupts. When the interrupt is received by its CPU, it stops its ongoing task, moves to the designated address for executing the interrupt service routine, and then continues with a previous task after the routine is said to complete. This system guarantees prompt reactions to hardware or system occurrences

    78. Hardware may trigger an interrupt at any time by sending a signal to the CPU, usually by way of the system bus. (There may be many buses within a computer system, but the system bus is the main communications path between the major components.) Interrupts are used for many other purposes as well and are a key part of how operating systems and hardware interact.

      This section explains that hardware interrupts are signals sent to the CPU, often via the system bus, to indicate that immediate attention is needed. Interrupts are essential for coordinating actions between the OS and hardware, enabling the system to respond efficiently to events as they occur.

    79. Consider a typical computer operation: a program performing I/O. To start an I/O operation, the device driver loads the appropriate registers in the device controller. The device controller, in turn, examines the contents of these registers to determine what action to take (such as “read a character from the keyboard”). The controller starts the transfer of data from the device to its local buffer. Once the transfer of data is complete, the device controller informs the device driver that it has finished its operation. The device driver then gives control to other parts of the operating system, possibly returning the data or a pointer to the data if the operation was a read. For other operations, the device driver returns status information such as “write completed successfully” or “device busy”. But how does the controller inform the device driver that it has finished its operation? This is accomplished via an interrupt.

      This passage describes the sequence of a typical I/O operation. The device driver sets up the device controller, which carries out the action and uses a buffer for data transfer. Once finished, the controller notifies the driver through an interrupt, allowing the OS to process the data or status information. This illustrates how the OS and hardware communicate efficiently.

    80. In the following subsections, we describe some basics of how such a system operates, focusing on three key aspects of the system. We start with interrupts, which alert the CPU to events that require attention. We then discuss storage structure and I/O structure.

      This passage introduces the three key aspects of system operation: interrupts, which notify the CPU of events needing attention, storage structure, and I/O structure. These fundamentals provide the foundation for understanding how the operating system coordinates hardware and software activities.

    81. Typically, operating systems have a device driver for each device controller. This device driver understands the device controller and provides the rest of the operating system with a uniform interface to the device. The CPU and the device controllers can execute in parallel, competing for memory cycles. To ensure orderly access to the shared memory, a memory controller synchronizes access to the memory.

      This section explains how operating systems manage hardware devices. Each device has a driver that translates between the OS and the device, providing a standard interface. Since the CPU and devices can operate simultaneously and compete for memory, a memory controller coordinates access to prevent conflicts and ensure smooth operation.

    82. Today, however, if we look at operating systems for mobile devices, we see that once again the number of features constituting the operating system is increasing. Mobile operating systems often include not only a core kernel but also middleware—a set of software frameworks that provide additional services to application developers. For example, each of the two most prominent mobile operating systems—Apple's IOS and Google's Android—features a core kernel along with middleware that supports databases, multimedia, and graphics (to name only a few).

      This section highlights how modern mobile operating systems have grown more feature-rich. Beyond the core kernel, they include middleware—software frameworks that provide additional services like databases, multimedia, and graphics—helping developers create sophisticated applications and enhancing the overall functionality of the device.

    83. The matter of what constitutes an operating system became increasingly important as personal computers became more widespread and operating systems grew increasingly sophisticated. In 1998, the United States Department of Justice filed suit against Microsoft, in essence claiming that Microsoft included too much functionality in its operating systems and thus prevented application vendors from competing. (For example, a web browser was an integral part of Microsoft's operating systems.) As a result, Microsoft was found guilty of using its operating-system monopoly to limit competition.

      This passage illustrates about how the scope of the operating system can have the legal and the economic implications. As OSs became more sophisticated, Microsoft was sued for bundling extra functionality, like a web browser, which limited competition. It shows that what is included in an OS can affect both market dynamics and regulatory scrutiny.

    84. In addition, we have no universally accepted definition of what is part of the operating system. A simple viewpoint is that it includes everything a vendor ships when you order “the operating system.” The features included, however, vary greatly across systems. Some systems take up less than a megabyte of space and lack even a full-screen editor, whereas others require gigabytes of space and are based entirely on graphical windowing systems. A more common definition, and the one that we usually follow, is that the operating system is the one program running at all times on the computer—usually called the kernel. Along with the kernel, there are two other types of programs: system programs, which are associated with the operating system but are not necessarily part of the kernel, and application programs, which include all programs not associated with the operation of the system.

      This section highlights that the boundaries of an operating system are not universally agreed upon. While some view it as everything that is being included when purchased, a more practical definition focuses on the kernel—the core program always running. Surrounding the kernel are system programs (supporting the OS) and application programs (serving users), showing that the OS is both central and part of a larger software ecosystem.

    85. How, then, can we define what an operating system is? In general, we have no completely adequate definition of an operating system. Operating systems exist because they offer a reasonable way to solve the problem of creating a usable computing system. The fundamental goal of computer systems is to execute programs and to make solving user problems easier. Computer hardware is constructed toward this goal. Since bare hardware alone is not particularly easy to use, application programs are developed. These programs require certain common operations, such as those controlling the I/O devices. The common functions of controlling and allocating resources are then brought together into one piece of software: the operating system.

      This passage explains that while there’s no single perfect definition of an operating system, it exists to make computing systems usable and efficient. By combining common functions like resource allocation and I/O control into one software layer, the OS simplifies program execution and helps users solve problems effectively.

    86. To explain this diversity, we can turn to the history of computers. Although computers have a relatively short history, they have evolved rapidly. Computing started as an experiment to determine what could be done and quickly moved to fixed-purpose systems for military uses, such as code breaking and trajectory plotting, and governmental uses, such as census calculation. Those early computers evolved into general-purpose, multifunction mainframes, and that's when operating systems were born. In the 1960s, Moore's Law predicted that the number of transistors on an integrated circuit would double every 18 months, and that prediction has held true. Computers gained in functionality and shrank in size, leading to a vast number of uses and a vast number and variety of operating systems. (See Appendix A for more details on the history of operating systems.)

      This section traces the evolution of computers to explain the diversity of operating systems. Early fixed-purpose machines for military and government tasks eventually gave way to general-purpose mainframes, prompting the development of operating systems. With rapid advancements in hardware—predicted by Moore’s Law—computers became more powerful and compact, enabling a wide variety of applications and a corresponding variety of OS designs.

    87. By now, you can probably see that the term operating system covers many roles and functions. That is the case, at least in part, because of the myriad designs and uses of computers. Computers are present within toasters, cars, ships, spacecraft, homes, and businesses. They are the basis for game machines, cable TV tuners, and industrial control systems.

      This passage emphasizes the versatility of operating systems, which perform many roles depending on the type of computer and its purpose. Because computers are embedded in a wide range of devices—from household appliances to spacecraft—the OS must be designed to meet diverse needs and environments.

    88. A slightly different view of an operating system emphasizes the need to control the various I/O devices and user programs. An operating system is a control program. A control program manages the execution of user programs to prevent errors and improper use of the computer. It is especially concerned with the operation and control of I/O devices.

      This section presents the operating system as a control program. Beyond just allocating resources, it ensures programs run safely and correctly, preventing misuse or conflicts. A major focus here is managing I/O devices, since they are often shared and prone to errors if not properly controlled.

    89. From the computer's point of view, the operating system is the program most intimately involved with the hardware. In this context, we can view an operating system as a resource allocator. A computer system has many resources that may be required to solve a problem: CPU time, memory space, storage space, I/O devices, and so on. The operating system acts as the manager of these resources. Facing numerous and possibly conflicting requests for resources, the operating system must decide how to allocate them to specific programs and users so that it can operate the computer system efficiently and fairly.

      This passage displys how the operating system as the hardware’s closest partner, serving as a resource allocator. Since programs and the users do constantly compete for the limited resources like the CPU time, memory, storage, and the I/O devices, the OS must make the fair and the efficient decisions about distribution. This role ensures smooth functioning of the entire computer system.

    90. Increasingly, many users interact with mobile devices such as smartphones and tablets—devices that are replacing desktop and laptop computer systems for some users. These devices are typically connected to networks through cellular or other wireless technologies. The user interface for mobile computers generally features a touch screen, where the user interacts with the system by pressing and swiping fingers across the screen rather than using a physical keyboard and mouse. Many mobile devices also allow users to interact through a voice recognition interface, such as Apple's Siri.

      This section highlights the importance of how the mobile devices have changed the way the users interact with the computers. Instead of relying on the keyboards and the mice, the users primarily use the touch screens and sometimes also the voice commands. Because these devices are always network-connected, the operating system must be optimized for the mobility, connectivity, and the natural interaction methods.

    91. The user's view of the computer varies according to the interface being used. Many computer users sit with a laptop or in front of a PC consisting of a monitor, keyboard, and mouse. Such a system is designed for one user to monopolize its resources. The goal is to maximize the work (or play) that the user is performing. In this case, the operating system is designed mostly for ease of use, with some attention paid to performance and security and none paid to resource utilization—how various hardware and software resources are shared.

      This passage points out that a user’s experience with a computer depends on the type of interface. For the personal systems like the laptops and the PCs, the operating system focuses on making the system very easy to use and also responsive for the single person. In this setup, the efficiency and the convenience take the priority over the resource sharing, since the machine is not meant to be divided among the multiple users.

    92. The hardware—the central processing unit (CPU), the memory, and the input/output (I/O) devices—provides the basic computing resources for the system. The application programs—such as word processors, spreadsheets, compilers, and web browsers—define the ways in which these resources are used to solve users' computing problems. The operating system controls the hardware and coordinates its use among the various application programs for the various users.

      This section explains the relationship between hardware, applications, and the operating system. Hardware provides the raw resources, applications give users practical tools, and the operating system acts as the manager that controls and coordinates how those resources are shared among programs and users.

    93. We begin our discussion by looking at the operating system's role in the overall computer system. A computer system can be divided roughly into four components: the hardware, the operating system, the application programs, and a user (Figure 1.1).

      This part introduces the layered view of a computer system, showing how the hardware, operating system, application programs, and user interact. The operating system sits in the middle, acting as the bridge between raw hardware and the applications that users depend on.

    94. Because an operating system is large and complex, it must be created piece by piece. Each of these pieces should be a well-delineated portion of the system, with carefully defined inputs, outputs, and functions. In this chapter, we provide a general overview of the major components of a contemporary computer system as well as the functions provided by the operating system. Additionally, we cover several topics to help set the stage for the remainder of the text: data structures used in operating systems, computing environments, and open-source and free operating systems.

      This passage highlights that the modular design of the operating systems. Breaking the OS into the smaller, well-defined components makes it very easy to manage the complexity, assign the clear responsibilities, and also maintain the system. The chapter overview also signals that beyond just the OS functions, students will learn about foundational concepts like data structures, different computing environments, and the role of open-source systems, which set the groundwork for deeper exploration later.

    95. In order to explore the role of an operating system in a modern computing environment, it is important first to understand the organization and architecture of computer hardware. This includes the CPU, memory, and I/O devices, as well as storage. A fundamental responsibility of an operating system is to allocate these resources to programs.

      This section highlights the importance that the operating system acts like the manager for the core hardware components—CPU, memory, the I/O devices, and the storage. By allocating these resources to the different programs, the OS will ensure the fairness, efficiency, and the stability in the modern computing environment. It reminds us that without this resource management,the multiple programs running at the same time would constantly conflict with each other.

    96. This output tells us the timestamp when the I/O operation occurred, whether the I/O was a Read or Write operation, and how many bytes were involved in the I/O. The final column reflects the duration (expressed as latency or LAT) in milliseconds of the I/O.

      This explanation makes it clear how BCC tools like disksnoop provide detailed insights into disk performance. I find it interesting that latency is included, as it directly shows performance bottlenecks. I wonder how this information could be used to optimize system performance.

    97. The specifics of writing custom BCC tools are beyond the scope of this text, but the BCC package (which is installed on the Linux virtual machine we provide) provides a number of existing tools that monitor several areas of activity in a running Linux kernel. As an example, the BCC disksnoop tool traces disk I/O activity. Entering the command

      It’s helpful that BCC comes with prebuilt tools like disksnoop, so I can monitor disk I/O without having to write custom eBPF programs. I wonder what other areas of the kernel can be traced with existing BCC tools and how much detail they provide.

    98. Although eBPF provides a rich set of features for tracing within the Linux kernel, it traditionally has been very difficult to develop programs using its C interface. BCC was developed to make it easier to write tools using eBPF by providing a front-end interface in Python. A BCC tool is written in Python and it embeds C code that interfaces with the eBPF instrumentation, which in turn interfaces with the kernel. The BCC tool also compiles the C program into eBPF instructions and inserts it into the kernel using either probes or tracepoints, two techniques that allow tracing events in the Linux kernel.

      I like how the BCC simplifies using the eBPF by letting the developers write their tools in the Python while embedding C for the kernel-level tracing. It’s interesting that the Python acts as a front-end, compiling and also inserting the C code as the eBPF instructions. I’m curious how the probes and the tracepoints differ in practice when monitoring the kernel events.

    99. BCC (BPF Compiler Collection) is a rich toolkit that provides tracing features for Linux systems. BCC is a front-end interface to the eBPF (extended Berkeley Packet Filter) tool. The BPF technology was developed in the early 1990s for filtering traffic across a computer network. The “extended” BPF (eBPF) added various features to BPF. eBPF programs are written in a subset of C and are compiled into eBPF instructions, which can be dynamically inserted into a running Linux system. The eBPF instructions can be used to capture specific events (such as a certain system call being invoked) or to monitor system performance (such as the time required to perform disk I/O). To ensure that eBPF instructions are well behaved, they are passed through a verifier before being inserted into the running Linux kernel. The verifier checks to make sure that the instructions do not affect system performance or security.

      I find it interesting that the BCC uses an eBPF to dynamically insert the instructions into the running Linux system for tracing and the performance monitoring. The verifier seems like a crucial safeguard, ensuring that these types of instructions don’t compromise the security or the system performance. I wonder how complex it is to write the eBPF programs in practice, given the limited C subset and the need to pass the verification.This keeps it reflective, humanized, and shows the curiosity about the technical aspects.

    100. Debugging the interactions between user-level and kernel code is nearly impossible without a toolset that understands both sets of code and can instrument their interactions. For that toolset to be truly useful, it must be able to debug any area of a system, including areas that were not written with debugging in mind, and do so without affecting system reliability. This toolset must also have a minimal performance impact—ideally it should have no impact when not in use and a proportional impact during use. The BCC toolkit meets these requirements and provides a dynamic, secure, low-impact debugging environment.

      Debugging seems incredibly complex when both user-level and kernel code interact. It's very impressive that the BCC toolkit can dynamically monitor and debug the system with minimal performance impact. I’m curious about how it will ensure the security while accessing the parts of the system that weren’t designed for debugging.

    101. Whereas counter-based tools simply inquire on the current value of certain statistics that are maintained by the kernel, tracing tools collect data for a specific event—such as the steps involved in a system-call invocation.

      It’s interesting how tracing tools differ from counters. While counters give a snapshot of ongoing statistics, tracing actually follows specific events as they happen. I wonder how much performance overhead tracing adds compared to just reading counters.

    102. Windows systems provide the Windows Task Manager, a tool that includes information for current applications as well as processes, CPU and memory usage, and networking statistics. A screen shot of the task manager in Windows 10 appears in Figure 2.19.

      I use the Task Manager all the time to check which of the programs are using the most resources. It’s clear to see how the Windows provides both the process-level and the overall system statistics in one place. I’m curious how the Task Manager gathers this type of data behind the scenes—does it use counters like the Linux tools?

    103. Operating systems keep track of system activity through a series of counters, such as the number of system calls made or the number of operations performed to a network device or disk. The following are examples of Linux tools that use counters:

      It’s interesting to see how the operating systems use the simple counters to monitor the activity. I didn’t realize that just counting things like the system calls or the disk operations could provide such valuable insight into system performance. I wonder how accurate this method is compared to other monitoring techniques.

    104. We mentioned earlier that performance tuning seeks to improve performance by removing processing bottlenecks. To identify bottlenecks, we must be able to monitor system performance. Thus, the operating system must have some means of computing and displaying measures of system behavior. Tools may be characterized as providing either per-process or system-wide observations. To make these observations, tools may use one of two approaches—counters or tracing. We explore each of these in the following sections.

      It makes sense that before you can be able to fix the performance issues, you need to measure them. I like how much the text distinguishes between the monitoring of the individual processes versus the whole system—this seems key to spotting exactly where the bottleneck is.

    105. Operating-system debugging and process debugging frequently use different tools and techniques due to the very different nature of these two tasks. Consider that a kernel failure in the file-system code would make it risky for the kernel to try to save its state to a file on the file system before rebooting. A common technique is to save the kernel's memory state to a section of disk set aside for this purpose that contains no file system. If the kernel detects an unrecoverable error, it writes the entire contents of memory, or at least the kernel-owned parts of the system memory, to the disk area. When the system reboots, a process runs to gather the data from that area and write it to a crash dump file within a file system for analysis. Obviously, such strategies would be unnecessary for debugging ordinary user-level processes.

      It’s interesting how the kernel debugging has to plan for the fact that the file system itself might be broken. Writing the memory state to the dedicated disk area outside of the file system is clever—it ensures that crash data isn’t lost even if the system fails completely.

    106. Debugging user-level process code is a challenge. Operating-system kernel debugging is even more complex because of the size and complexity of the kernel, its control of the hardware, and the lack of user-level debugging tools. A failure in the kernel is called a crash. When a crash occurs, error information is saved to a log file, and the memory state is saved to a crash dump.

      It’s overwhelming to see how much harder it is to debug the kernel as compared to the regular programs. The idea of a ‘crash dump’ makes sense—capturing the kernel’s memory state seems to be essential since normal user-level tools can’t reach it.

    107. If a process fails, most operating systems write the error information to a log file to alert system administrators or users that the problem occurred. The operating system can also take a core dump—a capture of the memory of the process—and store it in a file for later analysis. (Memory was referred to as the “core” in the early days of computing.) Running programs and core dumps can be probed by a debugger, which allows a programmer to explore the code and memory of a process at the time of failure.

      I like how the text explains the core dumps—it’s interesting that the ‘core’ comes from the older terminology for the memory. I also find it useful such that the modern OS is able to capture the process’s memory when it fails, so that the developers can be able to inspect exactly what had gone wrong.

    108. We have mentioned debugging from time to time in this chapter. Here, we take a closer look. Broadly, debugging is the activity of finding and fixing errors in a system, both in hardware and in software. Performance problems are considered bugs, so debugging can also include performance tuning, which seeks to improve performance by removing processing bottlenecks. In this section, we explore debugging process and kernel errors and performance problems. Hardware debugging is outside the scope of this text.

      I find it interesting that debugging isn’t just about fixing crashes or wrong outputs—it also includes improving performance. I didn’t realize that the performance issues are the considered bugs which need debugging at the system or the kernel level.

    109. Finally, boot loaders for most operating systems—including Windows, Linux, and macOS, as well as both iOS and Android—provide booting into recovery mode or single-user mode for diagnosing hardware issues, fixing corrupt file systems, and even reinstalling the operating system. In addition to hardware failures, computer systems can suffer from software errors and poor operating-system performance, which we consider in the following section.

      It’s useful that modern boot loaders offer recovery or single-user modes. This makes troubleshooting hardware or software problems much easier, and it’s interesting that this feature is standard across Windows, Linux, macOS, iOS, and Android.

    110. To save space as well as decrease boot time, the Linux kernel image is a compressed file that is extracted after it is loaded into memory. During the boot process, the boot loader typically creates a temporary RAM file system, known as initramfs. This file system contains necessary drivers and kernel modules that must be installed to support the real root file system (which is not in main memory). Once the kernel has started and the necessary drivers are installed, the kernel switches the root file system from the temporary RAM location to the appropriate root file system location. Finally, Linux creates the systemd process, the initial process in the system, and then starts other services (for example, a web server and/or database). Ultimately, the system will present the user with a login prompt. In Section 11.5.2, we describe the boot process for Windows.

      It’s interesting how Linux uses a temporary RAM file system (initramfs) to get everything started before switching to the real root file system. I wonder how this compares in speed and reliability to the Windows boot process mentioned later.

    111. Many recent computer systems have replaced the BIOS-based boot process with UEFI (Unified Extensible Firmware Interface). UEFI has several advantages over BIOS, including better support for 64-bit systems and larger disks. Perhaps the greatest advantage is that UEFI is a single, complete boot manager and therefore is faster than the multistage BIOS boot process.

      It’s surprising how the UEFI replaces the old BIOS process. I’m curious—how much faster is UEFI in practice, and does it make a noticeable difference when starting up modern computers?

    112. Some computer systems use a multistage boot process: When the computer is first powered on, a small boot loader located in nonvolatile firmware known as BIOS is run. This initial boot loader usually does nothing more than load a second boot loader, which is located at a fixed disk location called the boot block. The program stored in the boot block may be sophisticated enough to load the entire operating system into memory and begin its execution. More typically, it is simple code (as it must fit in a single disk block) and knows only the address on disk and the length of the remainder of the bootstrap program.

      It’s interesting how the boot process is broken into stages. I wonder why the first boot loader has to be so tiny—just enough to load the next stage. Is it mainly because of space constraints in the BIOS firmware?

    113. At a slightly less tailored level, the system description can lead to the selection of precompiled object modules from an existing library. These modules are linked together to form the generated operating system. This process allows the library to contain the device drivers for all supported I/O devices, but only those needed are selected and linked into the operating system. Because the system is not recompiled, system generation is faster, but the resulting system may be overly general and may not support different hardware configurations.

      This explains how precompiled modules help build an OS quickly without full recompilation. It makes sense for speed, but I’m curious—how often does this ‘overly general’ approach cause compatibility problems with less common hardware?

    114. Configuring the system involves specifying which features will be included, and this varies by operating system. Typically, parameters describing how the system is configured is stored in a configuration file of some type, and once this file is created, it can be used in several ways.

      So the OS can be suited by adjusting the configuration axxording to the files—this is like setting up the preferences before using the program. I wonder how much of the flexibility the different OS really gives in terms of which of the features can be included or excluded.

    115. Most commonly, a computer system, when purchased, has an operating system already installed. For example, you may purchase a new laptop with Windows or macOS preinstalled. But suppose you wish to replace the preinstalled operating system or add additional operating systems. Or suppose you purchase a computer without an operating system. In these latter situations, you have a few options for placing the appropriate operating system on the computer and configuring it for use.

      This makes me think about how operating systems are tied to hardware out of the box. It’s interesting that we have flexibility to replace or add OSes, but it also raises questions about compatibility and setup—like dual-booting or clean installations.

    116. It is possible to design, code, and implement an operating system specifically for one specific machine configuration. More commonly, however, operating systems are designed to run on any of a class of machines with a variety of peripheral configurations.

      This highlights the trade-off in the OS design: you can make a system that’s perfectly optimized for any one machine, but most of the OS developers aim for the flexibility so that the system works across many of the devices. I find it interesting to see how this will affect the performance versus the compatibility.

    117. Because Android can run on an almost unlimited number of hardware devices, Google has chosen to abstract the physical hardware through the hardware abstraction layer, or HAL. By abstracting all hardware, such as the camera, GPS chip, and other sensors, the HAL provides applications with a consistent view independent of specific hardware. This feature, of course, allows developers to write programs that are portable across different hardware platforms.

      The Hardware Abstraction Layer (HAL) is considered pretty smart— as it hides the differences between the devices so the developers won't have to worry about the specifics of every phone or the tablet. This explains why the same Android app can run on so many different devices without any modification.

    118. Software designers for Android devices develop applications in the Java language, but they do not generally use the standard Java API. Google has designed a separate Android API for Java development. Java applications are compiled into a form that can execute on the Android RunTime ART, a virtual machine designed for Android and optimized for mobile devices with limited memory and CPU processing capabilities. Java programs are first compiled to a Java bytecode .class file and then translated into an executable .dex file. Whereas many Java virtual machines perform just-in-time (JIT) compilation to improve application efficiency, ART performs ahead-of-time (AOT) compilation. Here, .dex files are compiled into native machine code when they are installed on a device, from which they can execute on the ART. AOT compilation allows more efficient application execution as well as reduced power consumption, features that are crucial for mobile systems.

      It’s interesting that the Android doesn’t use any of the standard Java API but instead has its own. The ahead-of-time (AOT) compilation in ART seems really clever—it makes apps run faster and saves battery life, which is super important for mobile devices with limited resources.

    119. The Android operating system was designed by the Open Handset Alliance (led primarily by Google) and was developed for Android smartphones and tablet computers. Whereas iOS is designed to run on Apple mobile devices and is close-sourced, Android runs on a variety of mobile platforms and is open-sourced, partly explaining its rapid rise in popularity. The structure of Android appears in Figure 2.18.

      Android’s open-source nature and the support for the multiple mobile platforms is used to help explain why it became so popular very quickly, especially when compared to the closed iOS ecosystem which only runs on the Apple devices.

    120. Apple has released the Darwin operating system as open source. As a result, various projects have added extra functionality to Darwin, such as the X-11 windowing system and support for additional file systems. Unlike Darwin, however, the Cocoa interface, as well as other proprietary Apple frameworks available for developing macOS applications, are closed.

      Apple is said to have released the Darwin operating system such as an open source. As a result, various projects have added the extra functionality to the Darwin, such as the X-11 windowing system and the support for the additional file systems. Unlike the Darwin, however, the Cocoa interface, as well as the other proprietary Apple frameworks are said to be available for the developing macOS applications, are closed.

    121. In Section 2.8.3, we described how the overhead of message passing between different services running in user space compromises the performance of microkernels. To address such performance problems, Darwin combines Mach, BSD, the I/O kit, and any kernel extensions into a single address space. Thus, Mach is not a pure microkernel in the sense that various subsystems run in user space. Message passing within Mach still does occur, but no copying is necessary, as the services have access to the same address space.

      Darwin improves the microkernel performance by combining the mac, BSD, and the I/O Kit, and the kernel extensions into the single address space. This design is used for reducing the overhead of message passing between the services because they share the memory, so no copying is needed—showing the practical way to balance the microkernel modularity with its efficiency.

    122. Beneath the system-call interface, Mach provides fundamental operating-system services, including memory management, CPU scheduling, and interprocess communication (IPC) facilities such as message passing and remote procedure calls (RPCs). Much of the functionality provided by Mach is available through kernel abstractions, which include tasks (a Mach process), threads, memory objects, and ports (used for IPC). As an example, an application may create a new process using the BSD POSIX fork() system call. Mach will, in turn, use a task kernel abstraction to represent the process in the kernel.

      Mac is used for handling the core OS tasks like the memory management, CPU scheduling, and the communication between processes using the abstractions such as the tasks, threads, memory objects, and the ports. For instance, when the program calls the POSIX fork() to create the new process, mac represents that process internally as a task—showing how the kernel translates into a high-level calls into its own mechanisms.

    123. Whereas most operating systems provide a single system-call interface to the kernel—such as through the standard C library on UNIX and Linux systems—Darwin provides two system-call interfaces: Mach system calls (known as traps) and BSD system calls (which provide POSIX functionality). The interface to these system calls is a rich set of libraries that includes not only the standard C library but also libraries that provide networking, security, and progamming language support (to name just a few).

      Darwin is very unique because it is said to offer two separate system-call interfaces: Mach calls for low-level kernel interactions and BSD calls for POSIX functionality. This dual interface, combined with extensive libraries for networking, security, and programming, gives developers a lot of flexibility compared to typical single-interface systems.

    124. The iOS operating system is generally much more restricted to developers than macOS and may even be closed to developers. For example, iOS restricts access to POSIX and BSD APIs on iOS, whereas they are openly available to developers on macOS.

      iOS is much more locked down as compared to the macOS. Developers have very limited access to the low-level APIs like the POSIX and the BSD, which are freely available on the macOS. This highlights how the Apple prioritizes security and the control on the mobile devices.

    125. Because macOS is intended for desktop and laptop computer systems, it is compiled to run on Intel architectures. iOS is designed for mobile devices and thus is compiled for ARM-based architectures. Similarly, the iOS kernel has been modified somewhat to address specific features and needs of mobile systems, such as power management and aggressive memory management. Additionally, iOS has more stringent security settings than macOS.

      This section defines how the same underlying OS (Darwin) is adapted for a different hardware. macOS targets the Intel desktops/laptops, while the iOS is optimized for the ARM mobile devices with the extra features like an advanced power management and the stricter security controls.

    126. Kernel environment. This environment, also known as Darwin, includes the Mach microkernel and the BSD UNIX kernel. We will elaborate on Darwin shortly.

      This highlights the foundation of the macOS and the iOS. Darwin, with its Mach microkernel and the BSD UNIX components, forms the core of the operating system, handling the essential functions like the process management, memory, and the system calls.

    127. Core frameworks. This layer defines frameworks that support graphics and media including, Quicktime and OpenGL.

      This layer shows just how the operating systems are said to provide the built-in support for the multimedia and the graphics. QuickTime and the OpenGL make it easier for the developers to create the media-rich applications without having to handle the low-level graphics or the video processing themselves.

    128. Application frameworks layer. This layer includes the Cocoa and Cocoa Touch frameworks, which provide an API for the Objective-C and Swift programming languages. The primary difference between Cocoa and Cocoa Touch is that the former is used for developing macOS applications, and the latter by iOS to provide support for hardware features unique to mobile devices, such as touch screens.

      It’s surprising how the Cocoa and Cocoa Touch serve the similar purposes but are said to be tailored for the different devices. Cocoa Touch supporting the touch-specific hardware really highlights how the APIs need to adapt to the features of the device, not just the operating system.

    129. User experience layer. This layer defines the software interface that allows users to interact with the computing devices. macOS uses the Aqua user interface, which is designed for a mouse or trackpad, whereas iOS uses the Springboard user interface, which is designed for touch devices.

      It’s fascinating to see how the user experience layer really suits the interface to the type of device. I hadn’t realized that macOS and iOS use completely different interfaces (Aqua vs. Springboard) even though they share underlying system components. It makes me think about how much design affects usability on different devices.

    130. In practice, very few operating systems adopt a single, strictly defined structure. Instead, they combine different structures, resulting in hybrid systems that address performance, security, and usability issues. For example, Linux is monolithic, because having the operating system in a single address space provides very efficient performance. However, it also modular, so that new functionality can be dynamically added to the kernel. Windows is largely monolithic as well (again primarily for performance reasons), but it retains some behavior typical of microkernel systems, including providing support for separate subsystems (known as operating-system personalities) that run as user-mode processes. Windows systems also provide support for dynamically loadable kernel modules. We provide case studies of Linux and Windows 10 in Chapter 20 and Chapter 21, respectively. In the remainder of this section, we explore the structure of three hybrid systems: the Apple macOS operating system and the two most prominent mobile operating systems—iOS and Android.

      It’s interesting to see how most of the modern operating systems are really hybrids rather than strictly monolithic or microkernel. I hadn’t realized how theLinux combines the monolithic efficiency with the modular flexibility, and that the Windows mixes the monolithic performance with some microkernel-like features. I wonder how these hybrid designs are used to affect the speed and the stability of the OS in the real-world use.

    131. The idea of the design is for the kernel to provide core services, while other services are implemented dynamically, as the kernel is running. Linking services dynamically is preferable to adding new features directly to the kernel, which would require recompiling the kernel every time a change was made. Thus, for example, we might build CPU scheduling and memory management algorithms directly into the kernel and then add support for different file systems by way of loadable modules.

      I like how this paragraph explains about the benefit of dynamic linking. It makes sense that the kernel handles core functions like CPU scheduling and memory management, while less essential features—like different file systems—can be added on the fly. It makes me curious: how does the OS make sure a newly loaded module doesn’t interfere with the core kernel services?

    132. Perhaps the best current methodology for operating-system design involves using loadable kernel modules (LKMs). Here, the kernel has a set of core components and can link in additional services via modules, either at boot time or during run time. This type of design is common in modern implementations of UNIX, such as Linux, macOS, and Solaris, as well as Windows.

      This part emphasizes how the modern day operating systems have evolved to be more flexible. I find it interesting such that the loadable kernel modules let the OS add or remove the services without rebuilding the whole kernel. It makes me wonder: how does the system ensure the stability when the new modules are loaded at the run time?”

    133. Unfortunately, the performance of microkernels can suffer due to increased system-function overhead. When two user-level services must communicate, messages must be copied between the services, which reside in separate address spaces. In addition, the operating system may have to switch from one process to the next to exchange the messages. The overhead involved in copying messages and switching between processes has been the largest impediment to the growth of microkernel-based operating systems. Consider the history of Windows NT: The first release had a layered microkernel organization. This version's performance was low compared with that of Windows 95. Windows NT 4.0 partially corrected the performance problem by moving layers from user space to kernel space and integrating them more closely. By the time Windows XP was designed, Windows architecture had become more monolithic than microkernel. Section 2.8.5.1 will describe how macOS addresses the performance issues of the Mach microkernel.

      Microkernels often face performance challenges because communication between user-level services requires message copying and process switching. This overhead can be said to slow down the system, as seen in the early versions of the Windows NT, which can be used as a layered microkernel architecture. Over time, performance concerns led Windows NT and XP to adopt a more monolithic approach, integrating layers into the kernel. Solutions like those in macOS (discussed later) aim to address these efficiency issues while retaining microkernel benefits.

    134. Another example is QNX, a real-time operating system for embedded systems. The QNX Neutrino microkernel provides services for message passing and process scheduling. It also handles low-level network communication and hardware interrupts. All other services in QNX are provided by standard processes that run outside the kernel in user mode.

      QNX demonstrates the microkernel design in the context of the real-time and embedded systems. Its Neutrino microkernel is said to manage the essential functions like the message passing, process scheduling, network communication, and the hardware interrupts, while all the other services run as a separate user-mode processes. This separation is said to enhance the reliability and it also simplifies the system maintenance and its updates.

    135. Perhaps the best-known illustration of a microkernel operating system is Darwin, the kernel component of the macOS and iOS operating systems. Darwin, in fact, consists of two kernels, one of which is the Mach microkernel. We will cover the macOS and iOS systems in further detail in Section 2.8.5.1.

      Darwin serves as an important example of a microkernel-based on the operating system. It forms the kernel foundation for macOS and iOS, incorporating the Mach microkernel as one of its core components. This highlights how modern operating systems can use microkernel principles while supporting complex, feature-rich environments.

    136. One benefit of the microkernel approach is that it makes extending the operating system easier. All new services are added to user space and consequently do not require modification of the kernel. When the kernel does have to be modified, the changes tend to be fewer, because the microkernel is a smaller kernel. The resulting operating system is easier to port from one hardware design to another. The microkernel also provides more security and reliability, since most services are running as user—rather than kernel—processes. If a service fails, the rest of the operating system remains untouched.

      The microkernel design is said to offer the several advantages: it simplifies the extending the operating system, since the new services can be added in the user space without the changing of the kernel. The smaller the kernel is, the easier it is to modify and port across the hardware platforms. Additionally, because most of the services run in the user space, the system gains the improved security and the reliability—if a service crashes, it does not affect the rest of the operating system.

    137. The main function of the microkernel is to provide communication between the client program and the various services that are also running in user space. Communication is provided through message passing, which was described in Section 2.3.3.5. For example, if the client program wishes to access a file, it must interact with the file server. The client program and service never interact directly. Rather, they communicate indirectly by exchanging messages with the microkernel.

      In a microkernel system, the kernel’s primary role is to act as a communication hub between user-space programs and services. Instead of direct interaction, clients and services exchange messages via the microkernel. For instance, a program requesting file access communicates with the file server through the kernel, ensuring controlled, indirect interaction and maintaining the modular structure of the system.

    138. We have already seen that the original UNIX system had a monolithic structure. As UNIX expanded, the kernel became large and difficult to manage. In the mid-1980s, researchers at Carnegie Mellon University developed an operating system called Mach that modularized the kernel using the microkernel approach. This method structures the operating system by removing all nonessential components from the kernel and implementing them as user-level programs that reside in separate address spaces. The result is a smaller kernel. There is little consensus regarding which services should remain in the kernel and which should be implemented in user space. Typically, however, microkernels provide minimal process and memory management, in addition to a communication facility. Figure 2.15 illustrates the architecture of a typical microkernel.

      The microkernel approach has emerged for addressing the complexity of the large monolithic kernels, like the UNIX. By moving the nonessential services out of the kernel into the user-space programs, the kernel becomes smaller and very easier to manage. Microkernels usually are said to handle only the core tasks—such as the process and the memory management and the interprocess communication—while the other services are said to run separately, improving the modularity and the maintainability.

    139. Layered systems have been successfully used in computer networks (such as TCP/IP) and web applications. Nevertheless, relatively few operating systems use a pure layered approach. One reason involves the challenges of appropriately defining the functionality of each layer. In addition, the overall performance of such systems is poor due to the overhead of requiring a user program to traverse through multiple layers to obtain an operating-system service. Some layering is common in contemporary operating systems, however. Generally, these systems have fewer layers with more functionality, providing most of the advantages of modularized code while avoiding the problems of layer definition and interaction.

      While the layered approach is said to offer the clarity and the modularity, it is rarely used in its pure form in operating systems. Defining precise responsibilities for each layer is difficult, and performance can suffer because service requests must pass through multiple layers. Modern systems often use a compromise: fewer, broader layers that retain modular benefits while reducing overhead and complexity.

    140. Each layer is implemented only with operations provided by lower-level layers. A layer does not need to know how these operations are implemented; it needs to know only what these operations do. Hence, each layer hides the existence of certain data structures, operations, and hardware from higher-level layers.

      Each layer acts like a “black box,” using services from lower layers without needing to know their internal workings. This abstraction hides implementation details, so higher layers focus only on what operations do, not how they are carried out, which simplifies design and enhances modularity.

    141. The main advantage of the layered approach is simplicity of construction and debugging. The layers are selected so that each uses functions (operations) and services of only lower-level layers. This approach simplifies debugging and system verification. The first layer can be debugged without any concern for the rest of the system, because, by definition, it uses only the basic hardware (which is assumed correct) to implement its functions. Once the first layer is debugged, its correct functioning can be assumed while the second layer is debugged, and so on. If an error is found during the debugging of a particular layer, the error must be on that layer, because the layers below it are already debugged. Thus, the design and implementation of the system are simplified.

      The layered approach makes the building and the debugging an operating system much easier. Every layer depends solely on the ones beneath it, allowing the developers to test any one layer individually. After a lower layer is verified for the functioning properly, any errors that are detected in the higher layers must be traceable to it, simplifying that the process of identifying and resolving issues while enhancing the overall reliability of the system

    142. An operating-system layer is an implementation of an abstract object made up of data and the operations that can manipulate those data. A typical operating-system layer—say, layer M—consists of data structures and a set of functions that can be invoked by higher-level layers. Layer M, in turn, can invoke operations on lower-level layers.

      An operating-system layer functions as a fundamental component, integrating the data with the operations that manipulate that data. Each layer (such as layer M) offers the services to the layers situated above it while relying on the layers beneath it for the foundational operations. This structured method helps in the system organization, enhancing its comprehensibility, maintainability, and the adaptability.

    143. The monolithic approach is often known as a tightly coupled system because changes to one part of the system can have wide-ranging effects on other parts. Alternatively, we could design a loosely coupled system. Such a system is divided into separate, smaller components that have specific and limited functionality. All these components together comprise the kernel. The advantage of this modular approach is that changes in one component affect only that component, and no others, allowing system implementers more freedom in creating and changing the inner workings of the system.

      Monolithic kernels are said to be challenging to implement and modify due to their very large, unified structure. However, they offer high performance because system calls involve minimal overhead and internal kernel communication is very fast. This speed advantage is why monolithic designs remain common in operating systems like UNIX, Linux, and Windows despite their complexity.

    144. Despite the apparent simplicity of monolithic kernels, they are difficult to implement and extend. Monolithic kernels do have a distinct performance advantage, however: there is very little overhead in the system-call interface, and communication within the kernel is fast. Therefore, despite the drawbacks of monolithic kernels, their speed and efficiency explains why we still see evidence of this structure in the UNIX, Linux, and Windows operating systems.

      Monolithic kernels are said to be challenging to implement and modify due to their very large, unified structure. However, they offer high performance because system calls involve minimal overhead and internal kernel communication is very fast. This speed advantage is why monolithic designs remain common in operating systems like UNIX, Linux, and Windows despite their complexity.

    145. The Linux operating system is based on UNIX and is structured similarly, as shown in Figure 2.13. Applications typically use the glibc standard C library when communicating with the system call interface to the kernel. The Linux kernel is monolithic in that it runs entirely in kernel mode in a single address space, but as we shall see in Section 2.8.4, it does have a modular design that allows the kernel to be modified during run time.

      Linux, like the UNIX, follows a largely monolithic structure but this includes the modular features. The kernel operates completely in the kernel mode within the unified address space and it facilitates the loadable modules, enabling the components of the kernel to be added, removed, or updated while the system is running. Applications are used to interact with the kernel through the glibc standard C library, serving as the conduit for the system calls.

    146. An example of such limited structuring is the original UNIX operating system, which consists of two separable parts: the kernel and the system programs. The kernel is further separated into a series of interfaces and device drivers, which have been added and expanded over the years as UNIX has evolved. We can view the traditional UNIX operating system as being layered to some extent, as shown in Figure 2.12. Everything below the system-call interface and above the physical hardware is the kernel. The kernel provides the file system, CPU scheduling, memory management, and other operating-system functions through system calls. Taken in sum, that is an enormous amount of functionality to be combined into one single address space.

      The original UNIX OS illustrates a partially layered structure. While it is mostly monolithic, it separates the kernel from system programs and further divides the kernel into interfaces and device drivers. The kernel handles core functions—like file systems, CPU scheduling, and the memory management—through system calls, all within a single address space, demonstrating how even limited structuring can help organize a complex operating system.

    147. The simplest structure for organizing an operating system is no structure at all. That is, place all of the functionality of the kernel into a single, static binary file that runs in a single address space. This approach—known as a monolithic structure—is a common technique for designing operating systems.

      A monolithic structure is the simplest way for organizing the operating system: all the kernel functions are compiled into the single large binary which runs in one address space. While straightforward, this design can make the debugging, updating, and maintaining the system becomes more difficult, because every part of the kernel is tightly interconnected. Many of the early operating systems have used this approach.

    148. A system as large and complex as a modern operating system must be engineered carefully if it is to function properly and be modified easily. A common approach is to partition the task into small components, or modules, rather than have one single system. Each of these modules should be a well-defined portion of the system, with carefully defined interfaces and functions. You may use a similar approach when you structure your programs: rather than placing all of your code in the main() function, you instead separate logic into a number of functions, clearly articulate parameters and return values, and then call those functions from main().

      Modern operating systems are meant to be extremely complex, so breaking them into the modules makes the development and the maintenance manageable.Every module manages a distinct, clearly defined function and interacts with the other modules via explicit interfaces. This modular method resembles effective programming practices, as the code is separated into functions with specified inputs and outputs instead of consolidating everything within the main(). It enhances readability, maintainability, and also decreases errors.

    149. As is true in other systems, major performance improvements in operating systems are more likely to be the result of better data structures and algorithms than of excellent assembly-language code. In addition, although operating systems are large, only a small amount of the code is critical to high performance; the interrupt handlers, I/O manager, memory manager, and CPU scheduler are probably the most critical routines. After the system is written and is working correctly, bottlenecks can be identified and can be refactored to operate more efficiently.

      As is true in other systems, major performance improvements in operating systems are more likely to be the result of better data structures and algorithms than of excellent assembly-language code. In addition, although operating systems are large, only a small amount of the code is critical to high performance; the interrupt handlers, I/O manager, memory manager, and CPU scheduler are probably the most critical routines. After the system is written and is working correctly, bottlenecks can be identified and can be refactored to operate more efficiently.

    150. The advantages of using a higher-level language, or at least a systems-implementation language, for implementing operating systems are the same as those gained when the language is used for application programs: the code can be written faster, is more compact, and is easier to understand and debug. In addition, improvements in compiler technology will improve the generated code for the entire operating system by simple recompilation. Finally, an operating system is far easier to port to other hardware if it is written in a higher-level language. This is particularly important for operating systems that are intended to run on several different hardware systems, such as small embedded devices, Intel x86 systems, and ARM chips running on phones and tablets.

      Using the higher-level languages for the operating system development offers the several key benefits: code can be written more quickly, is easier to read and debug, and is generally more compact. Compiler improvements automatically enhance the efficiency of the OS through recompilation. Additionally, the high-level languages make the porting of the OS to the different hardware platforms much easier—such as a crucial advantage for the systems designed for running on diverse devices, from embedded systems to desktop PCs and mobile ARM-based devices.

    151. Early operating systems were written in assembly language. Now, most are written in higher-level languages such as C or C++, with small amounts of the system written in assembly language. In fact, more than one higher-level language is often used. The lowest levels of the kernel might be written in assembly language and C. Higher-level routines might be written in C and C++, and system libraries might be written in C++ or even higher-level languages. Android provides a nice example: its kernel is written mostly in C with some assembly language. Most Android system libraries are written in C or C++, and its application frameworks—which provide the developer interface to the system—are written mostly in Java. We cover Android's architecture in more detail in Section 2.8.5.2.

      This passage emphasizes the importance and the evolution of the operating system development from the assembly language to the higher-level languages like C and C++. Modern OS kernels often use a mix of languages: low-level routines for the hardware control in the assembly or C, system libraries in the C or C++, and the higher-level application frameworks in the languages such as Java. Android is a clear example, showing how the different layers of the OS stack are used for implementation in the different languages to balance the performance, portability, and also the developer accessibility.

    152. Policy decisions are important for all resource allocation. Whenever it is necessary to decide whether or not to allocate a resource, a policy decision must be made. Whenever the question is how rather than what, it is a mechanism that must be determined.

      This passage emphasizes the difference between the policy and the mechanism in the resource management. A policy defines what should be done—for example, deciding which of the process gets the access to the resource—while a mechanism defines how the decision should be implemented, such as a specific algorithm or the procedure used to allocate such a resource. Recognizing this separation helps in designing the flexible and adaptable operating systems.

    153. We can make a similar comparison between commercial and open-source operating systems. For instance, contrast Windows, discussed above, with Linux, an open-source operating system that runs on a wide range of computing devices and has been available for over 25 years. The “standard” Linux kernel has a specific CPU scheduling algorithm (covered in Section 5.7.1), which is a mechanism that supports a certain policy. However, anyone is free to modify or replace the scheduler to support a different policy.

      This passage illustrates the separation of policy and mechanism in practice, using the Windows versus Linux as the examples. In Linux, the CPU scheduler is used for representing a mechanism, while the scheduling algorithm (policy) determines how much of the CPU time is being allocated. Unlike most of the commercial operating systems, Linux is an open source, so the users can be able to modify or replace the scheduler to implement a different policy without changing any of the underlying mechanism. This flexibility is a key advantage of open-source systems.

    154. The separation of policy and mechanism is important for flexibility. Policies are likely to change across places or over time. In the worst case, each change in policy would require a change in the underlying mechanism. A general mechanism flexible enough to work across a range of policies is preferable. A change in policy would then require redefinition of only certain parameters of the system. For instance, consider a mechanism for giving priority to certain types of programs over others. If the mechanism is properly separated from policy, it can be used either to support a policy decision that I/O-intensive programs should have priority over CPU-intensive ones or to support the opposite policy.

      This passage highlights why separating policy from mechanism increases flexibility in an operating system. Policies often change depending on context or over time, and if mechanisms were tightly coupled to policies, any change would require redesigning the mechanism. By keeping the mechanisms general and flexible, only the policy parameters needs to be adjusted. For example, the priority mechanism can be used to support the different policies, such as giving the preference to the I/O-intensive programs or the CPU-intensive programs, without modifying any of the underlying mechanism itself.

    155. One important principle is the separation of policy from mechanism. Mechanisms determine how to do something; policies determine what will be done. For example, the timer construct (see Section 1.4.3) is a mechanism for ensuring CPU protection, but deciding how long the timer is to be set for a particular user is a policy decision.

      This principle emphasizes distinguishing between mechanisms and policies. Mechanisms define how the task is performed, while policies define what is to be done. For instance, a timer is a mechanism that enforces CPU usage limits, but setting the duration of the timer for each user is a policy decision. This separation allows flexibility in system behavior without changing the underlying implementation.

    156. Specifying and designing an operating system is a highly creative task. Although no textbook can tell you how to do it, general principles have been developed in the field of software engineering, and we turn now to a discussion of some of these principles.

      Designing an operating system requires a high degree of creativity, as there is no single formula or textbook method for doing it. However, software engineering principles provide general guidelines and best practices that can help structure the design process, ensuring the system is reliable, efficient, and maintainable.

    157. There is, in short, no unique solution to the problem of defining the requirements for an operating system. The wide range of systems in existence shows that different requirements can result in a large variety of solutions for different environments. For example, the requirements for Wind River VxWorks, a real-time operating system for embedded systems, must have been substantially different from those for Windows Server, a large multiaccess operating system designed for enterprise applications.

      There is, in short, no unique solution to the problem of defining the requirements for an operating system. The wide range of systems in existence shows that different requirements can result in a large variety of solutions for different environments. For example, the requirements for Wind River VxWorks, a real-time operating system for embedded systems, must have been substantially different from those for Windows Server, a large multiaccess operating system designed for enterprise applications.

    158. The first problem in designing a system is to define goals and specifications. At the highest level, the design of the system will be affected by the choice of hardware and the type of system: traditional desktop/laptop, mobile, distributed, or real time.

      The initial step in designing the operating system is defining the clear goals and their specifications. Key design decisions will depend on the hardware platform and the type of the system that is being developed—whether it’s the traditional desktop or the laptop, a mobile device, a distributed system, or the real-time system. These factors are used to influence the performance, capabilities, and the overall architecture for the OS.

    159. In sum, all of these differences mean that unless an interpreter, RTE, or binary executable file is written for and compiled on a specific operating system on a specific CPU type (such as Intel x86 or ARMv8), the application will fail to run. Imagine the amount of work that is required for a program such as the Firefox browser to run on Windows, macOS, various Linux releases, iOS, and Android, sometimes on various CPU architectures.

      Ultimately, an application can only run on a system if its interpreter, runtime environment (RTE), or compiled binary is designed for that specific operating system and CPU architecture. This explains why cross-platform applications, like the Firefox browser, require significant effort to support multiple OSes and hardware types, including Windows, macOS, Linux distributions, iOS, and Android, often across different processor architectures.

    160. Each operating system has a binary format for applications that dictates the layout of the header, instructions, and variables. Those components need to be at certain locations in specified structures within an executable file so the operating system can open the file and load the application for proper execution.

      Every operating system defines its own binary file format for applications, which specifies how the executable’s header, instructions, and variables are arranged. This structure ensures that the OS can correctly load the program into memory and execute it, making the binary format a critical factor in application compatibility across different systems.

    161. In theory, these three approaches seemingly provide simple solutions for developing applications that can run across different operating systems. However, the general lack of application mobility has several causes, all of which still make developing cross-platform applications a challenging task. At the application level, the libraries provided with the operating system contain APIs to provide features like GUI interfaces, and an application designed to call one set of APIs (say, those available from IOS on the Apple iPhone) will not work on an operating system that does not provide those APIs (such as Android). Other challenges exist at lower levels in the system, including the following.

      While the interpreted languages, virtual machines, and the cross-compilers can help the applications run on the multiple operating systems, achieving the true cross-platform compatibility is said to remain difficult. One major reason is that the different operating systems offer the different libraries and the APIs, particularly for the GUI and the system-level features. An app designed for the one OS (like iOS) may fail on the other(like Android) if the expected APIs aren’t available. Additionally, the lower-level differences in the system architecture, the memory management, and the file handling are used to create the further challenges for the developers trying to make the applications that are portable.

    162. In theory, these three approaches seemingly provide simple solutions for developing applications that can run across different operating systems. However, the general lack of application mobility has several causes, all of which still make developing cross-platform applications a challenging task. At the application level, the libraries provided with the operating system contain APIs to provide features like GUI interfaces, and an application designed to call one set of APIs (say, those available from IOS on the Apple iPhone) will not work on an operating system that does not provide those APIs (such as Android). Other challenges exist at lower levels in the system, including the following.

      Although the interpreted languages, the virtual machines, and the cross-compilers help with the cross-platform development, true application portability is still considered difficult. A major reason is that the operating systems are used to provide the different APIs, especially for the features like the graphical interfaces. An app is built for one OS (e.g., iOS) may fail on another (e.g., Android) because of the expected APIs aren’t said to be available. Additional challenges also arise from the low-level system differences, making this cross-platform development complex.

    163. 1. The application can be written in an interpreted language (such as Python or Ruby) that has an interpreter available for multiple operating systems. The interpreter reads each line of the source program, executes equivalent instructions on the native instruction set, and calls native operating system calls. Performance suffers relative to that for native applications, and the interpreter provides only a subset of each operating system's features, possibly limiting the feature sets of the associated applications.

      Applications developed in interpreted languages such as Python or Ruby can operate on various operating systems since the interpreter functions as an intermediary layer. The interpreter executes the program line by line, converting it into native instructions and calling the OS when needed. This enables compatibility across platforms but might reduce performance compared to native apps and could limit access to some features exclusive to specific operating systems.

    164. Based on our earlier discussion, we can now see part of the problem—each operating system provides a unique set of system calls. System calls are part of the set of services provided by operating systems for use by applications. Even if system calls were somehow uniform, other barriers would make it difficult for us to execute application programs on different operating systems. But if you have used multiple operating systems, you may have used some of the same applications on them. How is that possible?

      Each of the operating system has its own set of the system calls, which makes it very hard to run the applications across the different systems. Even if the system calls were standardized, the differences in the design and the implementation would still cause the ompatibility issues. Yet, we often are able to see the same applications (like the browsers or the word processors) working across the Windows, Linux, and the macOS. This is possible because of the applications are usually written against the APIs or the cross-platform frameworks, rather than directly using system calls, allowing them to be adapted to different operating systems.

    165. Object files and executable files typically have standard formats that include the compiled machine code and a symbol table containing metadata about functions and variables that are referenced in the program. For UNIX and Linux systems, this standard format is known as ELF (for Executable and Linkable Format). There are separate ELF formats for relocatable and executable files. One piece of information in the ELF file for executable files is the program's entry point, which contains the address of the first instruction to be executed when the program runs. Windows systems use the Portable Executable (PE) format, and macOS uses the Mach-O format.

      Executable and the object files follow the standard formats which include both the actual machine code and the metadata (like details about functions and variables). On UNIX and the Linux systems, this format is called ELF (Executable and Linkable Format), with the different versions for the relocatable and the executable files. ELF files also are used specify the entry point, which is the first instruction to run when the program starts. Other operating systems use different formats—Windows uses PE (Portable Executable), and macOS uses Mach-O.

    166. Source files are compiled into object files that are designed to be loaded into any physical memory location, a format known as an relocatable object file. Next, the linker combines these relocatable object files into a single binary executable file. During the linking phase, other object files or libraries may be included as well, such as the standard C or math library (specified with the flag -lm).

      When the programs are compiled, then the source code is initially transformed into the relocatable object files, which can be loaded into any of the memory addresses. The linker merges these types of the object file types into one of the executable file, also including external object files or libraries when necessary (for example, the math library with -lm). This process ensures that the completed program is comprehensive and ready to run

    167. The view of the operating system seen by most users is defined by the application and system programs, rather than by the actual system calls. Consider a user's PC. When a user's computer is running the macOS operating system, the user might see the GUI, featuring a mouse-and-windows interface. Alternatively, or even in one of the windows, the user might have a command-line UNIX shell. Both use the same set of system calls, but the system calls look different and act in different ways. Further confusing the user view, consider the user dual-booting from macOS into Windows. Now the same user on the same hardware has two entirely different interfaces and two sets of applications using the same physical resources. On the same hardware, then, a user can be exposed to multiple user interfaces sequentially or concurrently.

      Users primarily interact with the operating system through the interfaces (GUIs or command lines) and applications, rather than directly getting through the system calls. For example, macOS users can interact through the graphical interface or the UNIX shell, both able to use the same system calls, although they appear quite different.The Dual-booting macOS and the Windows showcases how the identical hardware can result in the distinctly different type of the user experiences and the environments, despite relying on the same foundational system resources

    168. Program loading and execution. Once a program is assembled or compiled, it must be loaded into memory to be executed. The system may provide absolute loaders, relocatable loaders, linkage editors, and overlay loaders. Debugging systems for either higher-level languages or machine language are needed as well.

      Program loading and execution services handle the process of getting compiled programs into memory so they can run. These include loaders (absolute, relocatable, overlay) and tools like linkage editors. Debugging support is also part of this category, helping programmers test and fix errors in either high-level code or machine language.

    169. File management. These programs create, delete, copy, rename, print, list, and generally access and manipulate files and directories.

      File management services provide everyday tools for working with files and directories. They let users create, delete, copy, rename, print, and list files, making it easier to organize and manage data without needing to use low-level system calls directly.

    170. Another aspect of a modern system is its collection of system services. Recall Figure 1.1, which depicted the logical computer hierarchy. At the lowest level is hardware. Next is the operating system, then the system services, and finally the application programs. System services, also known as system utilities, provide a convenient environment for program development and execution. Some of them are simply user interfaces to system calls. Others are considerably more complex. They can be divided into these categories:

      This part explains where system services fit in the computer hierarchy. They are situated between the operating system and the application programs, making it very easy for the developers and the users to interact with the system. Some services are just the simple tools which act as the front end for the system calls, while the others are more advanced and are used to provide the broader functionality. Essentially, system services (or utilities) give the programmers a convenient way for developing and running the programs without dealing directly with the low-level details.

    171. Typically, system calls providing protection include set_permission() and get_permission(), which manipulate the permission settings of resources such as files and disks. The allow_user() and deny_user() system calls specify whether particular users can—or cannot—be allowed access to certain resources. We cover protection in Chapter 17 and the much larger issue of security—which involves using protection against external threats—in Chapter 16.

      This paragraph highlights about how the operating systems are used to employ the certain system calls to manage protection and access control. Functions such as the set_permission() and the get_permission()manage permissions for its resources, whereas allow_user() and the deny_user() are used to specify which of the users can access the particular files or the devices. This indicates that the protection is meant exclusively to manage internal access rights, whereas the security (addressed later) focuses on defending against external threats

    172. Protection provides a mechanism for controlling access to the resources provided by a computer system. Historically, protection was a concern only on multiprogrammed computer systems with several users. However, with the advent of networking and the Internet, all computer systems, from servers to mobile handheld devices, must be concerned with protection.

      Why has protection become an important concern for all the computer systems, not just the multiprogrammed systems with its multiple users?

    173. Both of the models just discussed are common in operating systems, and most systems implement both. Message passing is useful for exchanging smaller amounts of data, because no conflicts need be avoided. It is also easier to implement than is shared memory for intercomputer communication. Shared memory allows maximum speed and convenience of communication, since it can be done at memory transfer speeds when it takes place within a computer. Problems exist, however, in the areas of protection and synchronization between the processes sharing memory.

      What are the main advantages and the disadvantages of using the message passing versus the shared memory for interprocess communication, and in what situations is each model more suitable?

    174. There are two common models of interprocess communication: the message-passing model and the shared-memory model. In the message-passing model, the communicating processes exchange messages with one another to transfer information. Messages can be exchanged between the processes either directly or indirectly through a common mailbox. Before communication can take place, a connection must be opened. The name of the other communicator must be known, be it another process on the same system or a process on another computer connected by a communications network. Each computer in a network has a host name by which it is commonly known. A host also has a network identifier, such as an IP address. Similarly, each process has a process name, and this name is translated into an identifier by which the operating system can refer to the process. The get_hostid() and get_processid() system calls do this translation. The identifiers are then passed to the general-purpose open() and close() calls provided by the file system or to specific open_connection() and close_connection() system calls, depending on the system's model of communication. The recipient process usually must give its permission for communication to take place with an accept_connection() call. Most processes that will be receiving connections are special-purpose daemons, which are system programs provided for that purpose. They execute a wait_for_connection() call and are awakened when a connection is made. The source of the communication, known as the client, and the receiving daemon, known as a server, then exchange messages by using read_message() and write_message() system calls. The close_connection() call terminates the communication.

      Explain the steps involved in interprocess communication using the message-passing model. Include the roles of the client, server (daemon), and system calls such as open_connection(), accept_connection(), read_message(), and close_connection().

    175. Many operating systems provide a time profile of a program to indicate the amount of time that the program executes at a particular location or set of locations. A time profile requires either a tracing facility or regular timer interrupts. At every occurrence of the timer interrupt, the value of the program counter is recorded. With sufficiently frequent timer interrupts, a statistical picture of the time spent on various parts of the program can be obtained.

      Many operating systems can track how much time a program spends running at different points in its code. This is called a time profile. To create one, the system either traces the program or uses regular timer interrupts. Every time the timer interrupts, the system records the program’s current position. By doing this often frequently, it can give a statistical view of which parts of the program take the most time to execute.

    176. Many system calls exist simply for the purpose of transferring information between the user program and the operating system. For example, most systems have a system call to return the current time() and date(). Other system calls may return information about the system, such as the version number of the operating system, the amount of free memory or disk space, and so on.

      Many system calls are used for just passing the information back and forth between the program and the operating system. For example, many systems are used for processing a function which is used to retrieve the current time and its date. Additional calls can offer the information regarding the system, such as the version of the operating system, the amount of the available memory or disk space, and other related details

    177. Once the device has been requested (and allocated to us), we can read(), write(), and (possibly) reposition() the device, just as we can with files. In fact, the similarity between I/O devices and files is so great that many operating systems, including UNIX, merge the two into a combined file–device structure. In this case, a set of system calls is used on both files and devices. Sometimes, I/O devices are identified by special file names, directory placement, or file attributes.

      Once the device has been requested (and allocated to us), we can read(), write(), and (possibly) reposition() the device, just as we can with files. In fact, the similarity between I/O devices and files is so great that many operating systems, including UNIX, merge the two into a combined file–device structure. In this case, a set of system calls is used on both files and devices. Sometimes, I/O devices are identified by special file names, directory placement, or file attributes.

    178. The various resources controlled by the operating system can be thought of as devices. Some of these devices are physical devices (for example, disk drives), while others can be thought of as abstract or virtual devices (for example, files). A system with multiple users may require us to first request() a device, to ensure exclusive use of it. After we are finished with the device, we release() it. These functions are similar to the open() and close() system calls for files. Other operating systems allow unmanaged access to devices. The hazard then is the potential for device contention and perhaps deadlock, which are described in Chapter 8.

      The resources that an operating system manages can be thought of as devices. Some of these are physical, like the disk drives, while the others are abstract or virtual, like the files. In the systems where the multiple users, a program may need to request() the device to ensure that it has an exclusive access, and then release() it when it's finished. These actions are similar to open() and close() for files. Some operating systems let programs access devices without this kind of control, but doing so can lead to problems like device conflicts or deadlocks, which we’ll discuss in Chapter 8.

    179. We may need these same sets of operations for directories if we have a directory structure for organizing files in the file system. In addition, for either files or directories, we need to be able to determine the values of various attributes and perhaps to set them if necessary. File attributes include the file name, file type, protection codes, accounting information, and so on. At least two system calls, get_file_attributes() and set_file_attributes(), are required for this function. Some operating systems provide many more calls, such as calls for file move() and copy(). Others might provide an API that performs those operations using code and other system calls, and others might provide system programs to perform the tasks. If the system programs are callable by other programs, then each can be considered an API by other system programs.

      We often need similar operations for directories as we do for files, especially when using a directory structure to organize files. For both files and directories, it’s important to check or modify their attributes when necessary. Attributes can include things like the name, type,or the access permissions, and the accounting information. To handle this, operating systems usually provide system calls such as get_file_attributes() and set_file_attributes(). Some systems go further, offering extra calls for tasks like moving or copying files. In other cases, these actions are handled through APIs or system programs. If other programs can call these system programs, they effectively act as the APIs themselves.

    180. The file system is discussed in more detail in Chapter 13 through Chapter 15. Here, we identify several common system calls dealing with files. We first need to be able to create() and delete() files. Either system call requires the name of the file and perhaps some of the file's attributes. Once the file is created, we need to open() it and to use it. We may also read(), write(), or reposition() (rewind or skip to the end of the file, for example). Finally, we need to close() the file, indicating that we are no longer using it.

      This part elaborates on the primary file-management system calls offered by an operating system. A program can begin by generating the new file or removing the existing one, identifying its name and the additional attributes as said to be required. Once when the file is generated, it can be accessed by using the open(), allowing the program to engage with it—either by reading, writing, or the repositioning the file pointer with the reposition(). After the program has completed its operations within the file, close() is called for indicating that the file is no longer in use or accessed

    181. There are so many facets of and variations in process control that we next use two examples—one involving a single-tasking system and the other a multitasking system—to clarify these concepts. The Arduino is a simple hardware platform consisting of a microcontroller along with input sensors that respond to a variety of events, such as changes to light, temperature, and barometric pressure, to just name a few. To write a program for the Arduino, we first write the program on a PC and then upload the compiled program (known as a sketch) from the PC to the Arduino's flash memory via a USB connection. The standard Arduino platform does not provide an operating system; instead, a small piece of software known as a boot loader loads the sketch into a specific region in the Arduino's memory

      This passage explains process control in simple and multitasking systems using the Arduino as an example. The Arduino is a microcontroller platform with sensors that detect various events. Programs, called sketches, are written and compiled on a PC and then uploaded to the Arduino’s flash memory. Unlike more complex systems, the standard Arduino does not use a full operating system; a bootloader simply loads the sketch into memory, demonstrating a single-tasking environment.

    182. Quite often, two or more processes may share data. To ensure the integrity of the data being shared, operating systems often provide system calls allowing a process to lock shared data. Then, no other process can access the data until the lock is released. Typically, such system calls include acquire_lock() and release_lock().

      This paragraph explores how operating systems handle the data exchanged among various processes. For the data integrity preservation, the OS can protect the shared data via the system calls like acquire_lock(), stopping other processes from accessing it until it is freed with the release_lock().This mechanism is crucial for avoiding conflicts and ensuring consistent data in environments with simultaneous processing

    183. A process executing one program may want to load() and execute() another program. This feature allows the command interpreter to execute a program as directed by, for example, a user command or the click of a mouse. An interesting question is where to return control when the loaded program terminates. This question is related to whether the existing program is lost, saved, or allowed to continue execution concurrently with the new program. If control returns to the existing program when the new program terminates, we must save the memory image of the existing program; thus, we have effectively created a mechanism for one program to call another program. If both programs continue concurrently, we have created a new process to be multiprogrammed. Often, there is a system call specifically for this purpose (create_process()).

      This text explains how one application can load and run another application, for instance, when a user issues a command or selects an icon. It emphasizes the main problem of control flow once the new program ends: control might revert to the original program, necessitating its memory image to be preserved, or both programs could operate simultaneously, resulting in a multiprogramming situation. The excerpt mentions that operating systems typically offer a specific system call, like create_process(), to enable this functionality.

    184. A running program needs to be able to halt its execution either normally (end()) or abnormally (abort()). If a system call is made to terminate the currently running program abnormally, or if the program runs into a problem and causes an error trap, a dump of memory is sometimes taken and an error message generated. The dump is written to a special log file on disk and may be examined by a debugger—a system program designed to aid the programmer in finding and correcting errors, or bugs—to determine the cause of the problem. Under either normal or abnormal circumstances, the operating system must transfer control to the invoking command interpreter. The command interpreter then reads the next command. In an interactive system, the command interpreter simply continues with the next command; it is assumed that the user will issue an appropriate command to respond to any error. In a GUI system, a pop-up window might alert the user to the error and ask for guidance. Some systems may allow for special recovery actions in case an error occurs. If the program discovers an error in its input and wants to terminate abnormally, it may also want to define an error level. More severe errors can be indicated by a higher-level error parameter. It is then possible to combine normal and abnormal termination by defining a normal termination as an error at level 0. The command interpreter or a following program can use this error level to determine the next action automatically.

      This passage explains how a running program can terminate either normally using end() or abnormally using abort(). In the case of abnormal termination or an error trap, the operating system may create a memory dump and an error log for debugging. After termination, control is returned to the command interpreter, which continues processing user commands or provides GUI prompts for guidance. The passage also highlights the use of error levels to indicate the severity of errors, allowing subsequent programs or the command interpreter to respond appropriately.

    185. System calls can be grouped roughly into six major categories: process control, file management, device management, information maintenance, communications, and protection. Below, we briefly discuss the types of system calls that may be provided by an operating system. Most of these system calls support, or are supported by, concepts and functions that are discussed in later chapters. Figure 2.8 summarizes the types of system calls normally provided by an operating system. As mentioned, in this text, we normally refer to the system calls by generic names. Throughout the text, however, we provide examples of the actual counterparts to the system calls for UNIX, Linux, and Windows systems.

      This section explains that system calls can be categorized into six primary groups: process management, file handling, device control, information upkeep, communication, and security. The text emphasizes that most system calls relate to concepts discussed later and provides examples from UNIX, Linux, and Windows. Figure 2.8 gives a summary of these categories.

    186. hree general methods are used to pass parameters to the operating system. The simplest approach is to pass the parameters in registers. In some cases, however, there may be more parameters than registers. In these cases, the parameters are generally stored in a block, or table, in memory, and the address of the block is passed as a parameter in a register (Figure 2.7). Linux uses a combination of these approaches.

      This passage describes three ways that system-call parameters can be passed to the operating system. The simplest method is using CPU registers to hold the parameters. If there are too many parameters for the available registers, the parameters are then placed in the memory block or the table, and the address of that block is passed into the register. Linux uses the mix of both the methods depending on the situation.

    187. System calls occur in different ways, depending on the computer in use. Often, more information is required than simply the identity of the desired system call. The exact type and amount of information vary according to the particular operating system and call. For example, to get input, we may need to specify the file or device to use as the source, as well as the address and length of the memory buffer into which the input should be read. Of course, the device or file and length may be implicit in the call.

      This passage explains that system calls often require additional information beyond identifying the call itself. Parameters—like the source file or the device, memory buffer address, and buffer length—may need to be specified so the operating system understands how to process the request. The precise specifics rely on the particular operating system and the system calls being utilized

    188. The caller need know nothing about how the system call is implemented or what it does during execution. Rather, the caller need only obey the API and understand what the operating system will do as a result of the execution of that system call. Thus, most of the details of the operating-system interface are hidden from the programmer by the API and are managed by the RTE.

      This text highlights the importance of abstraction within system calls. Programmers working with an API do not have to understand the internal mechanisms or execution specifics of a system call. They just need to follow to the API's instructions and also understand the expected outcome. The run-time environment (RTE) manages the inner networks of interacting with the operating system, successfully concealing the underlying specifics from the developer.

    189. Another important factor in handling system calls is the run-time environment (RTE)—the full suite of software needed to execute applications written in a given programming language, including its compilers or interpreters as well as other software, such as libraries and loaders. The RTE provides a system-call interface that serves as the link to system calls made available by the operating system. The system-call interface intercepts function calls in the API and invokes the necessary system calls within the operating system. Typically, a number is associated with each system call, and the system-call interface maintains a table indexed according to these numbers

      This passage describes the role of the run-time environment (RTE) in managing system calls. The RTE includes compilers, interpreters, libraries, and loaders, and provides a system-call interface that connects API function calls to the operating system’s system calls. Each system call is typically assigned a number, and the interface uses a table indexed by these numbers to invoke the correct system call within the OS.

    190. Why would an application programmer prefer programming according to an API rather than invoking actual system calls? There are several reasons for doing so. One benefit concerns program portability. An application programmer designing a program using an API can expect her program to compile and run on any system that supports the same API (although, in reality, architectural differences often make this more difficult than it may appear). Furthermore, actual system calls can often be more detailed and difficult to work with than the API available to an application programmer. Nevertheless, there often exists a strong correlation between a function in the API and its associated system call within the kernel. In fact, many of the POSIX and Windows APIs are similar to the native system calls provided by the UNIX, Linux, and Windows operating systems.

      This passage describes why the application programmers prefer using the APIs instead of directly invoking the system calls. APIs provide the portability, allowing the programs to run on any system which supports the same API, and also simplify the programming by offering the higher-level, easier-to-use functions. While the system calls are often more detailed and complex, APIs usually have a close correspondence with the underlying system calls, as seen in the POSIX and the Windows APIs.

    191. As you can see, even simple programs may make heavy use of the operating system. Frequently, systems execute thousands of system calls per second. Most programmers never see this level of detail, however. Typically, application developers design programs according to an application programming interface (API). The API specifies a set of functions that are available to an application programmer, including the parameters that are passed to each function and the return values the programmer can expect. Three of the most common APIs available to application programmers are the Windows API for Windows systems, the POSIX API for POSIX-based systems (which include virtually all versions of UNIX, Linux, and macOS), and the Java API for programs that run on the Java virtual machine

      This passage highlights that even simple programs rely heavily on the operating system through system calls, often executing thousands per second. However, the programmers usually interact with the higher-level APIs rather than making the system calls directly. APIs likethe Windows API, POSIX API, and the Java API provide the standardized functions, parameters, and the expected return values, simplifying the program development while hiding the underlying OS complexity.

    192. When both files are set up, we enter a loop that reads from the input file (a system call) and writes to the output file (another system call). Each read and write must return status information regarding various possible error conditions. On input, the program may find that the end of the file has been reached or that there was a hardware failure in the read (such as a parity error). The write operation may encounter various errors, depending on the output device (for example, no more available disk space).

      This passage emphasizes that reading from and writing to files in a program involves repeated system calls, each of which must report status and handle potential errors. It illustrates how the operating system monitors both input and output operations, accounting for conditions like reaching the end of a file, hardware read failures, or insufficient disk space during writing.

    193. Once the two file names have been obtained, the program must open the input file and create and open the output file. Each of these operations requires another system call. Possible error conditions for each system call must be handled. For example, when the program tries to open the input file, it may find that there is no file of that name or that the file is protected against access. In these cases, the program should output an error message (another sequence of system calls) and then terminate abnormally (another system call).

      This passage explains that each file operation—opening an input file, creating and opening an output file—requires a separate system call. It highlights the need for handling potential errors, such as a missing file or insufficient access permissions, using system calls to display error messages and terminate the program if necessary.

    194. Before we discuss how an operating system makes system calls available, let's first use an example to illustrate how system calls are used: writing a simple program to read data from one file and copy them to another file. The first input that the program will need is the names of the two files: the input file and the output file. These names can be specified in many ways, depending on the operating-system design

      This passage introduces the concept of using system calls with a practical example: a program that reads from one file and writes to another. It emphasizes that the program first needs the file names and notes that how these names are specified can vary depending on the operating system’s design.

    195. System calls provide an interface to the services made available by an operating system. These calls are generally available as functions written in C and C++, although certain low-level tasks (for example, tasks where hardware must be accessed directly) may have to be written using assembly-language instructions.

      This passage explains that system calls act as the bridge between programs and the operating system’s services. Most system calls are accessible through high-level languages like C and C++, but some low-level operations—especially those requiring direct hardware access—may need to be implemented in assembly language.

    196. Although there are apps that provide a command-line interface for iOS and Android mobile systems, they are rarely used. Instead, almost all users of mobile systems interact with their devices using the touch-screen interface. The user interface can vary from system to system and even from user to user within a system; however, it typically is substantially removed from the actual system structure. The design of a useful and intuitive user interface is therefore not a direct function of the operating system. In this book, we concentrate on the fundamental problems of providing adequate service to user programs. From the point of view of the operating system, we do not distinguish between user programs and system programs.

      This passage emphasizes that mobile users almost exclusively use touch-screen interfaces rather than command-line interfaces. While user interfaces may differ across systems and users, their design is largely separate from the underlying operating system. The focus of the book, as noted here, is on the operating system’s role in providing consistent and adequate service to programs, treating user and system programs equivalently.

    197. In contrast, most Windows users are happy to use the Windows GUI environment and almost never use the shell interface. Recent versions of the Windows operating system provide both a standard GUI for desktop and traditional laptops and a touch screen for tablets. The various changes undergone by the Macintosh operating systems also provide a nice study in contrast.

      This passage differntiates the typical Windows users with the command-line users, noting that most Windows users rely primarily on the GUI and rarely use the shell. Modern Windows versions support both desktop GUIs and touch interfaces for tablets. The passage also points out that the evolution of Macintosh operating systems offers a useful comparison in understanding how GUI design and user interaction have developed over time.

    198. The choice of whether to use a command-line or GUI interface is mostly one of personal preference. System administrators who manage computers and power users who have deep knowledge of a system frequently use the command-line interface. For them, it is more efficient, giving them faster access to the activities they need to perform. Indeed, on some systems, only a subset of system functions is available via the GUI, leaving the less common tasks to those who are command-line knowledgeable

      This text emphasizes that the decision between using the graphical user interface (GUI) and the command-line interface (CLI) usually depends on individual preference and the user's skill level. System administrators and experienced users typically prefer the CLI for its quicker, more efficient access to system features Certain tasks might only be accessible through the CLI, highlighting the significance for users requiring specific or uncommon functions.

    199. Because a either a command-line interface or a mouse-and-keyboard system is impractical for most mobile systems, smartphones and handheld tablet computers typically use a touch-screen interface. Here, users interact by making gestures on the touch screen—for example, pressing and swiping fingers across the screen. Although earlier smartphones included a physical keyboard, most smartphones and tablets now simulate a keyboard on the touch screen

      This text demonstrates that mobile devices like smartphones and tablets depend on touch-screen interfaces rather than conventional command-line or mouse-and-keyboard systems. Users typically engage directly with the display by using gestures like tapping or swiping.While the early smartphones had physical keyboards, modern devices typically display a virtual keyboard on the touch screen for the input, optimizing portability and also usability.

    200. Graphical user interfaces first appeared due in part to research taking place in the early 1970s at Xerox PARC research facility. The first GUI appeared on the Xerox Alto computer in 1973. However, graphical interfaces became more widespread with the advent of Apple Macintosh computers in the 1980s. The user interface for the Macintosh operating system has undergone various changes over the years, the most significant being the adoption of the Aqua interface that appeared with macOS. Microsoft's first version of Windows—Version 1.0—was based on the addition of a GUI interface to the MS-DOS operating system

      This passage outlines how the historical development of the graphical user interfaces (GUIs). GUIs were at the beginning examined at the Xerox PARC in the early 1970s, with the Xerox Alto being the first computer to have one. Widespread usage took place in the 1980s with Apple’s Macintosh computers. Over time, GUIs evolved, such as Apple’s adoption of the Aqua interface in macOS. Microsoft also integrated a GUI with Windows 1.0, layering it over the MS-DOS operating system.