15

Back in the MS-DOS days, there was a program DoubleDOS that you could run that would split your machine in half and multitask two separate DOS programs. While it didn't particularly work well for games (as far as I remember), it was popular for system operators of bulletin board systems.

How did DoubleDOS work? I know that I had used it on 8086 machines back in the day which I don't believe had many of the real context switching capabilities that modern CPUs use to support multitasking. Was it simply hooking up to an interrupt and storing session 1's CPU registers, context switching, restoring session 2's registers, running and then running until the next interrupt? Was memory space adjusted accordingly or did programs which didn't go simply through DOS and the BIOS fail to operate?

(it has been a loooong time since I've used it, but another question just ignited an old brain cell :-) )

  • 6
    Context switching at its heart is a very basic operation, it just requires saving the current CPU register state for the current task and restoring the CPU state for the new task. So an 8086 CPU was capable of that, just like you describe with interrupts. What it wasn't capable of was enforcing a partition between tasks, or creating an environment where each task would appear to have machine to itself. So if two programs tried to write to video memory at the same time they be writing to the same screen and overwriting each other. – Ross Ridge Jun 28 '17 at 17:44
  • 2
    Plenty of context switching on any PC for hardware interrupts. But video and plenty of other issues as @RossRidge notes. I suspect it relied on bank-switched memory > 640k, which few programs (except Lotus 1-2-3) could do much with in the early days, so even limited multitasking was a good way to make use of extra memory. – manassehkatz Jun 28 '17 at 18:34
  • 2
    Interesting question! This would actually be fun to disassemble as a weekend project, if only I had a copy! Problem is, the resulting analysis would more likely be book-length than answer-length. The concise answer is basically what Ross has already said, which we can get by pure speculation. – Cody Gray Jun 28 '17 at 19:43
  • 1
    I'm curious how the memory management would have been done. Did DOS programs respect some kind of system heap manager or memory allocator that could be used to load two programs simultaneously and ensure they don't try to use the same memory space? IIRC, some DOS task switchers worked by snap-shotting RAM to disk while switching contexts. Not sure how it knew which chunks of RAM needed to be swapped. – Brian H Jun 29 '17 at 0:08
  • 1
    @BrianH MS-DOS 2 and later allowed programs to allocate and deallocate memory. It also allowed multiple programs to be loaded at once, a program could execute another program. This was all single-tasking however, the first program had to wait until the second terminated. (In MS-DOS 1 programs owned everything from start of their program to end of memory and pretty much had to load and execute other programs itself if it wanted to do that.) – Ross Ridge Jun 29 '17 at 18:14
7

Jwzumwalt already covered the basic, being not much younger I might add a few minor details still present to me.

While it didn't particularly work well for games (as far as I remember), it was popular for system operators of bulletin board systems.

It was perfect - well, let me rephrase this as rather useful - for well behaving (read no direct hardware access) programs to have two programs at hand. Like a BBS operating in the background while being able to do maintenance tasks at the same time.

How did DoubleDOS work? I know that I had used it on 8086 machines back in the day which I don't believe had many of the real context switching capabilities that modern CPUs use to support multitasking.

In general the process is the same on each and every CPU ever developed. To switch all CPU-states visible to a user task need to be exchanged. Some CPUs may offer special modes for special cases (like the second register set in the Z80) or instructions to store the whole state (or most of it) in a single operation. Still, it has to be done.

Also with a primary single taking BIOS/OS combination, several memory regions need to be swapped - just think of things like cursor position.

Same with screen memory. If there's only one screen adapter, the content needs to be exchanged. Otherwise one would not be able to see the output of the background task when switched up.

Was it simply hooking up to an interrupt and storing session 1's CPU registers, context switching, restoring session 2's registers, running and then running until the next interrupt?

Exactly like that. The basic task switch was done via a timer interrupt. To make it work some additional precaution had to be taken. For example monitoring entry to certain BIOS and DOS interrupts. As well as handling BIOS for I/O related functions. This is necessary since no (at least not many) DOS/BIOS functions are designed for reentry (i.e. two tasks running thru the same code). So DoubleDOS had to keep the tasks from doing so.

For example, if the timer interrupt (08h) fires while the active task issues a DOS function, it will be ignored. Prior to DOS 2.0 DoubleDOS did this by hooking Int 21h and setting a marker of their own, while with DOS 2.0 the InDOS Flag got introduced to sign when it's safe to (re)enter DOS (*1).

Was memory space adjusted accordingly

DoubleDOS was really build around the Idea of splitting a machine into two by partitioning memory. It wasn't really a taking system with dynamic memory assignment. At startup (or if no program was running in either task) available memory was to be split um in two regions and kept that way. Beside being the prime idea, it also avoids hassles wit programs manipulating the memory they assume to be entitled to.

or did programs which didn't go simply through DOS and the BIOS fail to operate?

There are zillion ways to screw operations, and computers really enable them :)) It depends on the way of switching and what kind of 'bypassing' DOS/BIOS had been used. The most important issue here is usually the screen content and keyboard. Programs accessing both directly did only run well in foreground. In background they may at best just screw up the front tasks screen and steal input.

