4 ms·
Perhaps getting into no true ship of theseus territory, but you can redefine read/write to do anything but it's arguable if that's still the same philosophy. Li
by tedunangst 7y ago
Perhaps getting into no true ship of theseus territory, but you can redefine read/write to do anything but it's arguable if that's still the same philosophy. Like, why even have open()? You could start each process with "/" already open, and then open other files by writing "open /etc/passwd" and reading back a new fd.
- kragen 7y agoYeah, so, is there a there there? I think there is. The open/close/read/write/getdents interface at least offers the possibility of certain kinds of REST-like uniformity, providing some benefits: - A thin hourglass-waist interface makes it relatively easy to add new components to the system, whether clients, servers, or proxies. Plan 9 implemented both network fileservice and GUI windowing as filesystem-interface proxies, and they composed properly, allowing you to remote your windowing system over the network and to test new versions of the windowing system in a window. Less remarked on is the fact that if you need 500 system calls to invoke the full functionality of your operating system, most of those calls are going to remain inaccessible to newly ported scripting languages until you write a C extension module for them; and if implementing a fileserver involves handling hundreds of protocol messages, you aren't going to have very many kinds of fileservers. (CIFS, as far as I know, has only two: Windows and Samba.) ioctl and its demonspawn brethren are the reason we didn't have rr in the 1990s, when Michael Elizabeth Chastain wrote mec-replay. - Putting all the system resources into a single namespace means that you can handle them uniformly in some other ways, like setting permissions and interactively exploring the hierarchy. - A lot of system state can be meaningfully treated as data that can be either read or written, with certain useful properties: if you write and then read, then what you read is what you wrote (or is, unless there was an error or a subsequent state change), and if you write back something you read at some previous time, you restore it to the state it had at that time. The framebuffer is one example from Plan 9. The contents of NVRAM are a thing it might be more important to be able to back up and restore in this way. - Also, byte-oriented things don't care what size your reads and writes are; you read the same sequence of bytes whether you read them one at a time or a million at a time. Usually. - Naming things with strings means you can add more things later without breaking backward compatibility. - A slightly richer interface that provides cache invalidation notifications (like inotify) can enable caching proxies and polling proxies, which are sort of dual to each other. Application containers (like Docker, but also like Vesta's build environment, and like rr) can provide isolation, reproducibility, observability, and auditing, but the difficulty of building them is multiplied by the number of different namespaces and system calls they need to interpose on. - It's useful to unify the interprocess communication interface for sending a series of employee records from one process to another with the interface for writing them to a file, a tape, or a terminal, and the interface for receiving them from a file, a tape, or a terminal. script(1) and ttyrec and their kin take advantage of this polymorphic interface to make it possible to replay a terminal session later. Unfortunately as far as I know nobody has implemented a system that lets you record and play back GUI screencasts or mouse-click test scripts in such a simple way. Now, open/close/read/write is really oriented toward the last point more than anything else, treating files as nothing more than recorded output streams that can be replayed. And you lose it if you start reading and writing multiple files! There are other uniform interfaces that have similar benefits for composability; SNMP provides one, REST provides another, and Named Data Networking proposes a third, one which unifies asynchronous notifications with satisfaction of read requests, which is sort of what Unix does too, except that as Benno complains, in Unix you have to bend over backwards to wait for any of multiple events, the polar opposite of the Win16 message loop. (Hilariously, as Benno points out, the Win32 APIs for nonblocking file and socket access are a total mess.) The particular set of restrictions imposed by your chosen architectural style and protocols will determine what kinds of things you can do to your system once you have it running. Surely we can do better than the Unix filesystem interface in 2020.