Page 5 of 6

Re: To POSIX or not to POSIX

Posted: Wed Apr 15, 2020 1:44 pm
by Qbyte
linguofreak wrote:But since the driver in your model is just a userspace library that calls send_packet() to send packets to a particular device, what's to prevent a malicious userspace application (that may or may not have the driver loaded) from waiting for a device that can only accept one connection to have a connection, and then calling send_packet() in order to cause mayhem?
An application has to have permission to communicate with devices in the first place in order for a send_packet() system call to succeed. If it doesn't, the kernel will simply deny the operation, so that serves as the first layer of security. Secondly, when a connection is being attempted, the OS can ask the user if they permit the connection, which allows them to prevent malicious apps from taking over single connection devices. Finally the user can also, at any time, terminate and revoke an applications access to a device, so if an unwanted connection ever does occur, they can blacklist the offending application.
Or for that matter, how do you enforce filesystem permissions?
The filesystem is not considered a device in my OS (it's an abstraction) so the device driver model has no relation to it. Applications are not given direct access to the disk via send_packet(), unless they have been explicitly given root privileges.

Re: To POSIX or not to POSIX

Posted: Thu Apr 16, 2020 12:57 pm
by eekee
I'm a little confused. I thought the current topic is programs (with libraries) having direct access to hardware, but Qbyte's words make it seem as if the kernel mediates transfers. Does the kernel use the MMU and IOMMU to control access to hardware? I guess that would make sense.

Re: To POSIX or not to POSIX

Posted: Thu Apr 16, 2020 1:47 pm
by Qbyte
eekee wrote:I'm a little confused. I thought the current topic is programs (with libraries) having direct access to hardware, but Qbyte's words make it seem as if the kernel mediates transfers. Does the kernel use the MMU and IOMMU to control access to hardware? I guess that would make sense.
I mentioned a few posts back that the precise meaning of "direct access" depends on the specifics of the hardware platform. With hardware support, it means that applications can send network/port packets without even having to make a system call because the kernel can set up registers which control things like packet headers, max packet size, etc. Network cards have been doing this sort of thing for years. Without that kind of hardware support, applications still have direct access to devices (they can create and send their own payloads without the need for kernel-land drivers) but they have to make a system call so that the kernel can ensure that packet metadata isn't being spoofed by the application (ie, pretending to be a different application, etc).

Re: To POSIX or not to POSIX

Posted: Sat Apr 18, 2020 5:08 am
by eekee
Qbyte wrote:With hardware support, it means that applications can send network/port packets without even having to make a system call because the kernel can set up registers which control things like packet headers, max packet size, etc. Network cards have been doing this sort of thing for years.
I see, thanks, I didn't know that. What stops an application from writing to the setup registers?

Re: To POSIX or not to POSIX

Posted: Sat May 23, 2020 7:58 am
by nexos
My feeling about POSIX is that it is overly bloated. For example, take the exec functions. You have execl, execv, execle, execve, execlp, and execvp. They all do almost the exact same thing! I am making a Unix like operating system, but is not fully POSIX compliant. So I think going full on POSIX isn't bad, just very complicated do to the amount of functions POSIX contains.

Re: To POSIX or not to POSIX

Posted: Sat May 23, 2020 9:14 am
by iansjack
I'm not sure that you are not confusing versatility with bloat.

It is true that - in one sense - Unix is bloated; all those little commands that do just one specific thing rather than one swiss-army knife command that does everything. Others might consider this to be one of the strengths of Unix.

Re: To POSIX or not to POSIX

Posted: Sat May 23, 2020 10:08 am
by eekee
nexos wrote:execl, execv, execle, execve, execlp, and execvp.
Just noting, most of those specific examples are more due to the limitations of C than Unix. A language which is nicer about variable-length argument lists would only need 2, or maybe just 1 with a path search option.

Incidentally, Plan 9 only has 2, but it has no path-searching variants. I don't like that. :)

Re: To POSIX or not to POSIX

Posted: Sat May 23, 2020 11:50 am
by nexos
That is very true. I personally prefer the Win32 API, simply for cleaner function names, and because one function can be customized to do many things. But this is simply my coding style.

Re: To POSIX or not to POSIX

Posted: Sat May 23, 2020 12:43 pm
by OSwhatever
nexos wrote:That is very true. I personally prefer the Win32 API, simply for cleaner function names, and because one function can be customized to do many things. But this is simply my coding style.
The Win32 API is way better than POSIX in my opinion and it is obvious that it is a more modern OS API and it has aged quite well. The most obvious Achilles heel of POSIX is IO and that's where it shows it is ancient. Win32 handles IO much better and is more versatile.

There is one thing that I have discovered creating a non-POSIX operating system and that is defining good interfaces is extremely hard and I still sometimes have to go back and change the API because it didn't fit how different programs interacts with the OS. if you go the POSIX route you will bypass most of that hard work with designing interfaces and also have a lot of ready made SW at your disposal.

Re: To POSIX or not to POSIX

Posted: Sun May 24, 2020 10:48 pm
by nullplan
nexos wrote:My feeling about POSIX is that it is overly bloated. For example, take the exec functions. You have execl, execv, execle, execve, execlp, and execvp. They all do almost the exact same thing! I am making a Unix like operating system, but is not fully POSIX compliant. So I think going full on POSIX isn't bad, just very complicated do to the amount of functions POSIX contains.
You are aware that POSIX only standardizes functions, right? It does not care at all about which of these are system calls, or even if there are system calls they all call. For instance, in Linux, only execve is a system call, and all the others are library calls wrapping execve().

My problem with POSIX is more that it sometimes requires things that are impossible. For instance, all of these exec functions are supposed to be async-signal-safe. And among other things, that means they cannot allocate memory. Then they require all of the ones with a p at the end to try to execute a file, and if they see a ENOEXEC error, to try to execute the file with /bin/sh. Erm... where do I get the space from for an argument list containing that /bin/sh? In practice, some libraries use stack allocation (glibc, bionic), while some others simply ignore this requirement (musl, dietlibc). In musl, it is because Rich does not like the idea of unbounded run-time stack allocation, and who can blame him? It is an obvious source for exploits.
OSwhatever wrote:The Win32 API is way better than POSIX in my opinion and it is obvious that it is a more modern OS API and it has aged quite well. The most obvious Achilles heel of POSIX is IO and that's where it shows it is ancient. Win32 handles IO much better and is more versatile.
All of these are value judgments you made for yourself and have not justified here. I disagree with all of them. I think the Win32 API is an ungodly mess that happens when corporate coding style tries to build its own version of POSIX. That is why all of the Win32 function names are kilometers long, and have even longer argument lists, most of which end up being NULL most of the time. And the constant use of Hungarian notation has aged like a bowl of sour milk. As has the use of "LP" for "long pointers", because, you know, it is still 1995 and we need to tell between short and far pointers. The shouty style for type names is an eyesore, and typedef'ing pointers is an entrance to a special version of hell. It is a mistake many beginners make, so obviously many multi-million-dollar corporations (and some that are considerably more loaded than that) require this style even to this day. The Win32 API is the epitome of 90ies corporate programming, and it shows. It has single-handedly done more to damage coding guidelines than any other bad piece of software I can think of.

As for I/O, I have honestly no idea what you are talking about. You call read() or write(), and it requires an FD, a buffer, and a length. In Win32, you call ReadFile() or WriteFile(), and they require a handle, a buffer, and a length. And a pointer to the place where it tells you the return value, because obviously that could not have been put into the actual return value. Other than that the two are equivalent.

Re: To POSIX or not to POSIX

Posted: Mon May 25, 2020 9:44 am
by Korona
nullplan wrote:My problem with POSIX is more that it sometimes requires things that are impossible. For instance, all of these exec functions are supposed to be async-signal-safe. And among other things, that means they cannot allocate memory. Then they require all of the ones with a p at the end to try to execute a file, and if they see a ENOEXEC error, to try to execute the file with /bin/sh. Erm... where do I get the space from for an argument list containing that /bin/sh? In practice, some libraries use stack allocation (glibc, bionic), while some others simply ignore this requirement (musl, dietlibc). In musl, it is because Rich does not like the idea of unbounded run-time stack allocation, and who can blame him? It is an obvious source for exploits.
Your points are entirely correct, but you can actually build an allocator that's signal safe: "just" disable signals while allocating. This doesn't really work well on Linux because it requires another syscall. However, on Managarm, we do this to be able to perform IPC (which sometimes needs to allocate message buffers) in signal handlers. The latter is required in our system to implement stuff like write() which is async-signal-safe. To make this perform well, Managarm has a fast way to disable signals via an atomic variable in shared memory that is checked by the POSIX subsystem before entering a signal handler.

Re: To POSIX or not to POSIX

Posted: Thu May 28, 2020 7:24 am
by eekee
Funnily enough, I've been trying to live with a program which tries to do POSIX-style disk IO on Windows. Or rather, I'm using several, but one of them pushes the edge cases of POSIX IO to breaking point. It's a ZUI (zoomable) file manager called Eagle Mode. It's always reading many files at once to display them. Under Linux or Mac, this works very well until you try to read a CD-ROM and then the whole program stalls while waiting for the slow disk. Under FreeBSD, it would stutter a little bit - stall very briefly and often. Under Windows, it stalls so much it's barely usable. Windows with 8GB RAM, Core i5 and SSD is much worse than Linux or OS X with 4GB, Core 2 Quad, and physical hard disks. If this is a general Windows problem, how on Earth could it ever be used as a server? Lots of programs seem to get on fine with Windows. I know of one which doesn't but I think it also uses POSIX file calls, so what's going on?

There's one obvious problem with Eagle mode: it expects specific semantics which barely hold true even on POSIX systems - it expects synchronous file reads to be fast. Obviously, it should be multi-threaded, but my point Unix's seemingly simple file API and somewhat-good semantics have let Eagle Mode's author believe he could make this thing work without multi-threading. Now he's got this big codebase which is an awesome proof of concept, but needs really deep changes to be practical wherever synchronous file access is slow. Whether you're on full-bloatware Windows or you've left a 90s game CD-ROM in the drive of your lean, mean Linux machine, Eagle Mode gets impractically slow. (I told him this years ago, but he said it's too hard, and he's just continued to add features and make detail changes ever since. Including changing the script API regularly. I wish I could handle complex languages - emCore is nearly 41,000 lines of C++, emFileMan nearly 6,500.)

This brings me to a concept I've been wrestling with: Unix as conceived by Thompson and Ritchie was all about simple interfaces. They apparently didn't say so, or possibly other programmers argued until they stopped, but eventually Rob Pike made a statement about Linux's sysfs in relation to Plan 9: "The point isn't plain text interfaces, the point is simple interfaces." With a little knowledge of Unix history, it becomes clear that simple interfaces were also the main goal of Unix. In 1970 it was normal for file access to be complex, even unnecessarily difficult. Unix has a simple file API because simplicity was desired. (Other, more complex interfaces were added in Berkley (notably sockets), by commercial implementors, or perhaps in response to opposition within the Bell organization when Unix was part of the Programmer's Workbench system of 1972.) But it's not just simplicity, the idea seems to be to design the semantics of these simple interfaces to be good for a wide range of tasks. I'm wondering if that's really a good thing, because no 'wide range' can possibly be 'wide' enough. Expectations based on Unix file semantacs fall apart if the filesystem is slow or if it has non-Unix semantics. And Unix - or Plan 9 - file semantics place demands on the file servers which can be impossible to meet or lead to other problems.

I kept running into these limitations of simplicity in Plan 9. Plan 9's primary network filesystem seems simple and good, but suffers serious performance degradation over long-distance networks, and while it's possible to work around it, such workarounds would complexify every program on the system; even cat. The simplicity of cat is a point of pride for many Plan 9 users. ;) Then there's the difficulty of writing file servers for Plan 9. Plan 9 is like a microkernel OS which uses file streams for its IPC. So many things are simple on Plan 9, but not writing a file server. A guy I know once wrote, "everything I've ever wanted to do with computers, I can do with a few lines of shell script in Plan 9," but then he almost immediately found he had to write a mountain of C code because Plan 9's file semantics didn't fit what he was trying to do. Over and over again I had this experience with Plan 9: whatever I wanted to do seemed easy, I'd get it part-way done, but some detail would crop up requiring so much more work! Sometimes it would be usable without the extra work, sometimes not. I ended up wondering if Plan 9's appearance of simple interfaces was really a good thing. And now I'm wondering the same about the parts of POSIX which come from original Unix. These interfaces are deceptively simple, and I'm thinking that's not a good thing.


