- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
#define min(t1,t2) -273.15
Admin
The code would be correct if it were "max(pty_fd, net_fd)+1". Assuming, of course, that max() itself were correct.
Admin
#define 16 strlen("WTF")
Admin
Reminds me of the bug in some IBM360 assembler which was traced to
R4 EQU 5
(That's right, the name R4 addressed register 5. Not the usual way of doing things.)
Admin
I was working on a system which built reports using a proprietary in-house system which was actually really well-designed and fun to use (ah, happy days). The text for the descriptors of the lines on those reports were held in a static file which was maintained by whoever it was tasked with the job.
Then one day one of my team approached with: "I changed the labels, but when I re-ran the report, it still shows me all the old labels." Probably something silly, like the wrong labels file was being used, or the wrong program, or whatever. Nope, all looked correct. New labels file, old labels. Nothing untoward in the make file, everything in there as supposed to be. Time to inspect the code. Let's look at the init routine. WHAT! Someone had written a routine which deliberately overwrote the contents of the variables populated from the labels file with the exact same data as had been put there from the labels file. The upshot was that it just looked as though the labels file had not been changed.
I wondered at that stage whether I'd been pranked. The possibility wasn't remote. But I calmly said, "There's your problem, right there. Go and find out who did this and for what reason, and you can take it from there, I trust?"
I miss that job.
Admin
Uhm, nope. Well, as Anonymous Pedant said it is wrong, but way less wrong than you think.
Admin
There's nothing weird about select. You just have to carefully RTFM.
But this WTF is a cute little time bomb :)
Admin
truly we are in a post-truth society.
Admin
It is less wrong to say select() is the easiest system call to understand, but it's much wrongerer to say that max(x, y) is 16 (instead of a suspension bridge).
Admin
"and Alan assumed that was where the root issue lied."
This means that the root issue told falsehoods. What you should have written was
"and Alan assumed that was where the root issue lay."
or
"and Alan assumed that was where the root issue was to be found."
Admin
TRWTF is that Remy didn't read the docs for select.
Remy: Oh, I did. But I didn't understand them. That's not the worst man page I've ever seen, but it's up there.
Admin
TRWTF is using select() instead of epoll(), where the performance is O(number of fds) instead of O(largest fd).
Incidentally, this code would work just fine on Windows, since Winsock completely ignores the nfds parameter, which is included only for compatibility with BSD sockets. Windows socket handles are opaque pointer-sized handle values, so anything that scaled in O(that) would be completely useless.
Admin
epoll() wasn't available in the early '90s. And, given that FD_SETSIZE is (presumably) 16 on the platform in question, it's fair to say that we're talking early '90s.
Nope, the real WTF is what Remy says it is -- redefining the system macro MAX() just so your comms code works.
Admin
Perhaps I shouldn't have mixed a serious response with a tongue-in-cheek response. Yes, obviously redefining max() is TRWTF.
Admin
From the select() man page: “ nfds should be set to the highest-numbered file descriptor in any of the three sets, plus 1”
So notwithstanding the redefinition of max(), the code is “correct”, as in it should be max(). Also, it basically tells the system call how high up to analyze the array of bits, so as long as the file descriptors are 15 or less then the code would actually work. As most Unix code in the 90s would basically fork() on an incoming connection, it’s very likely the FDs would have stayed under 15. I’m more concerned about the total lack of timeout in that code :)
If the code does NOT fork on incoming connections, then it’s ripe for a buffer overflow if the fd gets higher than FD_SETSIZE.
Admin
or maybe, "and Alan assumed that was who the root issue laid"
Admin
I suspect this was caused by a developer on the team called Max who just needed a temporary name for his macro :-)
Admin
I'm more interested in this part:
As an ABBA fan, I'm curious to hear what other Swedish pop bands were around. Time to build a Spotify playlist!
Admin
ABBA preceded the 90s, but surely you remember Rednex or Ace of Base? (Yes, Rednex are best known for Swedish cultural classics such as "Cotton-Eyed Joe" and "Spirit of the Hawk". ;-) )
Admin
That max function reminds me ... I just read recently somewhere ... A programmer was assigned to "write a function that returns today's date" in a certain format. He wrote the function on Sept 12, 2014, so the complete body of his function was 'return "Sept 12, 2014"'. Because that was "today's date". He met the requirements.
Admin
'From the select() man page: “ nfds should be set to the highest-numbered file descriptor in any of the three sets, plus 1”. So notwithstanding the redefinition of max(), the code is “correct”, as in it should be max().'
Um, no. If my two fds are 3 and 5, I need to pass nfds=6 so that select will look at the first 6 fds: 0, 1, 2, 3, 4, 5. So max()+1 is correct. for a sanity check, I scanned the code base for a networking program that I'm working on; "select(max_fd+1," appears several times.
Admin
That's not quite true, yes, select() is O(nfds), where "nfds" is, as others have stated before, the max. fd plus one, s, and even if we assume nfds is limited to 1024 (glibc default), can be quite expensive. However, epoll() is not O(number of fds), instead, poll() is (approximately?) O(number of fds) whereas the epoll() API consists of multiple syscalls to set up the watch fd and then, presumably repeated, calls to epoll(). I'm not sure what the setup costs, but for N fds, it will hardly be less than O(N). The epoll() call itself, on the other hand, is claimed to be very efficient, possibly even O(1).
epoll() is therefore much more efficient when there are many waits compared to the initial setup. select() and poll() on the other hand, require no setup but more honestly the setup is performed once on every waiting operation.
You can try to derive some guidelines from this if you want … my own broad rules are:
Of course, a probably even better idea is to use a portable event library that does much or all of that low level fd juggling for you, e.g. libevent2 (C/C++) or Boost.Asio (C++).
*) If you need to wait for signals, then, of course, you should prefer pselect() over select() and ppoll() over poll().
Addendum 2019-10-24 06:00: Another reason to prefer poll() over epoll() is that it is portable to *BSD, and that includes Darwin (i.e. Mac OS). The native *BSD equivalent of epoll() is kqueue.
Admin
Auuuugh!!!! Who let all these hamsters in here, and why are they line-dancing on my screen!?