A season in Plan 9 land

I mostly stayed under a rock during the last weeks: exams season, some assingments plus one week of much needed [VAC]; ironically in the DebConf 8 secondary hotel.

I'm in a very interesting course on operating systems' programming, it's a new optative course, and has generated a lot of expectatives: most of the systems-oriented undergrads in the computer science career are attending. The downside is that it's *intensive*: we're expected to build from scratch a minimal operating system, starting from the bootloader. So far my group has already done a bootloader that understands FAT, and the entry point for the OS, in which the basic stuff is setup: gate A20, interruptions, protected mode, GDT, etc.

Plan 9 mascot: GlendaAlso, each group is required to do a presentation of some systems research topic, and we choose Plan 9 from Bell Labs, that mostly unknown OS that was meant to be a better UNIX, but never gained popularity. So I spent many days playing with it, trying to grok quickly what it was about, and creating a small network of virtual hosts (in Qemu) that could show how it all fit togheter.

Plan 9 has all the credentials: created in the same lab as UNIX, designed by the same people, which already learned from past mistakes. It was started in the late eighties, and it really feels like what the future was meant to be. Sadly, we're just starting to see a few of it's revolutionary ideas being applied to other systems: UTF-8, /proc, unionfs, fuse, clone(2), separate namespaces; all of these follow concepts first created in Plan 9, UTF-8 was designed by Ken Thompson "in front of my eyes, on a placemat in a New Jersey diner one night in September or so 1992", in Rob Pike's words.

Not happy enough with reworking all the core concepts, they also recreated the visual environment. I have to admit, the user-facing ideas are so foreign that I still don't feel very comfortable using it. Surprisingly, the desktop is very mice-centric, it cannot be used at all without the mouse, and it's bothersome with less than three buttons. Anyway, the underlying workings are so attractive, that I cannot stop from wondering if a hybrid system could be built (Debian/kPlan9 anyone?).

To illustrate, I'll reproduce here the same example that I showed yesterday and left some jaws hanging. I had booted a CPU server and a diskless terminal, called cpu-0 and term-0 respectively. This is a screenshot taken in the terminal, which is basically a telnet to my Debian box:
Plan 9 screenshot: first telnet

Nothing spectacular here, except for the weird syntax, it was seen like this in the Debian box:

martin@abraxas:~$ netstat -nt | grep :22
tcp        0      0 10.0.2.1:22             10.0.2.30:39879         ESTABLISHED

But here comes the fun, I ran an import command, which is more or less a remote filesystem mount, with which I mount the remote machine's /net in the local namespace. It has to be noted that the /net path is by convention the entry point to anything network related, including all the networking API.
Plan 9 screenshot: second telnet

And the wornderful thing is that this works as it should (note the remote address):

martin@abraxas:~$ netstat -nt | grep :22
tcp        0      0 10.0.2.1:22             10.0.2.10:38158         ESTABLISHED

So, what happened? telnet wanted to create a TCP connection, and that is accomplished opening /net/tcp/clone, but then it found the imported filesystem. The open(2) request was then transferred to the remote machine, and there the networking code did the actual TCP/IP dance.

Things like this make you realise that maybe the BSD sockets API is not that nice an abstraction; in Plan 9 there are no BSD sockets, it's only implemented in the POSIX compatibility libraries, which aren't used by any of the core tools. Neither there exists any threads support, you just call rfork(2) setting the appropiate flags, exactly what glibc does under the covers nowadays. They also decided to live without select(2) or poll(2), there are no non-blocking calls. If you want non-blocking, you rfork(). The only syncronisation primitive is rendezvous(2), and everything else is built on that.

At this point, it should not surprise you that to kill a process you can type echo kill > /proc/$pid/ctl; and that there's no need for an equivalent to Xnest, as rio (the graphical interface) provides a modified /dev, you just type rio inside a window and there you go.

Yes, I'm hooked. If you're interested, I compiled many links here (some Spanish there, but all the content is in English), as one of the weakest points in Plan 9 is the unorganised and missing documentation.