Separately, the last thing I read in depth about POSIX function difficulties, many years ago, was the impossibility of fully implementing select(). I don't know if the standard has been improved, but at the time, select() was supposed to be able to select between every possible type of input. Many OSs didn't bother.

Re: To POSIX or not to POSIX

Posted: Fri May 29, 2020 6:36 pm
by eekee
OSwhatever wrote:The Win32 API is way better than POSIX in my opinion and it is obvious that it is a more modern OS API and it has aged quite well. The most obvious Achilles heel of POSIX is IO and that's where it shows it is ancient. Win32 handles IO much better and is more versatile.
Something I keep forgetting: if you like parts of Windows, especially the kernel, take a look at OpenVMS. I'm told the NT kernel is practically identical to the VMS kernel. The guy who told me this declared Windows' kernel to be good, but "everything on top of it is a house of cards." It's not really surprising. The guy Microsoft hired to design the NT kernel was the guy in charge of designing VMS. (I think I even heard he was in breach of his contract with Digital when he worked for Microsoft in this capacity!) I wonder if the features you like are present in OpenVMS. It's only slightly newer than Unix but comes from a different background, one not obsessed with simplicity.

Re: To POSIX or not to POSIX

Posted: Sat May 30, 2020 4:28 am
by OSwhatever
nullplan wrote:As for I/O, I have honestly no idea what you are talking about. You call read() or write(), and it requires an FD, a buffer, and a length. In Win32, you call ReadFile() or WriteFile(), and they require a handle, a buffer, and a length. And a pointer to the place where it tells you the return value, because obviously that could not have been put into the actual return value. Other than that the two are equivalent.
Good that you brought up ReadFile() or WriteFile() because here the difference really shows. Win32 supports asynchronous IO.

