Nixers Book Club - Book #6: Introduction to Operating Systems Abstractions - Community & Forums Related Discussions

Users browsing this thread: 1 Guest(s)
seninha
Long time nixers
As proposed in the last thread, the next book of the Nixer's Book Club is gonna be Introduction to Operating Systems Abstractions using Plan 9 from Bell Labs

[Image: plan9bunnywhite.jpg]

We can do 2 chapters per week.
Our first session will be Nov 13, when we will discuss the first two chapters.
See you then!
seninha
Long time nixers
Mainly because of our conf, I am postponing our first session to Nov 13.
If you are interested or curious on Operating Systems and Plan 9 in particular, join us in this sixth reading of the book club!
RoastPotatoes
Long time nixers
Interested in joining in with this. Have no experience with plan 9 but it looks interesting!
If I want to test it out what would you recommend? I know there's a couple of forks and different projects/continuations. And can I just spin up a virtual machine?
seninha
Long time nixers
(30-10-2021, 09:14 AM)RoastPotatoes Wrote: Interested in joining in with this. Have no experience with plan 9 but it looks interesting!
If I want to test it out what would you recommend? I know there's a couple of forks and different projects/continuations. And can I just spin up a virtual machine?

I also have no experience with plan 9, but I am having fun playing with it.
I'm using 9front (for no reason in special). Its manual, although full of unrelated pictures, explains the installation process in details.

I first tried to install it in Qemu. But I did not like how qemu grabs the cursor... I want to freely navigate between my windows.
Then I installed drawterm, which connects to a 9front system and runs rio inside a X11 window. You can connect drawterm with the plan9 system running in your qemu virtual machine.
Then I moved from qemu to OpenBSD vmm.

The nice thing about drawterm is that it mounts your host system's root file system in your 9front system. So I can use vim in my host system to edit my files in a xterm window and then open the files in the 9front guest system from a rio window open via drawterm.
venam
Administrators
It's time for the book club.
Here's my summary/notes for the first two chapters.

## Chapter 1

I installed Plan 9 latest image in a VM and started learning it
properly. All the times I tried it in the past, I stopped short and didn't
go so deep.

Rio is definitely a weird experience. It isn't very intuitive that ACME
is missing line numbers, and that using the cursor scrolls down instead
of going to the next line. These probably can be configured somewhere,
or so I think.
At least for now, it feels like I'm fighting against the UI and clumsily
editing files. I'm making a lot of mistakes with the mouse, deleting
text I didn't intend to, mixing middle mouse (emulated shift+right click).
I love plumber, but my hands just keep mixing the buttons.

Similarly, in the shell, arrow up doesn't show the previous command but
scrolls up. Obviously, there's no tab completion either.
Overall, I'll still need a while to get used to the UI.

I'm quite fund of the compiled that allows targeting multiple
architecture (cross-compilation) that easily.
It's also my first go at the Plan 9 C dialect and it looks good so fr.

Definitely liking the thin-client architecture, the decoupling of
terminal/data/cpu servers.

## Chapter 2

This chapter has an initial overview of what's the meaning of program
and processes, what it means to have an OS, letting multiple things run
at once (multitasking OS).

However, it quickly follows with analysis of processes exec layout and
virtual memory. I'm not so sure it's a good logical order, it felt
parachuted for me. At least, if I was writing for beginner students,
I would be surprised if they didn't nag when studying with such book.
Furthermore, it's a bit annoying that multiple sentences are sprinkled
with the words "it's important to know this". I guess if I didn't have
the background knowledge I have right now, I'd be freaked out reading
that book.
The writing is also a bit more botched and clumsy than the first chapter,
heavy explanations in some places where there shouldn't really be and
shallow ones where there should be.

Apart from this, I'm still liking the Plan 9 C dialect.
ARGBEGIN/ARGEND, E/ARGF are quite nice macros, a good simple replacement
for getopt.
It's great that the return status can be a string, it allows for more
explicit errors.
And actually, system calls can return both string and integers in general.

