LWN.net Logo

Google's behavior makes sense

Google's behavior makes sense

Posted Jul 12, 2009 8:47 UTC (Sun) by quotemstr (subscriber, #45331)
In reply to: Google's behavior makes sense by mikov
Parent article: Google Chrome OS and the community

POSIX in particular is horrible
Care to back this claim up? Name a particular thing you'd couldn't implement without breaking POSIX. There are many things that are broken, but POSIX isn't all that bad.


(Log in to post comments)

Google's behavior makes sense

Posted Jul 13, 2009 1:32 UTC (Mon) by mikov (subscriber, #33179) [Link]

Obviously you can implement anything with a sufficient amount of effort - but it is still a bad API full of kludges. The only thing really going for POSIX is that it is real and ultimately is an useful standard (in the sense that you can use it to get work done).

Anytime I browse through Stevens'es seminal books I want to cry - the books are great but what they are describing is a mess.

If you take the core Win32 API for comparison - only the IO operations and thread management - it is really clean and orthogonal, quite unlike POSIX. (Note that I am not necessarily saying that Win32's philosophy is better; only that the API is much cleaner).

One example of the POSIX mess that comes to mind is fork()/wait()/SIGCHLD/zombie processes/etc. Compare that to Win32's simple and straight-forward approach of WaitForMultipleObjects()/GetExitCodeProcess()/CloseHandle().

In an ideal world I would have liked most of the POSIX semantics with Win32's cleanness and orthogonality. (Well, WaitForMultipleObjects() woudln't hurt either)

Google's behavior makes sense

Posted Jul 13, 2009 2:05 UTC (Mon) by quotemstr (subscriber, #45331) [Link]

If you take the core Win32 API for comparison - only the IO operations and thread management - it is really clean and orthogonal, quite unlike POSIX
Clean and orthagonal? Like the WaitForMultipleObjects arbitrary 64-object limitation? Like the inability to wait on sockets using the thing without a WSAEventSelect? But wait -- if two threads are waiting on a single socket using WSAEventSelect, the second thread's event notification silently overwrites the first: i.e., only one thread can really wait on a given socket at a time.) How about the mess that's the named pipe interface, and its bastard stepchild, the anoymous pipe interface? How about having to care about the distinction between MsgWaitForMultipleObjects and WaitForMultipleObjects? And how on earth is it clean for COM initialization to implicitly create a GUI window for the thread?

Or how about the fact that sockets are in an undefined state after timing out? How about the horror that is CreateProcess, compared to fork? How about condition variables only being introduced in Windows Vista? How about the half of the functions that return NULL for failure and the half that return INVALID_HANDLE_VALUE?

What about handle inheritance? This deserves its own paragraph. Win32 can pass a HANDLE (for some objects) from a parent process to a child object, but unless you make that HANDLE one of the standard descriptors of a process (i..e, stdin, stdout, or stderr), you need to pass the *numeric value* of the handle to the child through some other mechanism (say, a command-line parameter), have the child pick that value up, and start using it. It's a kludge. Even SCM_RIGHTS is clean compared to that.

Granted, the Win32 event stuff is better than the rest of Win32. But while the worst part of POSIX is the setuid/seteuid mess, the setuid kind of arbitrary ugliness is par for the entire win32 API.

Google's behavior makes sense

Posted Jul 13, 2009 3:02 UTC (Mon) by mikov (subscriber, #33179) [Link]

As I said, I was not trying to compare Win32 and POSIX, nor their specific implementations - only the relative cleanliness of the (specific subset of the) APIs.

Also, I explicitly restricted my qualification to core "IO operations and thread management". Most of problems you raised relate to Winsock or User32 or COM, and so are completely beside the point.

I agree that ideally WaitForMultipleObjects() should have a much larger limit, but that doesn't negate the fact that it is conceptually a very clean and powerful API. Read/WriteFile[Ex], GetOverlappedResult, CancelIO, etc (even DeviceIoControl) - it is all very very simple and orthogonal.

The thread management and the IO use the same APIs. You can wait on anything (including custom IOCTLs!) using the same call, you also have a useful set of atomic operations (InterlockedXXX()).

I think that there is no need to compare this in detail to POSIX.

POSIX is what it is. It wasn't an effort to define a new clean API - it simply ratified the existing state of affairs, which had grown organically. It was a success because it exists and is portable and there are implementations from multiple vendors.

But we can't lie to ourselves by pretending that it is elegant or orthogonal or anything but a horrible mess.

Google's behavior makes sense

Posted Jul 13, 2009 10:57 UTC (Mon) by jlokier (guest, #52227) [Link]

I've spent a huge amount of time working with POSIX on lots of platforms, and with WIN32 in the areas of I/O, events and threads to a lesser extent.

WaitForMultipleEvents is not a strong point of WIN32 because it has so many limitations, and because you need to deal with the windows message queue and Winsock differently, and async I/O has lots of ways to report status, each with different performance characteristics and working with different versions of Windows. Apart from waiting for events and objects, there's APCs and Completion Ports and Vista's GetQueuedCompletionStatusEx, and you can wait on I/O handles or OVERLAPPED objects. For some things you need to create a "window" to receive events, though it's not really a "GUI window" as another post suggests, just a Windows object for demultiplexing the message queue.

POSIX is equally ugly when it comes to waiting for different things at the same time: select, aio_suspend, semop. With POSIX and WIN32 both, you have to use threads to wait for different classes of thing together. Like WIN32, POSIX select() has a fixed limit on the number of handles you can wait for: FD_SETSIZE, typically 256. Like WIN32, there are methods and alternate APIs to overcome the limits.

WIN32 I/O API is quite sensible. Basically equivalent to POSIX with a few extra options, and longer names for things. It's always had async I/O, and the I/O event dispatch is versatile (too versatile: no less than 4 ways to wait for async I/O), though awkwardly the different options aren't orthogonal. However, in practice you can't use all the options on all versions of Windows in every combination; it's not as orthogonal as it looks. The async I/O doesn't work on every version, and lacks important functionality prior to Vista.

It's all much the same as Linux really. WIN32 API is better documented and makes sense, but has a bunch of limitations and version-specificity, which isn't very well documented. Linux is similar when you use the non-POSIX APIs like epoll and eventfd.

WIN32's DLLs are a mess compared with ELF. Especially dynamically loading - enjoy the crashes, lockups (prior to Vista) and lack of load-time initialisation. People have to stick to certain patterns of DLL use to avoid the obscure problems which are quite nasty.

WIN32's threading primitives: mutexes, condition variables and so on were poor compared with POSIX threads, until Vista. Vista copies some of the good stuff and is comparable with Linux NPTL, that is to say, quite good. Vista's async I/O is better than Linux's and POSIX generally. But who wants to write Vista-specific code?

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds