69

Windows in its earliest days was simply a shell that ran on top of MS-DOS, which means that Windows 3.1 itself was actually just a standard MS-DOS application like any other.

Yet, MS-DOS is not a multitasking operating system, and at the same time, Windows applications were compiled native-code binaries that ran without any form of managed environment. So, how exactly was multitasking of Windows binaries achieved if Windows 3.1 was simply a regular old MS-DOS program itself? Are there any old technical documents still floating around that describe the early Windows architecture internally?

  • 11
    Not entirely true. Windows 3.1 would switch the processor to protected mode, which allowed memory segmentation and other goodies that helped manage a multi-process environment. It was not simply a "MS-DOS application like any other." (Thus, it required at least an 80286 processor for those features) – Joe Jun 7 '16 at 23:43
  • 4
    Joe, windows 2.x and 1.x don't switch to protected mode. Even on windows 3.0 was "optional". – Zardoz89 Jun 8 '16 at 5:22
  • 6
    @Joe Windows actually emulated "protected mode" if it wasn't available. It only really went "hardware protected" with preëmptive multi-tasking on a 386 CPU (not 286), and even then, it consisted of multiple virtual machines, some of which were "real" (for MS DOS applications) and some of which were "protected". Depending on your hardware and software configuration, Windows came all the way from "a thin GUI client on top of DOS" to "a full blown preëmptively multi-tasked OS that just happens to be started from a DOS loader instead of a bootloader". – Luaan Jun 8 '16 at 8:57
  • 7
    Raymond Chen has written a lot about how old versions of Windows worked on his blog, The Old New Thing. I recommend a perusal of the history tag on The Old New Thing. – a CVn Jun 8 '16 at 13:37
  • 4
    MS-DOS doesn't help programs multitask, but why do you think MS-DOS programs can't have their own multitasking? – immibis Jun 8 '16 at 23:07
64

For Win16 programs, Windows implemented co-operative multitasking. Its implementation was based upon the "message loop" architecture of every Windows program.

The duty of every program was to endlessly run in a loop in which a call to GetMessage() function was performed. This function call looks whether a message to this process is in the queue. If there is one, it is retrieved (GetMessage), optionally translated (TranslateMessage, done to convert keyboard shortcuts into menu actions) and finally, passed to the window procedure (DispatchMessage).

If there is no message available in the queue, Windows suspends the current task and gives the CPU to another task. This task will try to retrieve a message from its queue as well, yielding the CPU to another task if no message is present and so on.

If a program needed to perform background tasks while there was no pending messages in its queue, it would call PeekMessage instead of GetMessage. This didn't make the task relinquish the CPU, as PeekMessage would immediately return to the caller task to inform it whether a message is available or not. This was used to time-multiplex message processing with another time-consuming task (think of a 3D program rendering but letting the user cancel that render by pressing a "Cancel" button).

If this time-consuming task was actually very time-consuming, a well-behaved program should call the yield() function from time to time, to relinquish the CPU and let other task to run.

A badly-behaved program could easily hog the CPU by not retrieving messages too often or by spending too much time in a window procedure function.

The situation was quite different for MS-DOS boxes. They ran using the V8086 mode of the 80386 (if Windows was running in enhanced mode). Windows-aware programs ran in the so-called VM 0 (Virtual Machine 0). DOS boxes ran from VM 1 upwards.

DOS programs usually were badly-behaved programs, so Windows assigned each DOS box a different virtual machine. Virtual machines used pre-emptive multitasking in Windows 3.1, so each DOS box could run concurrently of each others and concurrently to any Windows-aware program.

  • 1
    MS-DOS programmes could be made aware of CPU sharing. The TSR functionality enabled a form of co-operative multi-tasking. – Chenmunka Jun 8 '16 at 10:01
  • 2
    In MSDOS Int 28h worked as an idle call when it was waiting for input. Also when running with DPMI hosts (such as windows 3.x) you could call int 2fh function 1680h (Release current virtual machines time slice) I added these to a Dos based application to improve the performance when running under Windows. (exact details may be wrong it's over 20 years ago now) – PeterI Jun 8 '16 at 14:07
  • 4
    A TSR program didn´t have to do anything with multitasking. They usually intercepted some DOS or BIOS vector so they would be triggered by some event (press a hot key, the timer interrupt, activity on the disk, etc). About int 28h and int 2Fh, those mechanisms came into scene when Windows was marketed. Before that, many DOS programs were made so no one of them was aware of such added functionality. Instead, programmers learned soon how to directly write on the screen, read keyboard, etc, making the DOS world a wilder place than the old west... – mcleod_ideafix Jun 8 '16 at 17:04
  • 2
    ...Those system calls of course helped DOS programs to behave a little better in the new Windows world, but the majority of them, just didn´t use them. Anyway, my answer has been edited to not to cause misinformation :) – mcleod_ideafix Jun 8 '16 at 17:04
  • 2
    As someone who tried to take advantage of that multiple DOS box thing - it wasn't as stable as one might like. I presume due to all the weirdness that DOS programs were wont to commit, the system had a tendency to get crash when running multiple DOS boxes. – Michael Kohne May 21 '17 at 2:21
40

Found a great answer on Super User that explains it really well!

Windows 3.1 uses cooperative multi-tasking – meaning that each application that is in the process of running is instructed to periodically check a message queue to find out if any other application is asking for use of the CPU and, if so, to yield control to that application. However, many Windows 3.1 applications would check the message queue only infrequently, or not at all, and monopolize control of the CPU for as much time as they required. A pre-emptive multi-tasking system like Windows 95 will take CPU control away from a running application and distribute it to those that have a higher priority based on the system’s needs.

Source: https://superuser.com/a/726367/541767

  • 5
    HTG just scraped Superuser for that article. The original is at: superuser.com/questions/726348/… – Dan Neely Jun 8 '16 at 11:25
  • 5
    "A pre-emptive multi-tasking system like Windows 95 will take CPU control away from a running application and distribute it to those that have a higher priority based on the system’s needs." -- this bit is only half-true, windows 95 premptively multitasked 32-bit code but it cooperatively multitasked 16-bit code and it was sufficiently reliant on 16-bit code that freezing the 16-bit side would freeze the whole UI. – Peter Green Jun 8 '16 at 13:30
  • 2
    @Peter: »reliant« is a string word here. Windows 95 tried hard to keep 16-bit applications in the illusion that they are in complete control of the computer. That's why there were a lot of hooks that routed Windows-native things through old 16-bit layers when necessary to allow old things (e.g. DOS device drivers) to still work. Those were often the places where a 16-bit application could stall or crash the OS. However, it's not so much that Windows needed those 16-bit parts to run, nor did 32-bit Windows applications. As far as I know they were only active when a 16-bit program was running. – Joey Jun 9 '16 at 7:43
  • 1
    @Joey - no, the graphics subsystem on Windows 95 was (entirely) still implemented in the 16-bit GDI and User DLLs; the 32-bit APIs were implemented through thunks to the 16-bit libraries. That also meant every GUI interaction required the global lock for running 16-bit code. – Jonathan Cast Mar 7 '17 at 7:12
  • @joey The entire 16 bit subsystem ran in a single thread in Windows 95. and the GDI was also 95% identical to the Win3.1 GDI and therefore 16 bit. In order to give the GDI and the 16 bit apps the illusion that they were running in Win 3.1, there was a single global lock that was taken by 16 bit apps and 32 bit apps while they were calling into the GDI.If any process hung while holding the lock, the entire graphics display would freeze, giving the illusion that the machine had frozen. – JeremyP Dec 5 '17 at 9:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.