However, even when the program returns a string, some of the info,
when the program crashes needs extra step to make sense of it.
src and acid command for debugging are super interesting, but I feel
like a lot of what is done could be much simpler. I'm also wondering if
all broken processes stay in the process tree hanging there (like zombie
processes on Unix).


Other cool info:
- Environment variables are similar to Unix.
- seninha mentioned it once but here I got reminded again: If you type
ip/ping, the shell tries with ./ip/ping, and then with /bin/ip/ping.
- PID are similar to Unix too
- Everything is a file, obviously. This particular example caught my
attention: echo kill >/proc/$pid/ctl

In sum, I'm hopeful for the next chapters.
josuah
Long time nixers
## Chapter 1

The group-based permission system is interesting, and solves the "shared directory" problem, which is a very common one: have one directory in read-write access by anyone in the group.

It looks simple, but with UNIX-style permissions, by default umask 022, not only files will be created with the wrong group (it would have to be setup by hand) but also they would be not modifiable by the group (due to the umask).

Plan 9 behaves the same way as UNIX after
Code:
chmod -R g+s /
and
Code:
umask 002
for all users : the +s mode provokes inheritance of groups on newly created files, and 002 make the new files read/write by the groups.

In fact there is not even chown(1) in plan 9, just chgrp(1).

## Chapter 2

The plan 9 cross-compilers are really nice. And look at what we find in Go source code history...
https://github.com/golang/go/tree/go1/src/cmd

Russ Cox worked long on getting Plan 9 commands everywhere, starting with the compilers to build everything else, so it was a good base for Go.

From the book, "demand paging" is quite enlightening, and constitute a good counterpart to dynamic libraries : since everything is made by composable programs that are reused by different purposes, there is only one instance of the program's code (.text section) in total.

In the end, filesystems seems offer the same feature-set that shared libraries are offering on non-plan9 world, except communicating through 9p instead of the ABI : more expensive (requires carefully placing the features across FS so there is not too much 9p protocol overhead, which is extremely low locally!), but more generic and isolated.
josuah
Long time nixers
(13-11-2021, 04:56 AM)venam Wrote: It's great that the return status can be a string, it allows for more
explicit errors.
IIRC there is a "error message" field in 9P, so that errors strings can come from remote or local.

(13-11-2021, 04:56 AM)venam Wrote: it's important to know this
from the book: "always check out for error conditions".
In practice I have seen a few code not doing so, but people doing it might know that the driver/fs does not have any room for error (no code that returns -1 for instance)... So maybe the idea under all the "important to know" was to focus the reader attention on core principles rather than the implementation details that are accidentally needed for the sake of example.

(30-10-2021, 11:29 PM)seninha Wrote: So I can use vim in my host system to edit my files in a xterm window and then open the files in the 9front guest system from a rio window open via drawterm.
For whoever interested in using Linux/UNIX-like tools but still discover plan-9:
https://www.ueber.net/who/mjl/plan9/plan9-obsd.html
josuah
Long time nixers
(13-11-2021, 04:56 AM)venam Wrote: ARGBEGIN/ARGEND, E/ARGF
Available on an UNIX machine near you TODAY https://git.suckless.org/sbase/file/arg.h.html

(13-11-2021, 04:56 AM)venam Wrote: However, even when the program returns a string, some of the info,
when the program crashes needs extra step to make sense of it.

Namely: http://git.9front.org/plan9front/plan9fr...d.c/f.html
Code:
int
refused(char *e)
{
    return e && strstr(e, "mail refused") != nil;
}

(13-11-2021, 04:56 AM)venam Wrote: src and acid command for debugging
https://9lab.org/plan9/debugging-with-acid/
I really like the source code dumps. Stepping through C source code as it gets executed!
I never played with it though.
seninha
Long time nixers
Getting Started

The first section is a brief introduction to a operating system as a collection of system programs that interface with the hardware and how it lies to the programmer by common abstractions.

`/sys/lib/newuser` is a rc(1) script that creates and set up the home directory for the user and create the necessary profile scripts. I cat this file to see its contents, and it is pretty straight forward at 9front.
I'm just curious about why it is at `/sys/lib/` and not at `/bin/whatever/`.

