Notes on alternative designs:
1. The refcount mechanism for the session object looks a little superflous at the first glance. But the alternative would be to lock the object for the entirety of the operation, which seems about as complex (we need to make sure not to forget to lock/unlock, just like we do acquire/release now). Additionally, a prolonged critical section tend to introduce unnecessary contention and potential for deadlock.
2. Note that we store the index, instead of a pointer to the shared memory object in the desktop. I think this design makes it clear that a desktop merely references but doesn't own the portion of the shared memory. We can of course store the `desktop_shm_t` pointer and eliminate `get_shared_desktop()`, but then we'd need to do pointer arithmetic to get the index back. My experience tells me that it's quite easy to mess up the arithmetic and choose the wrong base address, especially during refactoring. (By the way, `SHARED_WRITE_BEGIN` is necessary even if we held a direct pointer. Also `unsigned int index` is 4 bytes less than `desktop_shm_t *` on 64-bit, if it's of any significance.)
3. The object lock instead of `SHARED_READ_BEGIN`. We decided that it's more trouble than any help; this MR has a whole thread that argues against it.