Suppose we start with a very simple model of a computer. In this model the computer can run only one program at a time. So theoretically, we do not even need an operating system since the single running program can have complete control of the whole machine. But there is still a good reason to have an operating system. We would like any program that we write and run to be able to use all of the features of our computer, i.e., the various disk drives, the network connection, the printer, the graphics hardware, etc. We could incorporate all of the code needed for every one of these devices into every one of our programs. But this would be a nightmare. For one thing, we would need to know a great deal of detailed information about every device in the computer and then write quite a bit of fairly complicated code for each device. And if we went out and bought a new video card or a new printer, then we would need to rewrite all of the video and printer code in every one of our programs. This would not be an acceptable situation (see also Section 1.1.4, pages 7-8, of our textbook). A better idea is to have an "operating system" that is a collection of code that takes care of all of the hardware devices in the computer. For each hardware device in the computer this "operating system" would have a piece of code (called a "device driver") that knows all of the details of how to handle that particular hardware device. When we write a program and the program need to use some physical device, say a CD-ROM drive, we write the program so that it "calls" the CD-ROM's device driver. Each device driver will present a standard "interface" to our application programs. The interface defines what "calls" are available from the device driver and what each call does (like find a certain block of data on the CD-ROM drive or read a block of data off the CD-ROM drive; see, for example, pages 5-6 of our textbook). We would write our application programs so that they use this standard interface (and so that they therefore do not need to know the details of how this interface is actually implemented). If we go out and buy a new device, say a new video card, then we have to write a new device driver for the new card, but the device driver should still provide the same interface to our application programs (so that the application programs do not have to be rewritten for the new video card). To put it briefly, in our simplified model for a computer the job of our operating system is to provide our single program with an abstraction of the hardware in the machine that the program is running on, so that our programs can be more easily written and maintained. So even in our simplified model for a computer we need an operating system. When we run a program on our computer, in the computer's memory there will be our (single) program and the operating system (consisting of all the device drivers). Here is one way to organize this program/OS in the computer's memory. We can divide the computer memory in half and dedicate half the memory (say the lower half) to the single program and the other half to all of the operating system code. In this model, all of our program and all of the operating system are loaded into the computer's memory all of the time but the program and the operating system are kept separate from each other and the program "calls" the operating system whenever it needs some service done for it. Now here is another reason why we would want to have an operating system. Suppose that our computer has 128 MB of RAM. So in our model half would be dedicated to the program and half to the operating system. But that leaves only 64MB of memory for our program. What if we need to run a program that needs more memory (like an image or movie editing program)? We could go out and buy more memory, but there should be a better way to allow us to run programs that require more memory than is actually in the computer. One idea would be to have our large program divided up into several segments (sometimes called "overlays"), each of which can fit into the available memory. Then when we run the program, we start with one of the segments and that segment will, if needed, load one of the other segments on top of itself and let the other segment run. As our program runs, it would load segments (from the hard disk) and run one segment at a time. This way, our program could be as large as we want. But we have to write the code that finds and loads the segments and we need to put this code into every one of our programs. And if we go out and buy more memory, then we may not even need the segments anymore and they just needlessly slow down our program. Even worse, if we try to run our program on a computer with less memory, then our segments may be too big for that computer and we will be out of luck. A better idea than having to segment our program would be to extend our "operating system" to include code that implements a "virtual memory system". A virtual memory system essentially automatically segments our program for us (the segments are called "pages") and the virtual memory system automatically loads these pages as they are needed. Our virtual memory system could be written so as to fool our program into thinking that it has a large amount of "memory", say 4GB (which is 2^32 and the 32 comes from the fact that the Pentium is a 32-bit CPU). Half of this memory can still be dedicated to our program and the other half to the operating system (which now includes both the device drivers and the virtual memory code). (Note: This simplified model of a computer is actually the model that the Microsoft Windows NT and Windows 2000 operating systems creates for every program. Every program (i.e. process) has its own "virtual computer" with 4 GB of "virtual memory", half of which is dedicated to the single process running in this virtual computer and the other half dedicated to the operating system. In effect, every program thinks that it has a whole computer, the "virtual computer", all to itself. Notice that every process also thinks it has its own copy of the whole operating system code, but in fact, a single copy of the operating system code is shared between all of the running processes.) So now we have two jobs for the operating system in our simplified model of a computer. To provide our single program with an abstraction of the hardware that the program is running on and to provide an abstraction of the computer's physical memory so that the program can belive it has as much as 2GB of memory, even when the physical memory is much less. To be continued ... |