Our first interaction with rio! Damn this menu thing is awkward. I'm used to click to open the menu and then click on the selected entry (that's how I programmed πmenu to behave). But rio's menu is click-and-hold then release on the selected entry.

Now it's acme time.
Button3 click opens a file/directory or looks for a word in the current window. I found this behaviour really awkward... What if I wanted to look for a occurrence of a filename of a file that exists? Right click will open that file...

The window/widget that receives keyboard input is the one where the pointer is over, just like on Xaw/athena X applications. It's called point-to-type. I hated it.

One thing I find weird on rio and acme is how the height of the scroll bar handle changes while scrolling. After checking on the manual I found out that the height of the handle corresponds to the density of characters on the screen, not the number of lines on the window. So if you have a sequence of blank lines on the screen, the scroll bar handle will be very thin (as there are no characters on this section of the scroll), but when viewing the dump of xd that is full of characters, you will have a higher handle.

Enough acme. The next pages are on the manual. Simple file management commands (mv, cd, rm, etc) and concepts (directory, dot-dot, relative path, etc), and file content reading (plan9 uses xd(1), which is way more friendly than od(1)).

One thing I do not like in the plan 9 manuals is how everything is written in prose, rather than lists. Options are scattered through a paragraph that you have to read as a whole to understand the stuff. On some UNIX systems (OpenBSD at least), options are presented in a list using a `.TP` man macro. It is easy to spot an option for reference when they are on a list.

Then we write our first plan 9 program, using a variant of the C programming language with a plan9-specific standard library. The next pages talk about library and system calls, and how system calls work.


Programs and processes

Second chapter is about programs and the processes they generate. We begin with an overview of what a process is and how it is executed; and of the structure of a program (both in file and in memory) and how it is loaded into memory by the kernel.

The concept of program initialization is explained by the classic echo.c program. The example introduces the plan9 ARGBEGIN and ARGEND macros, which replace UNIX getopt(3).

Then comes the error handling. Plan9 has a "%r" directive for print(2) that is replaced by the error string, this directive does not require an additional argument. There is no errno(2). The system provides an err(3)-like function that both prints a message and exits: sysfatal(2). The {w,r}errstr functions write/read the error string.

Next section is about environment variables. Everything pretty simple and similar to how stuff is done on UNIX. One thing I discovered is that children processes can change the environment of their parents! (At least depending on how the processes are forked). The section about processes introduces the concepts of process id, process state, and process scheduling.

Next section explains how to debug a broken process that is still hanging around in the ps(1) table. The section introduces acid(1) and some of its commands (stk() and lstk()). To kill a broken process, run
Code:
% echo kill > /proc/$PID/ctl