In contrast 'well behaving' programs, using only DOS and BIOS could even continue to produce output in background. Same for Printers and serial lines (*2). In fact, I remember that somehow up to 6 'tasks' could run at the same time. Two real tasks, while the other being specialized like print spoolers.

In reality, many programs 'less than behaving' programs fail due to direct screen access. At the same time the majority do wait for user interaction at some point and don't issue any screen update when switching. So putting them in background won't do damage beside wasting CPU time for an idling application.

Then again DoubleDOS did offer a ways to get around that to a certain degree by setting the background execution to halt. So when foreground and background switch, everything gets saved and the program stops operation (*3).


Addendum 1: Time slice handling

It might be interesting to add the ways of handling time attribution to each task.

  • 2:1 Foreground/Background
  • 1:2 Foreground/Background
  • 1:1 (equal time)
  • 2:1 Upper/Lower Program
  • 1:2 Upper/Lower Program
  • Full time for Foreground

Addendum 2: Multitasking (and TSR) hooks

With DOS 2 a lot of hooks where designed into DOS to enable multitasking - much the same way as the AT BIOS introduced similar measures. From there on it was rather straightforward to build a tasking layer above DOS/BIOS. And Windows is maybe not the least example to do so.

On BIOS side this includes several functions to allow an OS independent protocol to detect and handle critical sections and process task swap. With the SysReq-Key even an OS independent user interaction was designed.

DOS added not only InDOS via Int 21h Function 34h (?), but also INT 28 to give a switching point/activity entry during idle. Beside InDOS function 34h also introduced an error flag which could be used to make the active DOS function fail in a (somewhat) orderly fashion. This again could be used in conjunction with the Error Handler at Int 24h(*4). To speed up the process. Int 23H also added the CTRL-BREAK handling as an entry point for task switchers/OSes due user request.

And then there was Int 2Fh, the MUX-Services. A collection of hooks mainly added by TSR utilities like PRINT, but also various versions of DOS (and various DOSes). There where functions from ASSIGN to PRINT over network and CD handling to a countless number of services provided by Windows, VM-Ware and alike. COMMAND.COM's command line handling being not the least :))


*1 - There are some function, especial the Character I/O which are usually safe to be used while InDOS is set.

*2 - Ofc. only if both tasks are not trying to access the same device on a character base - that is single byte (or line) output via DOS/BIOS. As soon a utility like PRINT was used even sharing a printer on job base was possible.

*3 - Not really desirable for a BBS, isn't it :))

*4 - Right, that's the one where the infamous Abort/Retry/Ignore/FAIL is displayed.

  • 1
    It's worth pointing out that MS-DOS 4.0 (sold by ICL and a few other european customers) multitasked in a similar fashion. en.wikipedia.org/wiki/MS-DOS_4.0_(multitasking) has the details. – PeterI Jan 29 '18 at 13:27
  • Jup. To bad it didn't get promoted better. Unlike DoubleDOS it did offer to run more than two programs and allowed (somewhat) dynamic memory assignment. It was in many ways more like ConcurentDOS. – Raffzahn Jan 30 '18 at 15:10
  • I remember vaguely of having problems with DOS 4.0... – Rui F Ribeiro Feb 1 '18 at 10:47
6

Multitasking is absolutely not depending on modern CPUs like the 386 or anything - Those CPUs go one step beyond and protect multiple tasks from each other, while earlier MT OSs had to rely on behaving applications.

I co-wrote a multitasking system for x86 based on Turbo Pascal 5 and running from DOS for industrial control applications back in 1990. You "simply" set up a scheduler that was driven by one of the PC's system timers and interrupted the running task, stored all of that task's register contents onto the task's stack and restored another task for some time slices. I think we needed only one single assembler file and wrote all the rest in TP. Last time I looked they still had some machines running that OS.

  • Somehow I can't figure out why this seams so well known :)) Ok, given, I usually did all in Assembly - less hassles to write :) – Raffzahn Jan 28 '18 at 15:04
5

