Kernel events without kevents
Posted Mar 17, 2007 11:59 UTC (Sat) by pphaneuf
In reply to: Kernel events without kevents
Parent article: Kernel events without kevents
64 is a pretty low number of objects, I'd say, but it depends on the design. It seems more oriented to a "one thread per connection" design, where a single connection could be handling a few things (waiting for an answer from a database, but also watching the socket for disconnection, say). Also, the way it can easily lead to starvation seems like a major design problem with it. Careless ordering of the list of handles could lead to a stuck process! Odd, that.
I both agree and disagree with your reply. Win32 had advanced capabilities for a long time, such as completion ports (although I think they were severely crippled on the non-NT platforms, if I recall correctly). We still don't have many of those on Linux, and POSIX itself is so out of date, it's practically irrelevant. If you want to do something high-performance that works on multiple Unix platforms, you have to invent your own abstraction for the various high-performance APIs, because POSIX is just too pathetic. Sure, you can also make a POSIX version for complete portability, but you just know that this one isn't going to be the one for high-performance requirements.
It's a kind strange, comparing the two APIs. I feel that the Win32 is a bit more integrated, yes, having had this stuff for a longer time (everything is an object with a handle, that can be given to WaitForMultipleObjects()), but somehow doesn't feel like that (reading from a socket with ReadFile() seems a bit odd).
The classic Unix API feels more tasteful, but seems to suffer from some rot. For example, newer additions, like threads, feels like they are crummy copies of other APIs, not fitting in well with the rest. For example, what you say about poll() not being able to wait on a number of things is really mostly linked to those new things (mostly related to threads) not having been made file descriptors in the first place! Remember that file descriptors are more or less the Unix equivalent of handles, despite having the name "file" in it (it's the "everything is a file" concept).
The signals are the exception (and thus, waiting for child processes), but that's by design. There are only two ways to affect a Unix process, synchronously (but not necessarily blocking) through a file descriptor, or asynchronously through a signal. And there are bridges to go from one to another (SIGIO to make file descriptor asynchronous, and pipes to turn signals into a synchronous event). The signal and pipe trick might sound hacky, but really, it's a matter of keeping the core simple, providing lightweight primitives that can be built upon to make the same effect.
It helps to remember Windows NT heritage from VMS, which had a number of distinct file types, that were opened and accessed completely differently, including a B-Tree file type. Think about it: on VMS, there was the equivalent of Berkeley DB in the kernel! Where on Unix, the philosophy is more that we'll give you the tools to write Berkeley DB, and you go from there. Hence my not being incredibly excited about signalfd(): it's nice, but not exceedingly so, since I could easily do without.
In my Windows code I've always tried at all cost to avoid using window messages for anything besides "pure" UI - in my experience they make the code very fragile (and obviously non-portable). You also have the problem that UI operations performance can limit your background tasks. I am not aware of any contemporary Win32 non-GUI API that relies on messages. (Win16 sockets used to, but that has been deprecated in Win32)
You mention UI operations limiting your "background" tasks. This is always true, for a single thread, as really there isn't one that's foreground and the other that's background, they're all equals, competing for execution on a thread. If your UI is giving you grief, the answer isn't necessarily to stop using messages, but to have another thread, so that there's more execution contexts to do the work. Ideally, it would all be so uniform that UI code could run on any thread as well, so things would just get done as quickly as possible, no matter what it is, nothing having the edge over the other.
to post comments)