11 ms·
How could the early Unix OS comprise so few lines of code?
- ovi256 3y agoAnswer: smaller target to cover! Modern Linux has most code in device drivers to support so many different devices. Then, it supports many targets for other subsystems, like file systems. The original Unix provided one implementation for each subsystem. They relentlessly simplified the problem they were solving to make it doable.
- eru 3y agoThey also didn't care nearly as much about performance. Or to be more precise, they had very different trade-offs to make. Back then, you could have a system call and context switch for every read and live with the overhead. Today we have something like io_uring.
- msla 3y agoBack then, fitting in RAM was a big problem: The PDP-11 (the first kind of computer to run Unix, as opposed to UNICS) had a 16-bit address space, which gives you 64 K of RAM if you ignore the fact peripherals were memory-mapped and so took addresses away from actual memory. Later models had split I+D, or separate address spaces for Instructions and Data, but that's still only 128 K. https://gunkies.org/wiki/PDP-11_Memory_Management https://gunkies.org/wiki/PDP-11_Memory_Management
- shrubble 3y agoLater models could address 18 (256k) or 22 bits (4Mbytes) of memory.
- systems_glitch 3y agoStill restricted to I+D of 128K mapped in at any given time, plus your 8K of I/O space for bank 7.
- dezgeg 3y agoI'd guess that back then system call overhead was lower than with modern CPUs with deep pipelines, speculation and their vulnerability workarounds.
- pixl97 3y agoI'm thinking most stuff was designed around single core performance. Lots of drivers had big'ole gigantic locks which really killed multi processor performance. These days with modern CPUs with a ton of cores the complexity has increased greatly.
- paulddraper 3y agoIt wasn't lower. But people put up with it. Because they had to; there just wasn't a viable alternative
- cmrdporcupine 3y agoFor sure, and up until the mid-to-late 80s RAM speeds were higher than processor speeds. So approaches to architecture were totally different. Most minicomputer class processors were sewn together from multiple chips and transistors; even their register sets for the CPU were often not dissimilar from main memory. Texas Instrument's minicomputer (and later microcomputer) architecture even just put registers in RAM. In the microcomputer world, the 6502 got around having a very small register set by just having a 256-byte "zero page" with slightly faster cycle access than regular memory. There was no need for complicated cache hierarchies. Relative cost of a context switch or interrupt or transition from user space to kernel etc. was way lower than now. And the users of the system were by and large trusted. Security was more of a suggestion.
- pmontra 3y agoWe did care about performance because 1 MHz was slow even back then and data bus were slow too. However we had to care more about memory size because we couldn't fit much in a few kB or 1 or 2 MB for huge machines. Finally, compilation time for substantial programs were... substantial! You could play games as in that sword fighting xkcd.
- bluetomcat 3y agoWith virtual memory and demand paging, memory management (done efficiently) becomes a much harder problem, too.
- tgv 3y agoUnix V7 had virtual memory, at least, I can remember the PDP-11 disk unit throwing itself around violently when somebody started nroff.
- inkyoto 3y ago> the PDP-11 disk unit throwing itself around violently when somebody started nroff. That was the overlays… the early days substitute for the virtual memory proper. If I remember correctly, the first PDP-11 to have the true virtual memory and a MMU was PDP-11/70 which had 18-bit wide hardware addresses.
- thequux 3y agoThe 11/70 had a 22-bit wide memory bus and an 18-bit wide unibus which was mapped to the high 256kb of the 4M physical address space.
- inkyoto 3y agoYou are correct. I have long forgotten about the mapped memory and was thinking about Unibus device registers having long 18-bit addresses. The 11/70 also had separate instruction and data spaces which did not exist in earlier models.
- arethuza 3y agoMany years ago the team I worked out got some shiny new Sun 4 machines and we soon ran out of disk space - solution was to plug a cabinet full of a few old huge disks that I think came from some kind of ancient mini into a Sun 3 and then NFS the new storage onto the Sun 4s. It was truly bizarre to watch the cabinet judder and shake as we accessed stuff - I think there were only 2 disks in it and it was mostly full!
- mdp2021 3y agoLatest Linux kernel source: 39,000 certs 0.0% 40,000 usr 0.0% 164,000 init 0.0% 240,000 virt 0.0% 250,000 ipc 0.0% 459,000 io_uring 0.0% 664,000 rust 0.1% 980,000 samples 0.1% 1,885,000 block 0.1% 2,850,000 scripts 0.2% 2,953,000 security 0.2% 3,609,000 crypto 0.3% 5,165,000 mm 0.4% 7,156,000 lib 0.5% 12,420,000 kernel 1.0% 33,047,000 net 2.5% 39,916,000 include 3.1% 43,224,000 fs 3.3% 45,001,000 sound 3.4% 54,988,000 tools 4.2% 107,971,000 arch 8.3% 943,527,000 drivers 72.2% Based on rough byte count (total 1,306,548,000 bytes in the above).
- uaeu321321 3y agoarch seems pretty essential and it's still at 107m. hardware is complex, no way around it.
- bluGill 3y agoI'm not familiar with linux, but is arch platforms support for a bunch of different archs - x86, x86_64, arm, arm64, and many more come to mind.
- cmrdporcupine 3y agoAs sibling pointed out, to be fair you'd want to somehow restrict arch/ down to one only architecture.
- rurban 3y agoFreeRTOS on the other hand is just two C files. And a proper secure microkernel much less.
- jhoechtl 3y agoThey also did't care that much about * unit testing * framework boiler plate * testing pragmas * mockups
- Conlectus 3y agoIf you’ve read any of the code you’ll also know that early Unix was full of security vulnerabilities. Eg. Statically allocating fixed buffers and not checking input sizes. I’m all for appreciating simplicity, but let’s not pretend we haven’t progressed since then.
- Joker_vD 3y agoNot only early Unix; look at the original inet_addr implementation [0]. It accepts not only "0x" but also just "x" as the 16-base prefix, it doesn't really care about the numbers overflowing, and it parses 09 as equal to 011 (which is decimal 9). And the less said about the coding style, the better. [0] https://github.com/dank101/4.2BSD/blob/master/lib/libc/inet/inet_addr.c https://github.com/dank101/4.2BSD/blob/master/lib/libc/inet/...
- cogman10 3y agoThere were also a lot of practical limitations on the hardware that need to be recognized. These weren't devices that could store megabytes of data for code or memory. Not only that, but the compilers were also a lot dumber (by necessity). So, optimizations you'd normally leave up to the compiler (like inlining) you instead did by hand.
- jandrese 3y agoThis part is frequently lost on people. Bell labs developed a multi-user operating system that supported multiple people logged in at the same time on a machine with 64 kilowords (144kB) of storage. Later development was done on a machine that supported a max of 4MB of memory and had to allow for hundreds of simultaneous logins. Keeping the code compact was a high priority, even over usability in some cases.
- 3y ago
- wkat4242 3y agoBut modern Linux is only the kernel. Early unixes included the userland as well which creates a different balance in types of code. In fact traditional unixes still do, like FreeBSD. Linux is the odd one out with this separation. I think it happened because GNU was not very successful with Hurd but they made great userland so "Linux" became kinda a combo. And for Linus the userland was never really in scope anyway.
- hnfong 3y agoI'm only speaking from impression, but I think early Unix's userland is probably comparable with busybox in terms of code size and features.
- bluetomcat 3y agoIt was essentially a "time-sharing" system that multiplexes interactive sessions of multiple users on teletype terminals. The "shell" handles such a session by waiting for user input on the terminal, interpreting it and starting external programs as a sub-hierarchy of user processes. On a teletype terminal, you couldn't even have a cursor-oriented editor like vi, but had to rely on line-oriented editors like ed and sed.
- pluijzer 3y agoIn a way it became the complete opposite of how it started. At first one OS for many users, ea with many processes. Now, with containers, micro services etc. we have an OS per service/process. Still the original abstractions work surprisingly well though makes it me wonder how a complete redesign of would look like aimed at modern usage.
- lmm 3y agoMost of the time the OS is just overhead now. Look at unikernels for one possible future.
- magicalhippo 3y ago> Most of the time the OS is just overhead now. And they became so good at it that we added more OS' on top, with our VMs and OS-like web browsers...
- cmiller1 3y agoI'm not sure I think the exokernel/unikernel approach by itself is the path forward. While the library operating system approach makes a lot of sense for applications where raw throughput/performance are crucial, they don't offer as much in the way of development luxuries, stability, or security as most modern operating systems. Furthermore, outside of very specific applications the bare metal kind of performance that the exokernel approach promises isn't really that useful. That said, I suspect a hybrid approach may be viable where two extremes are offered, an extremely well isolated and secure microkernel which offers all of the luxuries of a modern operating system built on top of an exokernel which can also be accessed directly through the library operating system approach for specific performance critical applications (say, network and disk operations for a server.)
- codeflo 3y agoI think mindset plays a role as well. Back in the day, there was a restraint on adding features, at least when they would make the logic more complicated for only a tiny or imagined benefit. Part of that was memory/storage limitations. But I think the pursuit of an abstract idea of elegance was equally important. After all, these systems were primarily written for other computer people. This idea is completely gone from the world of software engineering. Systems become overloaded with the implementation of every crappy idea under the sun -- if a PM in a fever dream can think of it, and an overworked dev can hack it together, it goes in.
- the_gipsy 3y agoNot in open source. Projects with the attitude of allowing any feature that some rando comes up with die quickly when the manpower to keep it up simply isn't there. The projects with maintainers that gatekeep are the ones that survive, and they survive for a long time.
- anewhnaccount2 3y agoIn the case of Unix, it was deliberately a KISS/stripped down successor to Multics. The simplicity was originally intended for faster development and running on minicomputers rather than mainframes. In the end the simplicity also meant hackability and portability which is probably why it was successful and has had so much staying power.
- pjc50 3y agoFeatures are, like it or no, where the value is.
- formerly_proven 3y agoCoding the perimeter vs coding the area
- jongjong 3y agoI feel that most 100K line programs could be rewritten with just 10K lines and end up being more reliable. Feature creep is responsible for some of the code bloat but I can guarantee from experience that, in the vast majority of projects, you could keep all the features and still cut the code to at least 1/10th of its size. I think the reason for this is because developers who focus on development speed do so at the expense of succinctness. The more foresight you have when you're writing code, the fewer lines you will end up with. Unfortunately, developing that foresight requires time spent not coding; it means choosing the best option out of all viable alternatives. When developers are pressed for time, even if LOC is not used as a metric to judge them, they will not have the time to look ahead in the near future to minimize the lines of code. Workarounds tend to require a lot of lines. When code is rushed, it ends up getting littered with workarounds which require additional checks, additional tests, etc... A bad foundation with sub-optimal abstractions can force developers' hands and lead to even more bad code being produced on top. Before I start working on a feature, I simulate how it's going to work in my head and try to identify all the hurdles and alternatives; sometimes several levels down in the hypothetical component/module hierarchy. I do brainstorms, draw diagrams and make lists of pros-and-cons. I use as many visual aids as I can get. I play devil's advocate with my own ideas until I'm at my mental limit and I cannot visualize the solution (and requirements) in any more detail and cannot identify any other hurdles. It actually feels like playing chess. You need a strong understanding of your tools and environment to be able to do do this kind of adversarial brainstorming and most importantly, you need time. Especially in the early stages of the project. The further along you are in the project, the less foresight you need.
- antaviana 3y agoReminds me of Mark Twain's quote "I didn't have time to write you a short letter, so I wrote you a long one."
- lproven 3y agoBlaise Pascal originally, I believe. https://quoteinvestigator.com/2012/04/28/shorter-letter/ https://quoteinvestigator.com/2012/04/28/shorter-letter/ Great line, though. I use it a lot.
- cb321 3y agohttps://github.com/mit-pdos/xv6-public https://github.com/mit-pdos/xv6-public has under 10,000 lines of C and assembly including some user space programs.
- raverbashing 3y agoLet me guess, very lax security checks, bound checks, size checks, invalid values, etc
- JoeAltmaier 3y agoThe whole point of writing Unix was in response to bloated feature-cluttered OSs of the time, e.g. Multix. It was an effort in minimum feature set to cover all OS necessities.
- uaeu321321 3y agoFrom one answer: > Linux, before all these features and bloat were added, as originally released as a crude kernel for 386 machines Developers surely like to say anything they don't care about is "bloat", don't they? This "bloat" is what makes Linux usable everywhere.
- vidarh 3y agoIt's unsurprising when you consider that there are often several magnitudes of difference in code between what code grows to when you have the capacity and time and compounding user requests, and what a meaningful starting point that provides useful functionality above and beyond what you had without it looks like. As an extreme example here[1] is an article by Brian Kernighan about a basic regexp matcher by Rob Pike. The code, with comments, is 35 lines of C. Meanwhile, the regexp engine in Ruby 3.2.2, not even including the Regexp class visible to the language, is ~20597 lines excluding the headers. They are not reasonably comparable, of course. Pike's code provides a very basic syntax which doesn't even support character classes, and does nothing to speed up the matching. The latter supports a very much more complex syntax, and is far faster for repeated or long matches. But while Ruby's regexp engine is 588 times large than Pike's code, you of course get a vastly higher boost in overall system capability from those first 35 lines of code (from no regexp matching to some regexp matching) than the last 35 lines of code, or indeed the second 35 lines. So if you have a small system and a small team, you work with that and start small and it won't be that surprising when you get a lot done in few lines of code, even though you have a long list of things you'll add when you can justify the extra resources (like those missing language classes, and a billion other features) (Then you get a larger system, and you'll very soon find yourself wondering how you could manage with so little) I think it's mostly surprising because most developers today aren't used to thinking about capacity constraints of small systems, and so starts designing for lots of features from the start (can't have regexps without character classes, and capture groups, and back-references, and ...). [1] https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html https://www.cs.princeton.edu/courses/archive/spr09/cos333/be...
- MichaelZuo 3y agoA classic example of diminishing marginal returns.
- hinkley 3y agoToy solutions deal with small data inputs. How many lines of that 20k is just optimizing for large inputs (you can’t have long repeating sections in small inputs).
- DayOfTheSeal 3y agoThere was no complex stuff like SMP, no netfilter or similar. Software in and before the 90s was written with extreme naivety; buffers would be blindly allocated / assumed based on user (even network) supplied input. This makes code much simpler, even with bloated designs like UNIX. If you think about it, UNIX actually can't even be defined, you just have a way to execute programs, some process management (in this case which is overly defined for no reason, with superfluous concepts like process groups), the UNIX file system with a permission model that only needs a hundred lines of code, and output (and input) just goes to a terminal that interprets it however it wants. It has no say on anything so that's why you have 13 different programming languages that all do the same thing, dumping files all over the place trying not to stomp on each other, a shell language which itself is so poorly defined that people aren't even sure if comparing something to empty string is portable, no standard way to pass around data (just strings, whose encoding changes every 5 years), even the encoding of file names. On the other hand, UNIX is bloated with garbage like `wall`, the ability to output text into another user's terminal, metadata all over the place with no discipline, like ps being able to see other users' command line including if they typed a password in it (security is a bonus but beside the point: you shouldn't expose data through an API that isn't explicitly needed for the purpose the API purports to serve). Stuff like hostnames, DNS, email, are built into the kernel in various ways. This could answer why it needs a whopping 13KLOC.
- kgr 3y agoUnlike previous OSes, UNIX provided the pipe facility to allow you to combine the functionality of many small programs. Ex. ls | grep ... | sort ... | more Before that every command-line program had to support the full suite of additional functionality like search, filtering, paging, etc. This UNIX/Pipe approach allowed for greater reuse and much less code. This is explained and simulated in this video: https://www.youtube.com/watch?v=3Ea3pkTCYx4 https://www.youtube.com/watch?v=3Ea3pkTCYx4
- mighmi 3y agoThank you for sharing that video! Your foam project looks fascinating too: https://github.com/kgrgreer/foam3 https://github.com/kgrgreer/foam3
- elteto 3y agoI disagree that it’s a human or subjective factor as others imply. Or at least to me it’s a secondary contributor. Back then, the hardware and peripherals were so much simpler. There was no graphical output for the original PDP where Unix was initially developed. Not even a terminal. There was no networking either. The features of the system were also rather basic (to us). And security wasn’t even a thing they thought about. Some code practices are what we now consider to be terrible, optimizing for the limitations of that time. So all in all, things have gotten so much more complex since then, and the size and complexity of the code has grown accordingly.
- Veliladon 3y ago> Some code practices are what we now consider to be terrible, optimizing for the limitations of that time. This. If you went back to 1972 when Dennis Ritchie was working on C and said "String literals should have an extra machine word for their length and strings should have yet another machine word for the capacity of their buffer" you'd be considered a moron for wasting so much memory.
- mavhc 3y agoDepends if you managed to explain why
- ajross 3y agoNot really. C was an iconoclast even at the time. Pascal was the en vogue language of the moment, and it used a length-prefixed string format. But sure: it's true that in (a half century of!) hindsight, C strings were probably a mistake. But don't sell null-terminated strings short either. C could play tricks that Pascal couldn't. Iterating over the characters of a string has a natural expression using the same compiler features as arrays. A pointer into the middle of a string was still a valid string. You could lex a string inline during parsing by adding termination to the end markers or whitespace, etc...
- Joker_vD 3y agoSo you just don't store the array's length near the arrays beginning but instead inside the slice-typed variable which lives somewhere else entirely. Boom, you got the best of the both worlds: trivial slicing and reliable bounds checking.
- dboreham 3y agoLots of unchecked error conditions and security vulnerabilities, apart from the ubiquitous "bloat".
- pca006132 3y agoNot necessary applicable to this case, but from my experience it is more about performance. If you want a solution that works, the solution is usually quite simple. But if you want something that is fast, you often need to do platform specific things, and use fast paths for 'special cases' that occur more often than the 'general case'. These things together will make your code more complicated, but get better performance. For example, memcpy can be implemented with a very simple loop, but platforms usually provide a much more complicated memcpy that uses vectorization and cache prefetching to get better performance. Compiler autovectorization can give you better performance, but it still cannot beat the hand-tuned memcpy in general. Another example would be interpreters. You can write a very simple interpreter that works, but if you want better performance, you will need to throw in various techniques that may or may not be machine independent. And in this case, it is more about the algorithm and global invariant that the compiler cannot reason and optimize. Note: I am not saying that all the code are necessary, I just argue that sometimes you need to sacrifice succinct code to get better performance, and this tradeoff is worthwhile for such a low level infrastructure that everyone depends on.
- daxfohl 3y agoAny way to reasonably estimate how long it would take to compile back then? The PDP-11 was 1.25 MHz, Would it be roughly 4000x slower than compiling a 13K-line C program on a modern CPU? Or are computer architectures so much different that CPU speed isn't the primary factor?
- hnfong 3y agoC compilers can be very fast. (See for example, https://bellard.org/tcc/tccboot.html https://bellard.org/tcc/tccboot.html ) If I'm not mistaken, much of the work when compiling code these days are optimizations.
- retrac 3y agoCompilers vary greatly in their complexity. In particular, optimization is a truly open-ended task, which can consume however much CPU time and memory as you're willing to throw at it. GCC and LLVM today are much more sophisticated than anything around in the 1970s or 1980s. They will chew up the entire program, transform it into an enormous (many megabyte or gigabyte) graph abstractly representing the program, and then spend hundreds of billions of cycles, exploring possible rewrites of this graph, that make the program faster or more efficient. In comparison, early compilers, including the first C compiler, usually worked on a single statement at a time, immediately translating it into equivalent machine code. It never examines the whole program together, as there wasn't enough RAM in those machines to do that. This produces inefficient code, but it's very fast to compile. In fact, accommodating the memory limits of machines like the PDP-11 influenced much of C's design. It's why everything has to be declared before use, for example. That way less state needs to be kept to resolve forward references.
- inkyoto 3y agoPeople did not compile the kernel back then. The kernel was supplied in a precompiled form as a collection of object (.o) files, and there was a kernel «generation» shell script that would ask questions about which parts of the kernel were required (e.g. which device drivers to link in), what to set certain kernel parameters to (e.g. the number and the size of I/O buffers for the page cache had not been invented yet and neither had been «sysctl»), and – after jumping through the hooves of the very detailed and thorough interview with the kernel generation script – it would link the /unix kernel a.out image. It took several hours to get the final product. The source code was distributed on a tape but it was not customary to compile the kernel from scratch every time.
- pjdesno 3y agoIt's really simple - the early Unix kernel had so few lines of code because the machine had so few bytes of memory (180KB I think), and a bigger kernel wouldn't have fit. It's actually worse than that, because the PDP-11 address space was 16 bits, so the kernel had to be <64KB. It really only had two types of devices - the disk and the serial ports. No network protocols, and a single very simple file system. Basically no virtual memory - it had segmentation, and most memory management was done by swapping processes to disk. More complexity would have to wait for bigger machines with more memory.
- samjohnation111 3y ago[dead]
- PaulHoule 3y agoAs mentioned in one of the comments in those threads, a lot of the code in an OS is device drivers, and I'd say that device drivers in the PDP-11 were really simple. You didn't have the multiple layers of serial bus such as PCIe, USB, etc. There was no multiprocessor support, very simple filesystems, probably less than 10% of the POSIX API we know and swear at today was implemented. Simple I/O was one reason why DEC's minicomputers held their own against the IBM 360, it was easy to make your own Unibus peripherals, whereas peripherals for the 360 required a highly complex "channel" processor; bulk I/O was crazy fast on the 360 but interrupt handling was slow: the PDP-11 could handle individual keystrokes from a serial terminal whereas the 360 would wait until you'd filled out a whole screen of data and hit the SEND key. I never used Unix on a PDP-11 but I did use RSTS/E and OS of that generation did not dynamically find hardware, instead you would have to rebuild an OS image with the configuration for your setup built in. Thus the PDP-11 expected a control terminal and bootstrap device to be installed on certain ports and you would load some software to build an OS image that you would actually boot up. (Also true of the 360) https://en.wikipedia.org/wiki/RSTS/E https://en.wikipedia.org/wiki/RSTS/E That dynamism is itself a huge complexity source in modern OS, see Linus' Torvalds comments here https://www.linuxjournal.com/article/7279 https://www.linuxjournal.com/article/7279 and particularly what he has said about ACPI there and in other places https://yarchive.net/comp/linux/acpi.html https://yarchive.net/comp/linux/acpi.html Before Linux it was common in an OS class to write a boot loader, that was about all you could do in a semester. After Linux you can write a few kernel modules and learn a lot more. If you tried to write a boot loader today it might be an assignment for two semesters for the whole class because today's boot loaders are crazy complex to what they were in the day but you do get some functionality (think of what it takes to be able to boot a live linux distro off a USB stick that has a FAT file system off it.)
- cmrdporcupine 3y agoIn large part what a modern Unix-like operating system is... is a kind of emulator that makes the very insanely complicated and powerful machines of today look as simple and understandable as a PDP/11. I think of the Linux kernel (in conjunction with some complicated hardware support) as a giant behemoth of code there to maintain the illusion of a set of relatively understandable clean abstractions: memory, tty, display, network, process, user, file system. None of those things are nearly as simple as the mental model we maintain of them, but the OS makes it look that way. They're actually insanely complicated underneath because of real world reasons. The code in the kernel is in large part there to hide that. That code wasn't needed in early operating systems because the underlying hardware system actually was that simple. ... But with hypervisors on the scene now, and virtualization the common way to run applications in the "cloud", it's now entirely conceivable that the "unikernel" type approach could create bespoke software systems out of only the pieces needed for a given application or service on a given platform, and ditch the rest. The win is potentially a more holistically understandable system, in addition to the potential for targeted optimization.
- retrac 3y ago> is a kind of emulator From what I've read I get the impression that for a while in the 1960s and 1970s, the terms "process" and "virtual machine" were interchangeable. I don't feel that was a mistake, and today we make an arbitrary excessive distinction between them. They are the same concept, just implemented in a slightly different way. From both the program's and the programmer's perspective, a process under a Unix-like is a virtual machine. A very nice virtual machine, too. It has approximately infinite memory, can operate in parallel with an arbitrary number of parallel machines, and the kernel API can be thought of as an enriched and very sophisticated instruction set.
- slackfan 3y agoA proposed axiom: The value and function of any program is inversely proportional to its' length.
- adamnemecek 3y agoIt had few features.
- gumby 3y agoIt's interesting where peoples' heads are. A number of people talk about device drivers, but back then few OSes ran on more than one kind of machine, and hardware didn't change much. So there wasn't much separation between hardware and software: you wanted a block of data written to disk, well, the filesystem implemented the code to twiddle the disk hardware directly. Unix was unusual in that it was written in a pretty high level language, an idea inherited from Multics. Most OSes were written in assembly.
- thequux 3y agoNormally, the filesystem wouldn't directly twiddle the disk hardware; even on the PDP-11, you had a bewildering array of disk types: fixed head RC disks, single platter RL01/RL02, multi-platter RK01-RK07, RP disks that were a somewhat more advanced RK (but completely different interface), Massbus disks like the RM04, MSCP disks which were a very weird beast (the programming interface was not entirely unlike io_uring), etc. (to say nothing of the 4 different tape drive interfaces, two different floppy drives, and a mind-numbing array of serial interfaces) v6 unix already had support for most of these, and even the famously tiny RT-11 (which would happily run with 8k of core for the kernel) supported multiple different types of disks at the same time.
- gumby 3y agoYes but the question was about the original PDP-7 implementation of Unix, not the port/rewrite for a large volume (by the standards of the day) machine like the -11.
- compiler-guy 3y agoJoel Spolsky has a terrific article about where all the extra lines come from and why mature codebases tend not to feel as clean. “ Yes, I know, it’s just a simple function to display a window, but it has grown little hairs and stuff on it and nobody knows why. Well, I’ll tell you why: those are bug fixes. One of them fixes that bug that Nancy had when she tried to install the thing on a computer that didn’t have Internet Explorer. Another one fixes that bug that occurs in low memory conditions. Another one fixes that bug that occurred when the file is on a floppy disk and the user yanks out the disk in the middle. That LoadLibrary call is ugly but it makes the code work on old versions of Windows 95.” https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/ https://www.joelonsoftware.com/2000/04/06/things-you-should-...
- ipnon 3y agoThings are much easier when you only need it to run on a single PDP-11 at Bell Labs.
- knorker 3y agoSame reason you can write a proof of concept in a weekend, but the production version can take years. The web's best example is twitter. Anyone can write a twitter clone in a weekend. A reasonably competent programmer can create a multiuser twitter clone in under an hour. But you can't write twitter in an hour. It's amazing how much you can write when your requirements are much smaller. Also if you write your Unix for exactly one hardware, then you don't need two serial port drivers. And therefore you don't even need a serial port driver abstraction API.
- pixl97 3y agoWriting the POC takes 90% of the time, writing the code to deal with the edge cases takes the other 90% of the time! Or another one I like to say. It takes a few lines of code to deal with the right answer. A few lines code to deal with the wrong answer. And an absolutely massive amount of code to deal with Russell's Paradox.
- failuser 3y agoError handling? What error handling? Corner cases, what corner cases? The software industry still suffers greatly from the decisions made in UNIX. Only the SUID bit caused so much trouble. It’s crazy to this that we still have /usr/bin, /home and /bin only because the original UNIX machine had 3 disks in the system. Bazaar wins, I guess.
- xenadu02 3y agoEarly Unix switched contexts by writing the current process out to disk, loading the next runnable process, then jumping to it. Besides that overhead being far too slow in modern terms it also did not admit threads nor multiple concurrent cores. There was no need to consider atomic operations or even locks to a large degree. Most people wouldn't appreciate minimalism if they had to use such software on a daily basis.
- nijave 3y agoNot sure specifically about early Unix but it seems system reliability and error recovery have improved quite a bit. Hardware devices and subsystems can crash and recover without the user noticing or only seeing a slight delay.