Matt Godbolt’s blog

Self-indulgent postings

Threading issues in the Windows Internet API

Imagine you were making a simple asynchronous HTTP request API. If you were coding in C you might sketch out something a little like:

For brevity I’ve ignored the actual reading of HTTP data, and any form of error handling.

// Starts an asynchronous HTTP fetch of the given url.
// Returns a positive integer request handle to be used
// to identify this request.
int StartRequest(const char* url);

// Blocks waiting for a request to complete. Returns the
// number of bytes received.
int WaitForRequest(int handle_id);

// ... APIs to read data from the request here ...

// Note that we're done with a handle, freeing up resources
// associated with it, and returning the handle to the pool
// of available handles.
void CloseRequest(int handle_id);

All is good until you realise that sometimes you need to be able to cancel an in-progress request. Say for example, a user hits the cancel button in a web browser. You tinker around with your implementation, and then realise you can reuse CloseRequest — you clarify this in the comment:

// Note that we're done with a handle, freeing up resources
// associated with it, and returning the handle to the pool
// of available handles. If the request is still
// in-progress, it is cancelled. Any threads blocked on
// this request will be released: WaitForRequest will
// return -1 to indicate the cancellation.
void CloseRequest(int handle_id);

Cool! We now have a simple API. But wait - there’s a threading problem waiting to bite us later on. Have a quick look and see if you can spot it.

Got it? If so — congratulations, go to the top of the class.

If not, don’t fret as you’re in good company: Microsoft missed this in their Windows Internet (WinInet) API design too.

To see where the problem lies, consider this situation:

// Cancelling example.
int handle = -1;  // an invalid handle
// Fetches a URL, waits for it to download, then does some
// form of (unspecified) processing on it.
void ProcessUrl(const char* url) {
  handle = StartRequest(url);
  int error = WaitForRequest(handle);
  if (error >= 0) {
    // ...process data here...
    CloseHandle(handle);
    handle = -1;
  } else {
    // cancelled!
  }
}

// Assume this is called on receipt of a UI event,
// asynchronous to the fetching of HTTP requests.
void BrowseToUrl(const char* url) {
  if (handle >= 0) {
    // Cancel any existing connection.
    CloseHandle(handle);
    handle = -1;
  }
  // Create a new thread to process this URL.
  StartNewThread(ProcessURL, url);
}

“Aha,” you might say, “there’s no lock on the handle variable so there’s a race there. Where’s my prize?” And indeed you’d be right. There’s no locking there.

But how would you add a lock?

// Thread-safe version?
void ProcessUrl(const char* url) {
  LockMutex();
  handle = StartRequest();
  int error = WaitForRequest(handle);
  UnlockMutex();
  ...
}

void BrowseToUrl(const char* url) {
  LockMutex();
  if (handle >= 0) {
    CloseHandle(handle);
    handle = -1;
  }
  UnlockMutex();
  ...
}

Job done. Except…you’re now unable to cancel an in-progress request!

The mutex is locked for the duration of the whole StartRequest and WaitForRequest calls. If BrowseToUrl is called on another thread it will be unable to cancel the existing request: It requires the mutex that the requesting thread holds — a mutex that will be held for the duration of the request!

There is no place you can place the lock and not end up with a race during cancellation. The only way you can do this is to have an atomic UnlockMutexAndWaitForRequest function1. In the absence of such a function, the best you can do is something like:

// Supports cancellation. Very nearly thread safe.
void ProcessUrl(const char* url) {
  LockMutex();
  handle = StartRequest();
  int temp_handle = handle;
  UnlockMutex();  // fingers crossed we don't yield here.
  int error = WaitForRequest(temp_handle);
  UnlockMutex();
  ...
}

The race is still there, but it’s now just at the point between unlocking the mutex and starting the request. Another thread could cancel the request between us taking a copy of the handle in temp_handle and starting to wait on it.

I mentioned before this is a problem in the Windows Inet library. So now to the really interesting bit: why is this not picked up by more people?

The key is that the handles provided by WinInet are not recycled - a unique handle (modulo the number of possible values of handles there are) is given out every time. In the race condition described above, that means in the worst case we try to WaitForRequest on an invalid handle, and provided the implementation is rigourous in checking the validity of handles, we’ll just get an “invalid handle” type of error.

