Saturday, August 29, 2009

Know What you Inherit

I ran into a couple of bugs recently that took longer than they should have to fix. Like all bugs, it seems obvious now that I know what was wrong but I think I spent a total of 5-6 hours investigating and fixing this across multiple platforms (hey, this is what makes developing software fun!). Here's hoping that those fancy search engines will help someone else find this post and save them time incase they have a similar problem.

I was working on some code that launched another process. This is a fairly mundane task. Interestingly though, the process launched went on to kill its parent and re-launch another copy of the parent. So, process A is running and launches process B, which then kills A and launches A'. Sounds kinda simple, right?

Well, everything seemed to work until I noticed that some resources needed by A' weren't available (ports/files). That seemed odd, given that A had been using those same resources successfully, and those should now be available since A was gone. The title of the post gives it away, but the problem is that a fork causes child processes to inherit the file descriptors/handles of the parent, so the files/ports opened by A were inherited by B and subsequently by A'. This meant that they weren't really cleaned up by the OS when A exited. Hence A' could not re-open those resources (some were locked for exclusive use).

The really interesting aspect of this bug was how it manifest itself on different OSes and the different fixes.

On Windows, TCPView showed the ports in use by a "<non-existent>" process. The PID of this process was that of A, which was already gone by now and didn't show up in the list of running processes.

After some analytical debugging, I guessed that the handles were being inherited by the children resulting in these strange 'orphaned' ports. The solution on Windows was to use the CreateProcess API with the 'bInheritHandles' flag to FALSE. Problem solved. By the way, the not existent process IDs attached to those ports seem to imply that the OS tracks ownership by processID, and hence cannot validate that the new owner of these is the child process now that the parent is dead - the child obviously has a different process ID. This might not be really how it's done, but seems logical.

The Mac was much more interesting. The manifestation of the problem was simply unavailability of the resources. There isn't an equivalent of the bInheritHandles flag for the fork command on UNIX. To cut to the chase, the solution was to fork the process, close all open file descriptors that it inherits and then call exec.

Now, the Mac guys have added a nifty 'open' command to the system which helps launch processes as a child of the launchd process, which doesn't inherit the callers file descriptors (it's parent is the launchd process). However, this open command has a couple of pretty severe limitations. It can only open app bundles, not native binaries. And you can't pass in command line arguments to the application you open. FAIL on both counts! Mac purists will claim that command line arguments aren't the 'right thing' on the Mac, and that Apple Events should be used instead. That's BS, really. For anyone writing platform independent C++ code, it's just not practical. People don't realize that not every app on the Mac is a Cocoa/Carbon app. Anyways, so on OS X I needed to be a little creative and have A launch B, but before doing anything useful in B enumerate all open file descriptors and close them (readdir() /dev/fd on FreeBSD and Darwin enumerates all open file descriptors). Oh and by the way, you might not want to close FDs 0, 1 and 2 - they're stdin, stdout and stderr respectively. This post on StackOverflow has some good related information incase you're curious.

Friday, August 7, 2009

To Every Web/UI Developer I've Scoffed At - Apologies!

I am/was a cocky programmer. Having only worked on system and application level programming thus far, I really didn't appreciate how hard building a good, usable website or application is. I knew that an application or a system is only as good as how usable it is, but I really considered usability to be a 'simple' problem and by inference I assumed that writing the code behind what you see on a website or an application is also 'simple'. As my career matured I suspected I might be wrong, and now I know I was!

Over the last few weeks, I've been messing quite a bit with Html and CSS to make stuff look non-ugly and Javascript/Ajax to make stuff feel non-sluggish. And the combination of these together to make non-ugly things appear non-sluggish. Of course, this also means dealing with everything that goes on in the middle/backend to support non-sluggish, non-ugly things. Oh, and once you have something that's not ugly and not sluggish, you have to worry about the bad guys. Cross-site Scripting, Cross-site Request Forgery, cookie theft and poisoning, etc are things I didn't think much about previously. What cans of worm those are... !

And then a couple of months ago I spent some time making an mac application non-ugly and non-sluggish. Same deal, pretty much.

Working on these new technologies sure feels like being a kid in a candy store, but I have to confess my new found respect for good UI/Web developers (and I am not one, by a long shot). I may have snickered behind your backs previously, but it sure won't happen again!

Thursday, August 6, 2009

What's your time worth?

One of the hardest questions I often find myself needing to answer is what my time is worth. Simple everyday decisions are influenced by what the answer to this question is - Should I get groceries from the store myself, or order online? Should I clean my own apartment or hire a professional? Should I contest the parking ticket by mail, in person or simply pay it? Should I go out an enjoy the weather instead of working overtime?

Of course, the right answer in most cases depends on more than just how you value your time. Tangible (I might pick better produce in person than online, or a professional could do a better job cleaning my apartment than I can) and non-tangible (I get to experience the judicial process at the municipal court myself if I contest a ticket in person) factors can sometimes influence these decision more than the absolute value of your time, and generally it's a combination of these factors + the value of your time which leads to the right answer.

What factors influence how you derive the value of your time? Here's a quick list of things I could think of:
  • Your age relative to life expectancy. Generally, the older you get the more valuable your time is. Time does run out eventually, afterall.
  • Real dollar value of gains from alternate activities you could be engaged in versus the intended activity. If you're paid by the minute on your job, the dollar value of every minute your spend in the break room outside of the allowed times better be worth more than your per-minute salary.
  • The intangible value of alternate activities you could be engaged in versus the intended activity. Heh - good luck figuring this out!
  • The tangible and intangible deferred value/costs of making a decision. Not feeding the parking meter in favor of enjoying your cup of coffee by the lake will cost you $25 next week.
  • Risk associated with the decision you make. You're quite likely to hurt yourself sawing wood, and depending on how badly you're injured you could easily outspend in medical bills what you would have paid a professional instead. Again, look luck quantifying risk.
What else do you consider when deciding one way or another?