Hello and welcome back. As you've seen previously, an operating system has to protect the integrity of the hardware resources it manages while providing the services to the applications. Thus it has many responsibilities and a variety of functional components that provide these services. But how should all these pieces fit together? At least some of the components of the operating system will have to run in a privileged mode of the processor architecture that allows them access to hardware. But must the whole operating system have this privilege? Also, if an application would benefit from having certain services, for example, memory management handled in a particular way. Can we personalize the services to suit the needs of the application? In other words, can we make the operating system flexible in terms of the policies it implements for the services offered by it? Does this flexibility have to come at the price of performance and or safety of the operating system? These are some of the questions we will try to answer in this course module. In this course module, we will learn the basics of operating system structuring issues. We will use SPIN and Exokernel as case studies of two closely-related approaches to providing extensibility of operating system services. We will then study a microkernel-based approach as well, using L3 microkernel.
This is a free-form quiz, and what I want you to do is, name as many system services as you can, that you expect from an operating system.
You may have hit many of the services that I've identified here, and plus even more. And even if you did not get some of the things that I've listed here, that's okay. It's just, is sort of refresh your memory as to what system services, one can expect from an operating system.
What do we mean by operating system structure? What we mean by this term is the way the operating system software is organized with respect to the applications that it serves and the underlying hardware that it manages. It's sort of like the burger between the buns. There is application at the top and technology or hardware at the bottom and system software of the operating system is what connects the applications to the underlying hardware. Since this lesson is all about operating system structure, I would like to get your thoughts on why you may think that the structure of an operating system is important, and from that point of view I'm going to give you a quiz again.
The question that I'm going to pose to you is, why you think the structure of the operating system is important, and I'm giving you several choices and you can choose as many of these choices as you'd think is appropriate in terms of your own perspective on why you think the structure of the operating system is important. The first one is protection, second one is performance, third one is flexibility, the fourth one is scalability and the fifth one is agility, and the final one is responsiveness.
If you checked off all the boxes you're right on. All of these issues are important issues to worry about in the structure of an Operating System.
Let's now elaborate on the goals of operating systems structure. The first goal is protection. By protection what we mean is protecting the user from the system and the system from the user and also users from one another. And also protecting an individual user from his or her own mistakes. That's what we mean by protection. And this is an important goal of operating system structuring. An operating system, of course, provides services and one of the key determinants of a good operating system structure is how good is the performance of the operating system. That is, what is the time taken to perform services on behalf of the application. I have, you've heard me say this even before in the previous lecture. A good operating system is one that provides the service that is needed by the application very quickly and gets out of the way. And that's the key determinant of operating system structure as well. Another goal, of operating system structure, and in fact, one of the goals that we will be focusing a lot on in this course module, is flexibility. Sometimes also called extensibility, meaning that a service that is provided by the operating system is not one size fits all, but the service is something that is adaptable to the requirements of the application. Another important goal of structuring an operating system is to ensure that the performance of the operating system goes up as you add more hardware resources to the system. This is sort of an intuitive understanding, but you want to make sure that the operating system developers on this intuitive understanding that when you increase the hardware resources, the performance also goes up, and that's what is meant by scalability. It turns out that both the needs of the application may change over the lifetime of an application and also the resources that are available for the operating system to manage and give to the application may change over time. Agility of the operating system refers to how quickly the operating system adapts itself to changes either in the application needs or the resource availability from the underlying hardware. Another worthwhile goal of operating system structure would be responsiveness. That is, how quickly the operating system reacts to external events, and this is particularly important for applications that are interactive in nature. Imagine you are playing a video game. In that case, what you want to see is when you do something like clicking the mouse to shoot at a target, you want to see action immediately on the screen. So that is responsiveness, how quickly the operating system is reacting to external events.
Are all the goals simeltaneously achieviable in a given operating system? At first glance it would seem that some of the goals conflict with one another. For example, it might seem that to achieve performance, we may have to sacrifice protection and/or flexibility. Let's explore how researchers have used their ingenuity to have the cake and eat it too.
You're probably wondering how the commercial operating systems that you and I use on an every day basis Meet many of these goals that I identified. The short answer to that question is they don't meet all the goals. We will return to the influence of research leading up to the current state of the art in operating system structure towards the end of this course module.
Now let's talk about different approaches to operating system structuring. The first structure that I will introduce to you is what we will call as a monolithic structure. You have the hardware at the bottom which is managed by the operating system and hardware includes, of course, the CPU, memory, peripheral devices such as the network and storage and so on. And there are applications at the top. And each of these applications is in its own hardware address space. What that means is that every application is protected from one another because the hardware ensures that the address space occupied by one application is different from the other applications and that is the first level of protection that you get between the applications themselves. And all the services that applications expect from the operating system are contained in this blob and that might include file system and network access, scheduling these applications on the available CPU, virtual memory management, and access to other peripheral devices. The OS itself of course is a program providing entry points for the applications for the services that are expected by the applications. And code and the data structure of the operating system is contained in its own hardware address space. What that means is that the operating system is protected from the applications and vise versa. So even if an application were to do anything in terms of misbehavior, either maliciously or unintentionally because they are in there own address spaces and the operating system is in its own hardware address space. Malfunctioning of an application does not affect the integrity of the operating system services. That is, when an application needs any system service, we switch from the hardware address space that is representing this particular application, into the hardware address space of the operating system. And execute the system code that provides the service that that is expected by the application. For example, accessing the file from the hard disk, or dynamic allocation of more memory that an application may want, or sending a message on the network. All of these things are done within the confines of the address space of the operating system itself. Note that all of the services expected of the operating system, file system, memory management, CPU scheduling, network and so on, are all contained in this one big blob. And that is the reason it's also sometimes referred to as the monolithic structure of an operating system.
Some of you may remember Microsoft's first entry in the world of PCs, with their operating system called DOS, or disc operating system, and the structure of DOS looks as shown here. And at first glance, at least visually, You might think that this structure is very similar to what I showed you as a monolithic structure before. What is the difference you see in this structure? First I would like you to think about it yourself before we go any further, so here is a question for you.
What is gained with the DOS-like structure that I showed you? And what is lost with the DOS-like structure that I showed you?
You have noticed visually that the key difference was, the red line was replaced by a dotted line, separating the application from the operating system. And what you get out of that is performance. Access to system services are going to be like a procedure call, and what is lost in the DOS-like structure is the fact that you don't have protection. Of the operating system from the application. An errant application can corrupt the operating system. We'll elaborate on this in the next few panels.
So in the DOS-like structure, the main difference from the monolithic structure that I showed you earlier is that the red line separating the application from the operating system is now replaced by a dotted line. What that means, the main difference is there is no hard separation between the address space of the application And the address space of the operating system. The good news is an application can access all the operating system services very quickly. As they would any procedures that they may execute within their own application with the same speed. At memory speeds, an application can make calls into the operating system and get system services. That's the good news. But the bad news is that there is no protection of the operating system from inerrant application. So, the integrity of the operating system can be compromised by a runaway application, either maliciously or unintentionally corrupting the data structures that are in the operating system. Now, you may wonder why DOS Chose this particular structure. Well, at least in the early days of PC, it was thought that a personal computer, as the name suggests, is a platform for a single user and, more importantly, the vision was, there will be exactly one app that is running at a time. Not even multitasking. So performance and simplicity was the key and protection was not primary concern in the DOS-like structure. And that you can get good performance comes from the simple observation that there is No hard separation between the application and the operating system. The operating system is not living in its own address space. The application and the operating system are in the same address space. And therefore, making a system call by an application is going to happen as quickly as the application would call a procedure which the application developer wrote himself or herself.
But this loss of protection with the Dos-like structure is simply unacceptable for a general purpose operating system today. On the other hand, the monolithic structure gives the protection that is so important. At the same time, what it strives to do is also (no period) It reduces the potential for performance loss by consolidating all the services in one big monolithic structure. That is, even tough and application has to go from its address space, into the operating system's address space in order to get some service, It is usually the case that the operating system has several components and they have to talk to one another in order to provide the service that an application wants. Think about the file system, for instance. You make a call to the file system to open a file and the file system then may have to call the storage module in order to find out where exactly a file is residing. And it may have to contact The memory manager module to see where it wants to bring in the file that you want to open and see the content of. So in this sense there's infraction that's going to go on under the cover. Inside the operating system between components of the operating system. In order to satisfy a single service call from an application. So this monolithic structure insures that even though... We have to go from an application into the operating system's address space. Once you're inside the operating system's address space, then potential for performance loss is avoided by the consolidation of all the components that comprise the operating system. But what is lost in the monolithic structure (no period) That is the ability to customize the operating system service for different applications. This model of one size fits all, so far the system service is concerned with the monolithic structure shutsoed the opportunity for customizing the operating service for the needs of different applications. Now, you may wonder why do we need to customize the operating system service for different applications? Why not one size fits all? Why is there an issue? If you look at a couple of examples, the need for customization will become fairly obvious. For example, Interactive video games. The requirement of applications, that are providing a video game experience for the user. Or consider another application, which is computing, All the prime numbers. You can immediately see that the operating system needs for these two classes of applications are perhaps very different. On the one hand, for the little kid who is playing a video game, the key determinant of a good operating system would be responsiveness. How quickly the operating system is responding to his nifty moves when he plays his video game. On the other hand, for the programmer that wrote this prime number computing application, the key determinant of performance is going to be sustained CPU time that's available for crunching his application.
Let's explore the opportunities for customization with a very specific example and the example I'm going to choose is memory management, in particular how an operating system handles page faults. Let's say that this thread executing on the processor incurs a page fault. The first thing that the operating system has to do in order to service this page fault will be to find a free page frame to host the missing page for this particular thread. And once it allocates a free page frame, then the operating system is going to initiate the disc IO to move the page from virtual memory into the free page frame that has been identified for hosting the missing page from this particular thread. Once the IO is complete and the missing page for this thread has been brought from storage into the free page frame, the operating system is going to update the page table for this thread or process, establishing the mapping between the missing virtual page and the page frame that had been allocated for hosting that missing page. Once the page table has been updated then we can resume the process so that it can continue where it left off. At the point of the page fault. One thing that I haven't told you the sequence of actions that the operating system takes, is that every so often, the operating system runs a page replacement algorithm to free up some page frames. And readiness for allocating the frame to a page fault that a process may incur. Just as an airline overbooks its seats in the hope that some passengers won't show up, the operating system is also overcommitting its available physical memory hoping that not all of the pages of a particular process which is in the memory footprint of the process will actually be needed by the process during its execution. But how does the operating system know what the memory access pattern of a particular process is going to be in making this decision? The short answer is it does not. So whatever the operating system chooses as an algorithm to implement page replacement. It may not always be the most appropriate one for some class of applications. So here is an opportunity for customization depending on the nature of the application. Knowing some details about the nature of the application, it might be possible to customize the way page replacement algorithm is handled by the operating system. Similar opportunities for customization exist in the way the operating system schedules processes on the processor and reacts to external events such as interrupts and so on.
There is a need for customization and the opportunity for customization is what spurred operating systems designers to think of a structure of the operating system that would allow customization of the services and gave birth to the idea of microkernel-based operating system. As before, each of the applications is in its own hardware address space, the microkernel runs in a privileged mode of the architecture, and provides simple abstractions such as threads, address space, and inter-process communication. In other words, small number of mechanisms are supported by the microkernel. The keyword is mechanisms, there are no policies ingrained in the microkernel, only mechanisms for accessing hardware resources. The operating system services, such as virtual memory management, CPU scheduling, file system, and so on that implemented as servers on top of the microkernel. So in other words, these system services execute with a same privilege as the applications themselves. Each of the system service is in its own address space and it is protected from one another and protected from the application and the microkernel, being below this red line, is running in privileged mode, it is protected from all of the applications as well as the system services. So in other words, we no longer have that monolithic structure that we had before. Instead each operating system service is in its own hardware address space. In principle, there is no distinction between regular applications and the system services that are executing a server processes on top of the microkernel. Thus, we have very strong protection among the applications, between the applications and system services, among the system services and between application system services and the microkernel. Now, the structure what it entails is that you need the microkernel to provide inter-process communication so that the applications can request system services by contacting the servers and the servers need to talk to one another as well. And in order for them to talk to one another they need inter-process communication as well. So what have we gained by the structure? What we have gained by the structure is extensibility. Because these OS services are implemented as service processes, we can have replicated server processes with different characteristics. For instance, this application may choose to use this particular file system. Another application may choose a different file system. No longer do we have that one size fits all characterization of the monolithic kernel. And this is the biggest draw for the microkernel based design that it is easy to extend the services that are provided with the operating system to customize the services depending on the needs of the application. This all sounds good, but is there a catch?
Is there a downside to the microkernel based approach? Well, there is. There is a potential for performance loss. Now consider this monolithic structure. Let's say this application makes a call to the file system to open up a file. The application slips through this red line into the hardware address space of the operating system. It runs in privileged mode because the operating system may have to do certain things that are privileged, and therefore, the hardware architecture of the CPU usually allows a privileged mode for execution of the operating system code. So now the app is now inside the operating system in a privileged mode with one instruction usually, called a trap instruction. For example, a system call results in a trap into the operating system. And once inside the operating system, all the work that needs to be done in order to satisfy the file system call that the app made. For instance, contacting the storage manager, contacting the memory manager and so on. All off that, are available as components within this blob. Which means that those components can be accessed at the speed of normal procedure call in order to handle the original request from this application. On the other hand, if you look at a microkernel based structure, the application has to make an IPC call in order to contact the service, which is, in this case, a file system service let's say. Which means that the application has to go through the microkernel, making the IPC call. Going up to the file system and the file system does the work, makes another IPC call in order to deliver the results of that system service back up to the application. So the minimum traversal so that you can see is going from the application of the microkernel, microkernel to the file system, and back into the microkernel and back up to the application. Potentially, there may be many more calls that may happen among servers that are sitting above the microkernel. Because the file system may have to contact the storage manager and the file system may have to contact the memory manager. All of those are server processes living above the microkernel and all of them require IPC for talking to one another. So what that means is that with this structure, there is a potential that we may have to switch between the address spaces of the application and many services that are living on top of the microkernel. Whereas in the case of the monolithic structure that I showed you here, there is only two address space switches, one to go from the application into the operating system, and the other to return back to the application. Whereas in a microkernel based design, there could potentially be several address space switches depending on the number of servers that need to be contacted in order to satisfy one system call that may be emanating from the application.
Why do we have this potential for performance loss, with the microkernel based design? Mainly because of the border crossings. That is, going across hardware address spaces, can be quite expensive. First there is this explicit cost of switching the address space, from one hardware address space to another hardware address space. That is the explicit cost. And in addition to the explicit cost of going across address spaces, there are implicit costs involved in this border crossing. And that comes about because of change in locality. We're going from one hardware address space to a different address space, and that changes the locality of execution of the processor. And that means that me memory hierarchy, the caches in particular, close to the processor, may not have the contents that are needed for executing the code and accessing the data structures of a particular server, different from the application. A change in locality is another important determinant of performance and it can adversely effect the performance. And also, when we are going across address spaces to ensure the integrity of the system, either the micro kernel, or the server that is living on top of the microkernel. There may be a need to copy from user space to system space. And those kind of copying of data from the application's memory space into the microkernel and back out to a server process. All of those can result in affecting the performance of the operating system. Whether they're in a monolithic structure, since all the components are contained within the same address space, it is much easier for sharing data without copying. And that's one of the biggest potential sources of performance loss when we have this microkernel based structure.
Now it's time for a question. Based on the discussion we've had thus far, what I would like you to think about is, coming up to the scorecard for the three different structures that I have identified. One is the monolithic operating system, the DOS-like structure, and the microkernel-based operating system. And what I would like you to do is think about the features that are important in the structure of the operating system. Extensibility, protection, performance. And try to fill out this score card as to which of these features are adequately met by each one of these structures. So for each of these operating system structures, monolithic, think about whether it meets all of the features that I've identified here. Do the same thing for Dos-like structure. Do the same thing for the microkernel based structure.
A Monolithic structure definitely gives you protection, no questions about that. And we also argued that it's performant because of the fact that border crossings are minimized and loss of locality is minimized. And, and sources of copying overhead are minimized. All of that add up to giving good performance for the Monolithic structure. On the other hand It's not easily extensible. Any change to the operating system would require rebuilding the monolithic structure with the changed characteristic of the system service. So, one size fits all is what you get with a monolithic structure. A DOS-like structure is performant because there is no separation between the application and the operating system and, therefore, an application can execute system services at the same speed as it would execute a procedure call that is part of that application itself. And it's also easily extensible because you can build new versions of system service. To cater to the needs of specific applications. But on the other hand, it fails on the safety attribute. Because there is no boundary separating the kernel from the user space. A micro-kernel based operating system also. Pays attention to protection because it makes sure that the applications and the servers are in distinct hardware address spaces separated from the microkernel itself and it is also easily extensible because you can have different servers that provide the same service. But differently to cater to the needs of the application but it may have performance flaws because of the need for so many border crossing that might be needed to go between applications and the server processes. Having said that I want to give a note of caution, on the surface it may appear That the microkernel based approach may not be performant because of the potential for frequent border crossings. I'll have a surprise for you on this aspect when we discuss the L3 microkernel later on in this course module where it is shown that a microkernel. Can be made performant by careful implementation, that's the key. I'll leave you with that thought, but we'll come back to a micro kernal base design using L3 later on.
Here's another way to visualize the relationship between these different attributes that I mentioned of performance, extensibility and protection or safety. A DOS-like structure that does not pay attention to safety or protection, needs the two attributes of performance and extensibility. A micro kernel based approach achieves protection and extensibility, but may have issues with respect to performance. A monolithic structure may yield good performance, has protection. But, it is not easily extensible. Now what do we want? Of course we want all three of these characteristics in an operating system structure. But can we have all of these three characteristics in an operating system? In other words, what we would like the operating system structure to be such. That, we get to this, center of the triangle that caters to all three attributes. Performance, Extensibility, and Protection. And the research ideas that we will study in this course module. Is, looking at ways to get to the center of the triangle so that all three attributes can be present in the structure of the operating system. We will resume the course module with research approaches that have been proposed than that we will cover in this course module that help us get to the middle of the triangle.