This hides the problem — it’s still there, but the non-recycled handles prevent it from ever biting.

Unforuntately, on Windows Mobile devices, the handles are aggressively reused2. In the case described above, that could mean that between us taking a copy of the handle in temp_handle and us waiting on it; another thread could have cancelled our request, started a new one — receiving the same handle that the original thread thinks it owns. When the scheduler allows the original thread to run, we will call WaitForRequest on the other thread’s handle — with disastrous results.

So is there a way around this? Thankfully, yes — though it’s not perfect. More on this in another post, though!


  1. This type of operation is similar to the locking approached used in Java when calling wait

  2. They seem to be actually pointers to an underlying set of limited global resources. 

Filed under: Coding

Posted at 23:12:00 BST on 3rd July 2009.


Honey and Lime - a mobile bar

As a Google employee, I’m always being asked how to get websites higher up on the search results page. I really don’t know any more than the average person, but as far as I can tell, there’s really no secret to it — have an interesting website that contains useful, easy to read information, and you’re well on the way.

However, you need incoming links. Of course, a good website will pick up links as people discover it, but there’s a kind of boot-strapping problem to that. A friend has set up a new business, and has exactly this problem, so this is a bit of an excuse of a post to help him out.

Honey and Lime is a mobile bar that specialises in providing an expert cocktail-making service for parties and corporate events. They deal with getting temporary licensing, supply the ice and drinks, and then mix fabulous drinks on the night of your event.

Filed under: Blog

Posted at 22:06:00 BST on 14th May 2009.


Sunday Lunch at the Fat Duck

Fat duck logo

I haven’t blogged for ages, mainly as I don’t have much to talk about, and also as I’m now using Twitter for my day-to-day postings. That’s changed somewhat, as today I was lucky enough to enjoy Sunday lunch at the Fat Duck, Heston Blumenthal’s restaurant.

We had the taster menu, which is a 20-course spectacular including the famous snail porridge and bacon and egg ice cream. From start to finish it was a wonderfully presented sensory overload. One course turns up on a bed of steaming dry ice, another comes with an iPod playing sea sounds. Some are prepared at the table by the serving staff by cooking mainly those involving liquid nitrogen.

To my surprise, I enjoyed every single dish, including the more unusual ones and the sea food dishes. It’s amazing how much flavour is packed into the sauces and foams.

The only bit that wasn’t much fun was receiving the bill at the end — it’s definitely a “once in a lifetime” lunch.

A big thank you to my sister for booking the table, and also to my Dad for looking after William while we were out.

Filed under: Blog

Posted at 22:35:00 BST on 10th May 2009.


DIY Plumbing Fail

Silly plumbing picture

Just before New Year I noticed our combi boiler’s pressure had dropped below the recommended amount. As I rather fancy myself as a plumber I attempted to repressurise the system myself.

Inevitably things didn’t go to plan and turning the two taps that I expected did nothing. In my search for what I was doing wrong I inadvertantly turned the pressure release tap — which vented the entire contents of the system into the garden. Oops. I had gone from a working (if slightly under-pressured) heating system to one which didn’t work at all.

At this point I admitted defeat and called a local plumber. Staggeringly, they were able to pop over that afternoon in a break between jobs. The plumber was very helpful and determined quickly that there was a blockage in the refilling hose. I had been doing the right thing (until I emptied the system) but the filling loop was blocked.

Then the bad news: the little pipe was boiler-specific and would take a few days to arrive. The idea of not having any heating while it was sub-zero outside didn’t appeal at all.

Then we had the idea of trying to clear the blockage ourselves. A few minutes later a metal coat-hanger had been sacrificed and poked down the tube…and out came our gunky blockage. Phew!

Shortly after that we had the pressure back and heating returned.

And the cost of this? “Oh, just call it twenty quid,” said the plumber. Fantastic — we were expecting a lot more just for the call out!

So, if you’re in need of a plumber in the HA7 area, I can heartily recommend Stanmore Plumbing Services.

Filed under: Blog

Posted at 22:45:00 GMT on 17th January 2009.