Protel, SOS, And The DSM-100

Protel, the The PRocedure Oriented Type Enforcing Language, and the operating system SOS (for the Digital Multiplex Switch, DSM-100) that was built with it, give us an interesting snapshot of the early history of software engineering (as opposed to programming, and as opposed to computing science: programming integrated over time). Naturally, my focus is on the safety affordances of the language, but the Nortel engineers had a whole lot of modern design going on.

The language was in use starting in 1975, so it’s almost as old as C, and also used for systems programming. It’s a familiar ALGOL derivative. The official papers I could find (so far) are short and serve only to tantalize:

I also found some useful reminiscences from a former Nortel engineer, Frazer Clement:

There are more (offline, sadly) citations at The York University Computer Museum. Searching the web for some of the citations can get you closer, but the holy grails that I haven’t found yet are H. Johnson, “PROTEL: A programming Language for Large Real-Time Applications” (1984); and Protel Technical Notes, BNR, Language Development Group; issues: vol. 1, nr. 1 – 7, 1980.

The broad view these sources provide of Protel and SOS is of a type-checked and spatially memory-safe systems programming language, compiled into dynamically linkable and swappable shared objects, which all run as real-time, pre-emptively scheduled threads in a single shared address space.

The systems ran with volatile storage as their primary storage, rather than treating volatile storage as a fast cache for non-volatile storage. Instead, production systems had redundant power supplies and battery-backed power, and used an explicit delineation of memory types for reliability and recovery. Certain memories were explicitly temporary, while others would be restored from disk or tape only in escalated outages. See Clement, especially “Multiple memory types”.

Protel’s type system was somewhat richer than C; from Foxall, et al.:

TYPE digit-value, terminal-id {0 TO 9}
    status_condition {busy, idle, blocked, ready},
    out_of_service BOOL,
    protocol_ptr PTR TO status_condition;

TYPE digit_register TABLE [0 TO 19] OF digit_value,
    special_feature SET {abbreviated_dial, add_on,
                  call_transfer, do_not_disturb},
    time_interval
       STRUCT
          amount {0 TO 255},
          unit {ten_ms, secs, mins, hours}
       ENDSTRUCT;

I find ranged integers notable; even now, we have to roll our own, but I suspect their ergonomic definition could have prevented many bugs.

Foxall, et al. describe descriptors:

A descriptor consists of two parts: a descriptor part and a table part. The descriptor part contains the table element count, the size of these elements, and a pointer to the base of the table part. The table part contains the elements of the current array. At execution time a descriptor may be made to point at any table of the correct type. This results in modification of the element count and pointer fields of the descriptor part.

The area type seems to provide a form of abstract class inheritance via C-union-like structured type punning:

TYPE daddy AREA (6 * byte-width)
   i integer
ENDAREA;

TYPE son AREA REFINES daddy
   t TABLE [0 TO 15] OF BOOL
ENDAREA;

TYPE daughter AREA REFINES daddy
   j integer,
   k BOOL
ENDAREA;

I don’t see discussion of down-casting safety with areas, though. As for C unions and C++ without RTTI, areas may be unsafe.

Protel also had function types:

TYPE get_channel PROC (terminal terminal_id)
     RETURNS integer;
TYPE transfer PROC (REF t time_interval,
     UPDATES feature_table DESC OF BOOL);

Early Modern Engineering

Although that method of operation is different from what we use now, we can see from these sources that Protel, SOS, and the DSM-100 embodied very early forms of what we now consider a baseline for modern software engineering and site reliability engineering culture. Some examples:

Musings

I used to think (and so did the designers of Microsoft’s Singularity operating system, so at least I was in good company) that language safety could obviate protected memory (as mediated by a privileged supervisor). Clearly, the SOS designers were hoping for that, too, and like the Singularity designers they really wanted to get rid of the over head of context switching and virtual memory. (The overhead is amazingly high! We’ve just come to accept it as normal, which really puts micro-performance concerns into perspective.)

Similarly, it’s obvious (even to me) now that memory protection alone can never suffice: untrustworthy programs can call and corrupt a program even from outside its protection zone (and even, of course, from other machines entirely). Add to that side-channels and the practical difficulty of maximally reducing the privilege of programs in real-world systems, and you have a recipe for sadness.

Having no memory protection does make language safety paramount — clearly, we must have at least one of language safety and protected memory. But we also know that there will always be unavoidable zones of language un-safety, even if they are few and small. (Although it’s worth noting that, according to Foxall, et al., “Furthermore, it was decided that PROTEL should be the only implementation language — no assembly language was provided for DMS-100.”) In the end, even Singularity had to provide virtual memory protection. I do think, though, that strong language safety provides trustworthiness that can allow us to reduce the proliferation of memory protected address spaces, and hence to regain some efficiency.

Here’s a simple example of scripting in the DSM-100 shell — it was still in use at least as late as 2012:

And, finally, your moment of Zen (Cashin, et al.):

Rather than increasing complexity by allowing module nesting as in ADA, our experience leads us to believe that even our current structure may be more complex than necessary. Instead, it may be sufficient to have a structure consisting of a linear chain of interface sections and a single implementation section. This would increase the efficiency of the support system since symbolic information would no longer need to be placed in implementation section object files thus eliminating the need for a linker.