English | 中文 | Русский | Français
2,590 Posts served
8,335 Conversations started
This is the fourth and last part of this article. Previous parts surveyed Windows User Mode and UNIX. Part 3 of this article covered Windows Kernel.
The discussion is how parallel are these operating systems and we save the best for last: This last part of the article raises a surprising question 'Is DOS the ideal parallel system?'... or is this question really that surprising?
DOS
The old DOS operating system is rarely ever used but we can still find it today for simple slim applications such as Windows CE pre-boot loader menu and whenever we use Windows 98 / ME. The name DOS stands for Disk Operating System which indicated that it could work with disks at a time when personal computers could use only ROM loader and sometimes ROM based Cartridges (something like a bootable disk-on-key with 32KB of read-only memory).
DOS was designed specifically for Intel's X86 processors at a time when Floating Point operations came as an external chip and was considered an accessory. The year is 1981 and a PC that has a multicore CPU makes as much sense as an ice cream for a database. (If you are reading this in the far future, currently we are still not using ice creams as database engines).
DOS is an over simplistic operating system that was designed very long ago. It does not support multiprocessing API, does not have locking mechanisms, does not support dynamic linking and code reusability, and is not object oriented. In fact in a DOS application most C library functions are only wrappers for system Interrupt calls. Everything in DOS is done by use of an Interrupt. Reading a character from the keyboard, writing a string to the screen, opening a file, moving the cursor, setting system time, and anything else an application can perform is done by calling a CPU Interrupt.
CPU Interrupts are a special mechanism that was added to the CPU in order to service hardware peripherals. When the keyboard has a new key-press event it will Interrupt the CPU by signaling on a dedicated pin of the CPU Chip. The 8086 CPU was very advanced at the time and a signal on the INT pin will make the CPU stop and ask the hardware what is the ID of the device that generated the INT request. We can still see this today on Windows XP's device manager – some of the devices have a tab called "Resources" and in it you can find the value of the IRQ – Interrupt Request. Every Interrupt number has a special Interrupt handler which is a function. The 8086 processor supported 256 interrupt numbers (Vectors).
The computer's ROM for the 8086 is called BIOS. It was the first thing to load and initialize the CPU. The BIOS was also responsible for any hardware functionality because there were no installable drivers for the basic devices such as display adapter and motherboard. Higher level software (such as operating system and applications) communicated with the BIOS by using the same Interrupt mechanism. The software would issue a Software Interrupt" which basically means asking the CPU to call the Interrupt handler function by the vector number. The CPU has an array of 256 function pointers and issuing an Interrupt means calling the function by its index in the array. For example you would initiate Interrupt 29 to query video card information. For extensive information about Interrupts see Ralf Brown's interrupt list – an amazingly valuable resource for working with interrupts.
There are three types of Interrupts: Hardware Interrupts are generated by hardware devices issues by a signal to the processor's INT pin, Software Interrupts are issued by drivers by executing the INT instruction, and CPU Interrupts which are generated internally by the CPU in reaction to extreme conditions. For example the CPU generates an Interrupt to escape from an infinite internal loop of dividing by zero, or for interrupting an instruction that violates access rights. The first two types on Interrupts are only for system kernel and CPU generated interrupts are sent as Exceptions to the user application.
The DOS operating system uses the same methodology as BIOS did. When you want to call a system API in your DOS application you issue INT 33 (21 hex). The DOS operating system installs the handler for interrupt 33 and every call to INT 33 is handled by DOS. Parameters are sent in CPU Registers. For example INT 33 with parameter 44 will return the current system time.
A DOS application is never parallel. You cannot have more than a single task running in the system. This is logical because there is only one core of CPU. Multitasking on one core is accomplished by stopping the running process and scheduling another one on the same core. The majority of operating system, Windows included, schedule processes by process and thread priorities. Every process and thread has a priority value and the system decides which process should run according to its priority value. The problem with this model is that processes perform different tasks. Some of the tasks are high priority and some are not. The solution is dedicating a thread for every task, so for example there is a thread that reads from the network in high priority and another thread that writes to disk in low priority. Setting process and thread priorities is a major part of system design.
DOS does not support multiple tasks but there was only one core on the CPU so there was no performance reason in re-scheduling.
However, DOS was written at the lowest levels and is closely coupled with the hardware by design. The hardware is and always has been extremely parallel. Hardware Interrupts are handled by the CPU by priority - lowest first. When the CPU is handling Interrupt 15 and Interrupt 14 is signaled, the CPU will stop working on interrupt 15 and immediately start working on interrupt 14. This is why it is called an interrupt – because the CPU is interrupted based on priority.
It seems that DOS is based on very good parallel foundations. DOS also provides API that installs new interrupt handlers. You create an application and set it as a TSR – "Terminate Stay Resident", which means that the application runs from start to end and after it exits it stays in RAM waiting for Interrupts to occur.
Now let's turn DOS upside down:
We run a simple application. This application is of course single task, single thread. This application is equivalent to the Idle Process in parallel systems. Whenever nothing else runs this process is active. This process does not have to consume CPU and can sleep, wait or HALT (CPU instruction).
Advanced operating systems use threads with different priorities to make sure that important tasks are run before the lesser ones. Here, instead of allocating threads for every operation and setting thread priority we set Interrupt Handlers to perform the operations, so that every task has a dedicated interrupt handler and therefore has a clear priority. Every operation that the application performs has a clear priority. For example the application's handler function for keyboard input has lower priority than the timer's handler function. These examples are hardware events but we can also implement software functionality with these handlers.
Write a simple console application with multiple functions, just like we are used to. Now, every function has a priority between 1 and 255. Every function has four parameters but you can pass pointers to structs that hold more data. Once you pass data to a function you can no longer touch this data, so the function becomes the only owner and therefore no need for locks. There can only be a single owner function for every resource, memory buffer, hardware device, dick file, etc. When you want to read from this resource or write to it you call its handler.
Since every function is only called by issuing an interrupt - there is true priority ordering between operations in this application. Every operation is stopped when a more important operation is pending and when this is complete, the original operation resumes. There is some problem with that: Operating Systems today have a mechanism called "Priority Inversion" that kicks in when a low priority thread owns a resource that a high priority thread requires. The mechanism raises priority of the lower thread so it can keep running to the point when it releases the resource (such as lock object) that the higher priority thread is waiting for. In our case we allow handlers to call other handlers so for example handler number 45 can issue interrupt level 23 or 66 without worrying about priority. Only hardware interrupts really stop execution. This way we start the operations in the right priority according to the issuing hardware but a keyboard interrupt can be anything from 'type a char' to 'immediately cancel the long operation'. This means that we need some method of making sure that the operations are kept in their logical priority, but DOS does not support this and we need to add some management. For example any hardware handler can verify the priority. If it is higher than the running task then it will start execution. If it is lower than the running task then it will push to tasks queue (or manipulate the process's stack by pushing another return address).
The software design of a parallel DOS system is very good but we are missing the Operation State management which can only be single task – stack based (anything else we need to manage manually). Another problem is that the priority based operations only work with hardware events and anything else has to be manually managed. So – we have some very good design but no real system support for it, both in hardware and software layers.
Is DOS the ideal parallel environment?
DOS is really close to the hardware and the hardware has always been extremely parallel. The basic system design is extremely parallel, but the parallel engine is only implemented for the hardware and not for the software. So 'Yes' DOS supports a very advanced application design, but 'No' the CPU does not fully implement the functionality required for this design to really work.
The reason I wrote this very long article is so that we watch and learn from systems that are closely coupled with the computer's hardware because the hardware has always been parallel. We still learn how to write parallel applications when hardware related code has been working in parallel since the first Intel 8086 based machine was manufactured.
This is the final part of a four-part article that covered existing operating systems and their parallel design, with advantages and faults.
The concepts brought here are given as background for a new software design model called Operation View Model.
| October 30, 2008 3:12 AM PDT
UX-admin |
"Multitasking on one core is accomplished by stopping the running process and scheduling another one on the same core." This is also not entirely correct: you left out DMA. Notably, the i86pc architecture didn't have much of one, but one could program the DMA to execute tasks (graphics, audio, I/O) while CPU would just be a dispatcher, so one could have multiple processes running at the same in parallel. The hardware would of course raise the IRQ line high (or low, depending on the implementation) when the DMA ran out of data, but as long as the DMA was active, it ran in parallel to the CPU, memory bus contention notwithstanding. One example of a single core system that did this is the Amiga, and the modern PC fully utilizes that concept (albeit almost 30 years later). |
| October 30, 2008 12:24 PM PDT
Asaf Shelly
|
As for the first comment: This was probably performed by hooking the sound card interrupt and responding to incoming buffers (or audio card internal clock events), or by hooking PC timer interrupt and periodically executing the short audio task and then completing the interrupt to return to the main application. In a way I agree about programming skills today but I think that this was always the case. Even 30 years ago, with difference that at that tine you could not work without fully understanding the system and having a clear design. |
| October 30, 2008 12:31 PM PDT
Asaf Shelly
|
As for the second commnet: I do not consider DMA as another process. The DMA can perform some hardware acceleration howwever you cannot execute CPU code on it. This is similar to the hardware acceleration on the keyboard that keeps 16 typed keys in a buffer, not only one. Whenever you see "hardware acceleration" and "offloading" there is a hardware component that does something in parallel to the CPU without being able to execute CPU instructions. |
| October 31, 2008 1:55 AM PDT
UX-admin |
Perhaps you are correct as far as the i86pc platform goes, although that's debatable, since tools like NVidia's CUDA C compiler turn a GPU (which has her own DMA) into a high-performance, generic processing CPU. This was also the case on the Amiga, where some folks wrote some clever code to utilize the Blitter hardware (which *of course* had his own DMA!) to do general-purpose calculations, whereby the Blitter was being used as an accelerated number crunching facility. And if one can do general purpose calculations, then one can use the hardware as a regular CPU! All it takes is some imagination, and clever programming, and one can repurpose otherwise specialized hardware for a generic purpose, thereby running regular processes on "non-regular" processor. The delineation is a 'Gray area' at best. |
| October 31, 2008 2:01 AM PDT
UX-admin |
"In a way I agree about programming skills today but I think that this was always the case. Even 30 years ago, with difference that at that tine you could not work without fully understanding the system and having a clear design." It was a happier and better age as far as computing is concerned, than is the case today. We didn't have hardware as powerful as we do today, but by and large, people who worked with computers did so because they loved computing and computer science, and were both professionals and enthusiasts at the same time, not the armies of overpaid, incompetent charlatans working in "IT" that don't care one bit about IT and CS come 17:00, and want nothing to do with computers outside of getting a pay slip. |
| October 31, 2008 9:19 PM PDT
Asaf Shelly
|
Yes, I see your point now. So it wasn't just the DMA, it was the acceleration hardware that was connected through it to RAM. The Amiga had an advantage that the hardware has clear specifications. PCs today (and back then) are able to use any type of expansion hardware such as display cards. This means that you cannot base your code on a hardware that might not be there. This is why Direct3D also has software emulation. CUDA is an attempt to create a generalized interface to video acceleration hardware. Let's hope that it works and maybe in 10 years the OS will see a collection of CPUs and utilize them in the best possible way. As of now we still don't have the programming language to do so. It should also be noted here that the CPU can operate acceleration hardware such as the FPU and MMX (which are now internal but still behave as external), however this interface makes the CPU wait until operation is complete and will not work in parallel to CPU instruction (thus making it thread safe). As for the 'happier days', it was so frustrating that you had to enjoy to be there. In our world we need the worker armies as you call them, as much as we need the artists. Until someone comes up with a better technology we need every man and woman drafted :-) |
| March 4, 2009 4:02 PM PST
a | i dont see a fundamental difference between dos and windows. in windows teh application is free to do whatever it likes as it was the case under dos. you dont need interrupts to do such kind of processing. the reason that under dos programs were simpler is that they were doing less stuff! |
| March 24, 2009 8:49 AM PDT
Asaf Shelly
|
Hi a.. Windows is using protected-mode with is a half-way to virtualization. Windows does not handle Interrupts at all. It is the Windows-NT Kernel that handles Interrupts, which is an alltogether different system. Windows and Win32 API handle System Events (this is the same for Windows CE btw.) DOS handled Interrupts directly and applications used Interrupts as a way to communicate with the system. Windows users file system operations. Best, Asaf |

UX-admin
Technically, that is not true. Some MOD players under DOS were programmed to play the MOD and return the DOS prompt, so that the music would be playing in the background and the user could continue working.
This did however require a high understanding of how an i86pc platform architecture worked, and it required cleverly written programs, so it wasn't a widespread practice.
The problem was, and still is today, very few people on this planet have the mindset required to program computers in clever ways.