https://docs.microsoft.com/en-us/window ... i-readfile
https://docs.microsoft.com/en-us/window ... overlapped

With the overlapped structure you can start an asynchronous operation and do synchronization when the operation is finished as well. POSIX completely lacks this which shows that POSIX was made during a time asynchronous IO was not a thing. Some of you will probably bring up select in order to support async IO but I consider that design to be very clumsy.

POSIX has asynchronous IO now but it is relatively young. Win32 was made in the 90s and got that part right from the get go. POSIX is not leading the way or cutting edge but is a follower here.

Re: To POSIX or not to POSIX

Posted: Sat May 30, 2020 5:48 am
by nullplan
OSwhatever wrote:Good that you brought up ReadFile() or WriteFile() because here the difference really shows. Win32 supports asynchronous IO.
[...]
With the overlapped structure you can start an asynchronous operation and do synchronization when the operation is finished as well. POSIX completely lacks this which shows that POSIX was made during a time asynchronous IO was not a thing. Some of you will probably bring up select in order to support async IO but I consider that design to be very clumsy.

POSIX has asynchronous IO now but it is relatively young. Win32 was made in the 90s and got that part right from the get go.
Erm... what is your point, then? Win32 got async IO earlier than POSIX? Alright, I suppose, but the functionality exists now. No, I will not bring up select()/poll()/epoll()/whatever your particular OS supports (there are many variations on that theme in the different UNIX flavors), since that doesn't do async IO. select() allows FD multiplexing, which is sort of similar to async IO but not the same. I mean, disk files for instance are always ready to read and write, at least on Linux, even if they are on Network file systems or otherwise slow connections.

No, the correct way to do async IO is not to do it at all, but rather use synchronous IO in multiple threads. This also allows for simpler control flow. The only other way to do async IO is to separate the data input path from the data output path (main loop switches between handling read and write). But this only requires a way to test for whether data is ready to be read. Which can also be done with a read() call on a socket that was set to nonblocking, and otherwise only requires a way to sleep until a time has elapsed or data is ready, which select() provides, but so do other things.

To summarize: I think POSIX and Win32 are equivalent in the area of IO, synchronous or otherwise. They might require different approaches for their quirks, but the things you can do with them are the same.