| about System/161
| project news
download | guides and resources | documentation | for instructors | bugs | mailing lists
A log of things have been changed in OS/161 2.x, which may necessitate updating course materials (handouts, assignment text, lecture notes, etc.) or merging local changes. This page attempts to document the important differences. There is probably stuff missing, so if you find something that's been changed around and isn't listed here, please let me know.
The big deal in 2.x of course is multiprocessor support. The kernel's thread system has been rewritten from the ground up. While the high-level thread operations are more or less unchanged, the implementation is quite a bit different under the covers: there's a struct cpu, and struct pcb has gone away. While the spl functions are still present, they should mostly not be used; instead, spinlocks are provided, and thread_sleep is replaced with a wait channel abstraction, struct wchan.
The scheduler is now a traditional scheduler - it is supposed to permute the run queue, rather than manage the run queue's queue/dequeue operations. (The run queue is per-processor, and there's basic code for thread migration included.)
Because OS/161 has always been about fine-grained locking, multiprocessor support has very little direct impact on the assignments or the students. It is now incorrect to fall back to spl synchronization to work around irreconcilable lock ordering, and in some cases the students will need to choose whether to use a spinlock or sleep-lock. Scheduling is somewhat different, and we now make the students think about how to decide when to do thread migration. The system calls assignment is otherwise almost entirely unaffected. When doing the VM system, it can be necessary to do TLB shootdown. (This is done via interprocessor interrupt, for which code is provided.) Thread migration can also require VM hooks. However, because we don't have user-level threads, and System/161 is cache-coherent, the rest of the VM system is unchanged. And the file system assignment is (almost inherently) unaffected.
Several other things have been reworked or strengthened in ways that may require adjustment.
The system now ships with a struct proc, and threads belong to processes. There are basically two ways to implement the interaction of threads and processes; one is to have separate structures, the other is to use threads as processes. The system used to lean toward the second model; we've found that this causes assorted problems for the less seasoned students that can be avoided by providing a separate process structure up front. (Advanced students have no trouble switching to the other model no matter what they're given.)
There's now synchronization for userland. I thought of a way to do it without making the students write anything extra: a special file system. So there's now a sem: file system and you can open "files" on it; reading and writing the files manipulates the semaphore count. A number of the test programs have been updated to use this logic, especially the ones that had previously been using polling loops.
The kernel now supports 64-bit integers (the necessary gcc backend "millicode" is now provided) and includes a more complete set of endianness definitions and byte-swap functions. The practical upshot of this is that the lseek call now requires marshalling the 64-bit off_t argument out of the argument registers, but the "delicate" bits of this are provided. Comments are provided in the MIPS syscall.c to explain why and how.
The waitpid system call is now defined to use the standard WIF* macros, and there are codes for signals provided. The user programs that inspect wait status have all been adjusted accordingly. This is enough support to e.g. have processes exit with SIGSEGV, makes it much easier to build Unix programs, and costs the students nothing. (Students could now in theory also implement real signal handling, but I don't recommend it...)
The array code has been augmented with preprocessor hacks to allow type-safe usage. You can have arrays of any pointer type, and neither the arrays nor the elements can be intermixed. The old untyped form with void pointers is still available.
The array code is no longer used for the thread system run queues; there's linked list code for that now. This has turned out to mean the students don't find the array code unless it's specifically brought to their attention; it is probably a good idea to do so, or they'll be open-coding linked list ops everywhere and racking up bugs.
The array-based queue code has been removed. If anyone really wants it back, I can bring it back, but it never had much use anyway.
The kernel malloc now has guard band and leak-checking and other diagnostic compile-time options. See kmalloc.c.
VOP_TRYSEEK has been removed and replaced with VOP_ISSEEKABLE, which can be checked at open time. This encourages constructing open file objects that don't lock the seek position of unseekable objects, which makes the console work better and is required for semaphores to be fully safe.
The exported kernel headers now provide all the definitions needed to build a real C library, and also include basic handling for namespace control in libc. Much of this is not used, or really needed, but it doesn't cost very much to have it. (The work is from a research kernel that had a real C library, but I haven't tested the OS/161 version against real libc sources yet. If you do for some reason and find any glitches, report them as bugs.)
Both user-level malloc and the shell are now provided in the base system. This is how we've been running our course for some time. Implementing malloc is a good exercise for students... in an environment where they can run a debugger on it. The same is true for the shell; plus, implementing a shell for Unix instead of OS/161 allows going into things like job control that would take excessive work to also implement the kernel-side functionality for.
The system now includes sbin/sfsck, a file system checker for SFS. This was previously available to instructors only, for no particularly clear reason. The current version at least can be imported into 1.x and will work perfectly well there. If there's demand it can be added to the next 1.x release.
There are a lot of new tests:
Some other things have changed that the students will probably never notice.
The pseudorand driver has been removed. It didn't quite generate uniform probabilities and it wasn't a very good generator anyway.
The C library has been beefed up a little, but not very much. I was hoping to get more done before 2.0, in order to allow building more real apps as test cases, but this is probably not happening. Maybe for 2.1...
There are a lot of really minor changes by now, as it's been five years since the 2.x branch was started. I recommend reviewing the CHANGES file -- unfortunately it's hard to know in advance which obscure details might have made their way into course materials that now need updating.
The following things have been moved around:
The toolchain for 2.0 has somewhat newer versions of things; however, the big difference is that instead of reusing the mips-linux and/or generic mips-elf configurations, we now have a proper mips-harvard-os161 configuration patched into binutils, gcc, and gdb.
The build system accordingly invokes the compiler as "mips-harvard-os161-gcc" rather than as "cs161-gcc"; this removes a dependency on our course number (which doesn't mean anything to most other schools) and also reduces the amount of non-standard installation. If you want the shorter names for typing by hand it's easy to create a family of symlinks after installing the toolchain.
The build system requires BSD make. A copy of "bmake" (the portable distribution of NetBSD's make) is posted on the toolchain page. If working on NetBSD you can just use "make". (This may be true on OpenBSD, FreeBSD, and/or Dragonfly too; success or failure reports welcome.)
The build system has been modernized. Instead of the traditional OS build method of installing as the build goes, now it installs into a staging area and the final install step copies everything across in one go. Typing "make install" by hand for a single program still installs that into the system root directory; installing into the staging area is done with another target. The userland build also builds everything into a single and potentially separate tree of object files, which can if be desired put somewhere separate from the source tree. Symlinks to the build directories are created for convenience; these can be disabled for building from a read-only tree. In general I've gone to some trouble to make this work nicely, so if you have problems please let me know.
The supplied kernel configs are named rather than numbered, to avoid confusion if not using our assignment sequencing.