And finally! Everything is a file! (Or that's the lie the computer tells to you). Time is a file (see /dev/time); processes are files (/proc/); environment variables are files (/env/).
seninha
Long time nixers
(13-11-2021, 04:56 AM)venam Wrote: Similarly, in the shell, arrow up doesn't show the previous command but
scrolls up. Obviously, there's no tab completion either.
Overall, I'll still need a while to get used to the UI.
9front has a " command that prints the previous command, and a "" that runs it. File completion is done with Ctrl+F.

(13-11-2021, 04:56 AM)venam Wrote: However, it quickly follows with analysis of processes exec layout and
virtual memory. I'm not so sure it's a good logical order, it felt
parachuted for me. At least, if I was writing for beginner students,
I would be surprised if they didn't nag when studying with such
book.
The book was written for the students of the Operating System courses the author is professor of. Since the course is given after the Computer Architecture course, the students should knew about virtual memory beforehand.

(13-11-2021, 06:22 AM)josuah Wrote: The group-based permission system is interesting, and solves the "shared directory" problem, which is a very common one: have one directory in read-write access by anyone in the group.
UNIX has that. Quoting from the APUE book, third edition, section 4.6:

Quote:The user ID of a new file is set to the effective user ID of the process. POSIX.1 allows an implementation to choose one of the following options to determine the group ID of a new file:
1. The group ID of a new file can be the effective group ID of the process.
2. The group ID of a new file can be the group ID of the directory in which the file is being created.

FreeBSD 8.0 and Mac OS X 10.6.8 always copy the new file's group ID from the directory. Several Linux file systems allow the choice between the two options to be selected using a mount(1) command option. The default behavior for Linux 3.2.0 and Solaris 10 is to determine the group ID of a new file depending on whether the set-group-ID bit is set for the directory which the file is created. If this bit is set, the new file's group ID is copied from the directory; otherwise, the new file's group ID is set to the effective group ID of the process.

Using the second option (inheriting the directory's group ID) assures us that all files and directories created in that directory will have the same group ID as the directory. This group ownership of files and directories will then propagate down the hierarchy from that point. This is used in the Linux directory /var/mail, for example.
Edit: More information on that in this Wikipedia article
venam
Administrators
Chapter 3 and 4 were pretty simple, especially with a Unix background
the content can be compared.

Here are a couple of notes I took during my reading.

## Chapter 3

They fixed the create syscall 😂

Code:
fd = create("afile", OWRITE, 0664);

Quote:> Plan 9 does not have a wastebasket
First time I hear it called that way.

In Plan9, like old Unix, you can still see the directory file structure
and manipulate it directly with the help of some specific syscalls:

Code:
xd -c .
typedef
struct Dir {
    /* system-modified data */
    ushort type; /* server type */
    uint dev; /* server subtype */
    /* file data */
    Qid qid; /* unique id from server */
    ulong mode; /* permissions */
    ulong atime; /* last read time */
    ulong mtime; /* last write time */
    vlong length; /* file length */
    char *name; /* last element of path */
    char *uid; /* owner name */
    char *gid; /* group name */
    char *muid; /* last modifier name */
} Dir;

Globbing in the shell is the same as Unix.

One thing that is different though are the arguments for the dd command,
they got dashes now.


I was particularly impressed by the buffer section of chapter 3. It's
a pretty good way to learn the importance of buffering. We also get a
practical example. Biobuf is really useful instead of reinventing the
wheel each time.


## Chapter 4

Similar vibe as chapter 3, I keep comparing in my mind.

Fork is the same as Unix fork.

NB: The author never stops the "important" talk.

One thing I found weird is that execl needs argv[0] explicitly, that's
peculiar.

Wait syscall also returns a full message, I like how errors are much
more verbose in Plan9, that makes it simpler to debug.
seninha
Long time nixers
(20-11-2021, 04:40 AM)venam Wrote: One thing that is different though are the arguments for the dd command,
they got dashes now.
In rc(1) the = character is special not only at the beginning of the command line, but in the middle too. So you can set an environment variable in the middle of the line. The UNIX dd syntax
Code:
dd if=/dev/random of=/dev/mordor
was problematic in rc(1) because of the special meaning of the equal sign.

Files

Third chapter is about files, I/O and buffered I/O using the <bio.h> header. Plan 9 also uses the concepts of file descriptors to identify the files open by a process.

The first section of this chapter introduces the basic unbuffered I/O functions (write(2) and read(2)), the functions to open/close files (open(2) and close(2)), and the function to set the file offset (seek(2)). /proc/$pid/fd lists the file descriptors that are open for process $pid (it also contains the process' cwd).

In the second section, we know that open(2) does not truncate the file by default, we should use `OTRUNC` to truncate. The file descriptor in the process' file descriptor table points to a `Chan` (channel), a structure that “contains information needed to let the kernel reach the file server and perform operations on the file”. This section also tells you that a file can have holes; it also tells about the append only permission bit.

Next sections is about the read(2) function and how to handle errors; and about the creat(2), access(2) and remove(2) functions. The next section covers directory entries, the Dir structure and functions to handle this structure.

We are introduced to globbing and, finally, at the end of the chapter, to buffered I/O.


Parent and Child

Fourth chapter deals with process creation. It introduces the functions fork(2), exec(2) and wait(2), and introduces the pitfalls of process creation (shared files, race conditions, waiting for children, etc).

Since we have bind(2) now, we do not need execp or execlp functions, the meaning of $path was diminished to a rc(1) feature. Just look at /bin.

At the end of the chapter, shell scripts and the shebang are introduced.
venam
Administrators
Time for the book club discussion.

Chapter 5 and 6 were interesting because they started to give an overview
of the decoupled, decentralized, architecture of Plan 9. They also
emphasize the strong enforcement of "everything is a file".


## Chapter 5


This one was about the shell and redirection in general.

The virtual descriptor, /fd/0 and /fd/1 were new to me, interface to
file descriptors.

The redirection to different file description is done using square brackets.
That's cleaner than Unix usual shells.

Code:
; lc *.c >[2] /dev/null

One interesting point, that is well covered in the book, is that pipes
preserve write boundaries, unlike Unix.
Another unusual feature that enforce cleanliness, is that Plan 9 kills
processes that only use the write end of the pipe.

rc, shell execute command like this:

Code:
`{command}

<{...} # or when redirecting as input


The concept of notes to process wasn't obvious at first because of
the name, but making the comparison with Unix signals, it started to
make sense.
Similarly, like signals, they can be caught with a notification handler
(atnotify).

Plumbing is pretty cool, it has ports to dispatch messages to
applications. It's kind of like mime-open and xdg-open in a way.



## Chapter 6

This chapter was about networking.

The network is a file on the disk, as with everything else. Somewhat
like linux proc/net/tcp which was inspired by Plan 9. Namely on Plan 9
we can have files such as /net/ether0.

One thing that feels a bit awkward is to send text as commands to files.
Code:
echo hangup >/net/tcp/14

I kind of think that it can be flimsy, unless there is a way to list
all the possible commands/notifications that a process can handle and
to limit processing unknown commands.

We also see the concept of translation of human readable names to
addresses/ports.
It reminds me of this but I hadn't covered Plan9 in it.

The network database, ndb in /lib/ndb/local is like NSS.
The equivalent of getent on Plan 9 is csquery. CS stands for "connection
server".

The socket programming style is novel, different than BSD sockets,
and much simpler.

We get to also talk about registering services and running them.
We see /rc/bin/service which is kind of like an inetd if I understood
properly.

Lastly, we get reminded that the architecture is decoupled and that
commands are actually executed on a CPU server. We can explicitly do
that using rc command.
seninha
Long time nixers
Chapter 5 covers the basic IPC mechanisms for Plan 9. It begins with
IO redirection on rc (with the < and > operators) and on C (with dp(2)).
Redirection of one file descriptor to other other is much more different
on Plan 9. ">[1=2]" vs "1>&2".

Pipe is also explained both in rc(1) (which works like in UNIX sh(1)) and in
C (with pipe(2)).

rc(1) has <{}, a very useful construct that runs the command between
braces and expands to a pipe file with the output of that command.
Bash already does that with <(), but that's not in POSIX sh(1).

Plan 9 replaces UNIX signals with notes, which are strings "posted" into
a process' `/proc/$pid/note` file. The chapter illustrates this
mechanism with a program that prints the note that are posted into it.
It also introduces alarm(2), that posts a note containing `alarm` to the
process after some time has been passed.

The `ORCLOSE` flag for open(2) is then introduced. I wish UNIX had
that! With this flag, you do not need a signal handler to cleanup files
after the program is terminated.

The next session is about the /srv file descriptor bulletin board.
Apparently, that's plan 9 weird but interesting way to implement named
pipes.

Chapter 6 is about networking and how it is represented in the file system.
I read this chapter some weeks ago but I have not wrote any notes about
it... So here's what I remember.

Through the chapter we design a simple echo server that we can use from
our Plan 9 machine. I used it to communicate between my Plan 9 guest
system to my host system.

At the end of the chapter we see how Plan 9 offers a simpler echo
service using only cat(1) (in a secript at /rc/bin/service/tcp7).

The way connections are controlled using writing into control files
was new to me.