I was asked to share this, so though it might be a fun for more people. It is a demonstration of pre-emptive multitasking in Turbo Pascal. I wrote this back '97 when I was 17 years old, using Turbo Pascal 7.

I was asked to share this, so though it might be a fun for more people. It is a demonstration of pre-emptive multitasking in Turbo Pascal. I wrote this back '97 when I was 17 years old, using Turbo Pascal 7.

You can register a number of tasks, in the form of parameter-less procedures, and the code will then switch between them pre-emptively, that is, without cooperation.

It hooks interrupt 8, which fires every 18.2 ms or so, which triggers a task switch in a round-robbin fashion. It saves all the registers of the running tasks, find the next task to run, and restore all registers from that task.

I recall spending an entire night studying the x86 instruction set trying to figure out how to save all the registers and flags in a way which would not overwrite the very registers or flags I was trying to save.

The code here just has two tasks, one which processes keyboard inputs and one which draws something on the screen.

Anyway, good times :)
http://paste.ie/view/8d50f39c

Comments

  1. TP7 already provided to use protected mode! Why keep the memory unprotected? :P

    ReplyDelete
  2. Arioch The I'm pretty sure protected mode was one of the features exclusive to Borland Pascal.

    ReplyDelete
  3. Asbjørn Heid​ among what set? There was not that many Pascal compilers anyway. Outside Pascal there were DJGPP extender for GCC port, there were DOS16M and DOS4G extenders utilized by Watcom, etc

    ReplyDelete
  4. Arioch The
    From what I remember, it was Borland Pascal that had protected mode, not Turbo Pascal. At least that's what I remember from university computer class - that only one version of IDE had protected mode.

    ReplyDelete
  5. Arioch The Turbo Pascal was "standard edition" and Borland Pascal was "enterprise edition". TP had no source code for RTL for example, BP did. And I'm 99.9% sure protected mode was a BP thing.

    ReplyDelete
  6. Borland Pascal included both the protected mode compiler and the normal TP7 compiler. There was also Frontier Software Pascal (Canadian company?) making a protected mode 32 bit compiler.

    ReplyDelete
  7. Very interesting! Is this similar to the techniques a primitive pre-emptive multitasking kernel would use?

    I'm curious about some of the code. For example, why does MainProc have the loop counting down from $feff? Is it effectively a timer? But Main_Proc is one of the two tasks set running in Init_Task so why is it called at the end of the program?

    ReplyDelete
  8. Many of the RTL routines are not reentrant, so switching tasks could potentially fail. Cooperative scheduling is to prefer.

    ReplyDelete
  9. David Millington It's called at the end because otherwise the program would just quit. Also since it saves/restores the state, it has to be running in the first task when the first switch happens, otherwise it would continue running the non-task. So it's a poor mans bootstrap of sorts.

    As to why it's counting down... due to my poor variable naming it's easy to miss that the MainProc task is responsible for changing counter which is used by the drawing task to determine which character and color to draw on screen.

    ReplyDelete
  10. Leif Uneus Yes indeed. To be honest I can't recall if I knew how big of an issue this would be. I think I was aware that it wasn't entirely safe, but I'm pretty sure I wasn't aware of just how bad.

    That said, the state saving/restoring procedure could be a good starting point for a cooperative fiber like library.

    ReplyDelete
  11. David Millington I forgot to mention that emulating the task switching in a primitive kernel was indeed my "quest" when I made this. I've never written a proper OS as such, so I'm not sure how close I got though. I presume I'd need a lot more for handling sleeping tasks, ie those waiting on locks and similar.

    ReplyDelete
  12. Jeroen Wiert Pluimers As you can see from my task data structure, the stack for each task was simply a fixed 1kB array. I recall going with this for simplicity.

    ReplyDelete

Post a Comment