I'm 61yrs old and my memory no longer serves me well but I do remember a few things about DOS. I purchased a book in the late 80's that contained a less optimized free version of DOS. That version of DOS (I can't remember for sure but I think it was MX-Dos) was very close to Caldera/DR-DOS and somewhat like FreeDos. (I suspect FreeDos is based on it) It included multi-user login, task switching, and several tools similar to QDos (cpm variant), DoubleDos, and QEMM. The book provided a short summary of every Dos C procedure.

There were also several excellent asm books written by Tom (edited) Swan on how task switching was accomplished. I eventually purchased about 15 of his books and he regularly contributed to Byte magazine. He wrote about 150 asm utilities that where published and given to Byte readers for free.

(As has all ready been pointed out, a TSR is a crude form of task switching - most lacked time slicing and live independent video support.) Exactly how the task switch was handled depended on the CPU mfg. Machine state was saved for the task switching but the details were different.

As mentioned by several folks above, all computers used TSR's for all BIOS i.e i/o intercept. For Intel CPU, the 80xx memory segment pointers would be saved and loaded appropriately for each task switch. The 80xx has extra hardware clock registers and software timer interrupts would trigger the task switch according to time slices. The 80286 and later chips supported better multitasking with specific registers designed for task switching.

enter image description here

The Z80 machines where even easier (I owned several), the Z-80 has two complete sets of registers and a single asm command will swap between them which made handling two OS environments a breeze. The Z80 has a dedicated external timer chip with 4 "counter/timer channels" (CTC) attached that could be software programmed for a software interrupt task switch - time slices.

enter image description here

An interesting bit of Z80 history... The two register sets where specifically provided to assist in easy interrupt handling but most programmers were scared of getting the wrong register set mixed so the mirror register set was almost never used.

I have no idea how the 6502 & 6800 CPU was handled. Now, back to DoubleDos. Programs could be run in two modes, with or without i/o and screen support. The video was a challenge because DOS machines lacked extra memory so switching video in and out was very slow and consumed a big chunk of the limited 64k program memory block (later extended XMS memory drivers got quite good at freeing lower program memory). There was not any virtual video memory (frame buffers) so all video had to be done on the actual physical video memory. Also, the video chip was accessing video memory live and any DMA had to be halted during the video read cycles.

Programs set to run without screen support ran almost transparently. Both the Z80 and 80xx had DMA but copying large blocks of memory at 4-8mhz caused significant flickering.

I do not remember the task switching rate, it seems to me that was user selectable to some degree. But, flicker was noticeable because everything had to swap live physical memory. The background program had to save the foreground video, load the background video, allow the background program to access physical screen memory, save it, and reload the foreground program video again. That was asking a lot from a 16bit CPU. Later, larger capacity video cards had "bit blasting" capability which was optimized DMA video memory manipulation and that almost eliminated the flicker.

It did not have resource tokens or arbitration so two programs sending output to a i/o device like the com port or printer would end up with gobbledygook. There where some clever folks that made add on print spool drivers, but DoubleDos did not manage it internally; or at least the early versions did not support it. Because there were no resource tokens there could never be deadlock. It was pretty much bullet proof except for an occasional TSR locking up. There was significant development between versions but MS deliberately killed it with pseudo task switching and a more powerful XMS manager in Dos 5 & 6.

Quarterdeck Deskview arrived and immediately surpassed it. DoubleDos died a very quick death shortly after the first DeskView release. Deskview had pretty much unlimited task switching, print and com spoolers, the best virtual memory manager, and 20 or 30 utilities; all for slightly more money than DoubleDos. Third party developers immediately wrote compatible games and utilities for it. For some reason DoubleDos never received third party support.

  • Erm, you might mix something up here. DouebleDOS on the Z80, or more specific for the TRS-80 was a modified TRS-DOS as supplied by percom for their double density controler board. There is no relation to the PC product in question. In fact, DoubleDOS is such an easy idea for a name, that it also has been used for an Apple add on that allowed a cold boot of DOS 3.2 (13 sector) or DOS3.3 (16 sector) and later with the flip of a switch. I wouldn't be surprised if many more companies had used that name. – Raffzahn Jan 28 '18 at 19:17
  • I never owned a TRS-80. I had several home-brew S-100 and several Exidy Sorcerer's which ran QDOS (CPM) and PC-DOS. PC-DOS on Z-80's was very common and very easy to export. All you had to do was reassign your hardware ports to the software BIOS interrupt calls. Which is the same thing Bill Gates did to Gary Kildall's QDOS CPM. CPM was exactly the same as DOS including 22 identical interrupt calls with the exact register same vars doing the same thing. I think Gates plagiarized CPM in 3-4 days. It didn't take long for IBM to settle with Kildall. Once folks knew how, it could be done in a day. – jwzumwalt Jan 28 '18 at 21:05
  • 1
    Well, non the less there was never a taskswitcher called DoubleDOS for the Z80. Also, Gates didn't have to plagiarize CP/M, as that job was done by Seattle Computer Product. Not a secret as buying a licence for QDOS as it was called then is part of the official history. I'm somewhat puzzled what kind o 'PCDOS' you might have had on your Sourcerers (also got on back then) or other 8 Bit machines, as PC-DOS was never available for the Z80. it's a 8086 design from the very first version (as QDOS). – Raffzahn Jan 28 '18 at 21:47
  • IIRC, the author's name was Tom Swan, not Timothy. I learnt a great deal from him, but not how to write a multi-tasking OS. – No'am Newman Jan 29 '18 at 14:10
  • 1
    Well, TSRs were the most used well behaved technology, but not only that. In fact TSRs only appeared in DOS 2.x or 3.x, if memory does not fail me. You could modify directly the memory allocation structures of DOS and leave code behind, or even write code in the MBR that was installed before DOS booting. At some point I write both of those. Some ROM routines also often wrote in the secondary set of Z80 registers, for instance in the ZX Spectrum. I use Deskview for a while, but by that time was already hooked into using SCO V at home. – Rui F Ribeiro Jan 30 '18 at 18:23

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.