• The Old New Thing

    Proto-Microspeak: Center of value

    • 23 Comments

    I have only one citation, so it may not be proper Microspeak.

    With all of these features covering the scenario end to end, we wanted to create a new center of value.

    I still don't know what it means.

  • The Old New Thing

    Email tips from Adam Phillabaum

    • 3 Comments

    Adam Phillabaum of Doing Boeing (who kept the name even though he left Boeing and now works for PayScale) has his own tips for writing email. Recommended reading.

  • The Old New Thing

    The management of memory for resources in 16-bit Windows, redux

    • 10 Comments

    Some time ago, I briefly ran down how 16-bit Windows managed memory for resources. But there's a detail that I neglected to mention: Ownership.

    As we saw, a resource handle HRSRC was really a pointer to the resource directory entry of the resource from the corresponding module. This could be done with a 16-bit pointer because the segment portion of the pointer could be inferred from the module the resource belonged to. In fact, since modules could be relocated in memory at run time due to compaction, you had better not try to remember the segment portion of the pointer since it could change!

    The Find­Resource function located the resource directory entry. The Load­Resource function allocated memory for the resource and loaded it from disk. The Lock­Resource function locked the memory so you could access it. If two people tried to load the same resource, the memory for the resource was re-used so there was only one copy in memory, and if both people free the resource, the resource is cached in case somebody asks for it again soon.

    Now things get interesting: When does the resource get removed from the cache? What actually controls the lifetime of the resource?

    Answer: The resource lifetime is tied to the module it came from. When the module is unloaded, all its resources are unloaded along with it. (Note that even if a resource is cached, its contents can get discarded if it is tagged as DISCARDABLE.)

    In Win32, modules are directly mapped into memory, and along with it, the resources. Therefore, accessing the resources of a module is a simple matter of figuring out where they got mapped (Find­Resource and friends will tell you), and then reading the memory directly. So despite the radical change to resources work, the basic rules haven't changed: The resources are good as long as the module is still in memory.

    But there are resources and then there are resources. So far, we've been talking about resources in the sense of Find­Resource, which I will call module resources for lack of a better term. But people often work with objects like icons and bitmaps which are not literally resources but which are derived from resources. Next time, we'll look at the relationship between module resources and resource-derived objects in 16-bit Windows.

  • The Old New Thing

    The introduction of whimsical teasing in Comic Chat

    • 11 Comments

    A few months after my post on the sad demise of whimsical teasing in Comic Chat, I received a piece of email from none other than the author of Comic Chat, DJ Kurlander:

    I was the person that started the Comic Chat project in Microsoft Research and was responsible for that line, "This person is too lazy to create a profile entry."

    Not a whole lot of thought went into the default profile. In maybe the 30 seconds that I put into it, I thought that the line was moderately humorous, fit with the quirky nature of Comic Chat, and might motivate more people to create profiles. When we released version 2, MSN got the following complaint. Yes, this is verbatim (and specifically in reference to the default profile):

    I am very offended that this is type of code is allowed to leave microsoft. I am seriously considering dropping my subscription to MSN. I don't get this kind of crap from CompuServe, and I can get comparable Internet access from a local ISP. I can see that there is a serious lack of customer respect at microsoft and this is probably just the tip of the iceberg.

    MSN was pretty conservative, at least at the time, and this caused a big headache for the team. How dare we insult our customers! Did the project not have enough management overhead? Can we make things any more difficult for the small team? Yes we can! As a result, we were required to remove the message from the 2.1 release. It became "This user has no profile." at least in the version that was released on the MSN CD-ROM.

    Meanwhile, we got some advanced notice about an upcoming PC World review of the 2.0 version that had included the original message. The summary (which was emailed to us), said: "She [the reviewer] praises Microsoft for finally having a sense of humor (loves the note about being 'too lazy to have a bio' message). She claims Comic Chat is an absolute delight."

    I love the part about MS finally having a sense of humor. Well at least we were allowed to add back the message for the 2.5 release!

    Check out DJ's history of Comic Chat, which includes links to videos and other time-wasty goodness.

    Bonus chatter: DJ also has a page on Peedy the Parrot, a research project to develop a more natural user interface. Out in the product groups, we just called it that stupid parrot demo because it became tiresome from overexposure, having been used in a CES keynote and multiple company meetings.

  • The Old New Thing

    The history of Win32 critical sections so far

    • 19 Comments

    The CRITICAL_SECTION structure has gone through a lot of changes since its introduction back oh so many decades ago. The amazing thing is that as long as you stick to the documented API, your code is completely unaffected.

    Initially, the critical section object had an owner field to keep track of which thread entered the critical section, if any. It also had a lock count to keep track of how many times the owner thread entered the critical section, so that the critical section would be released when the matching number of Leave­Critical­Section calls was made. And there was an auto-reset event used to manage contention. We'll look more at that event later. (It's actually more complicated than this, but the details aren't important.)

    If you've ever looked at the innards of a critical section (for entertainment purposes only), you may have noticed that the lock count was off by one: The lock count was the number of active calls to Enter­Critical­Section minus one. The bias was needed because the original version of the interlocked increment and decrement operations returned only the sign of the result, not the revised value. Biasing the result by 1 means that all three states could be detected: Unlocked (negative), locked exactly once (zero), reentrant lock (positive). (It's actually more complicated than this, but the details aren't important.)

    If a thread tries to enter a critical section but can't because the critical section is owned by another thread, then it sits and waits on the contention event. When the owning thread releases all its claims on the critical section, it signals the event to say, "Okay, the door is unlocked. The next guy can come in."

    The contention event is allocated only when contention occurs. (This is what older versions of MSDN meant when they said that the event is "allocated on demand.") Which leads to a nasty problem: What if contention occurs, but the attempt to create the contention event fails? Originally, the answer was "The kernel raises an out-of-memory exception."

    Now you'd think that a clever program could catch this exception and try to recover from it, say, by unwinding everything that led up to the exception. Unfortunately, the weakest link in the chain is the critical section object itself: In the original version of the code, the out-of-memory exception was raised while the critical section was in an unstable state. Even if you managed to catch the exception and unwind everything you could, the critical section was itself irretrievably corrupted.

    Another problem with the original design became apparent on multiprocessor systems: If a critical section was typically held for a very brief time, then by the time you called into kernel to wait on the contention event, the critical section was already freed!

    void SetGuid(REFGUID guid)
    {
     EnterCriticalSection(&g_csGuidUpdate);
     g_theGuid = guid;
     LeaveCriticalSection(&g_csGuidUpdate);
    }
    
    void GetGuid(GUID *pguid)
    {
     EnterCriticalSection(&g_csGuidUpdate);
     *pguid = g_theGuid;
     LeaveCriticalSection(&g_csGuidUpdate);
    }
    

    This imaginary code uses a critical section to protect accesses to a GUID. The actual protected region is just nine instructions long. Setting up to wait on a kernel object is way, way more than nine instructions. If the second thread immediately waited on the critical section contention event, it would find that by the time the kernel got around to entering the wait state, the event would say, "Dude, what took you so long? I was signaleded, like, a bazillion cycles ago!"

    Windows 2000 added the Initialize­Critical­Section­And­Spin­Count function, which lets you avoid the problem where waiting for a critical section costs more than the code the critical section was protecting. If you initialize with a spin count, then when a thread tries to enter the critical section and can't, it goes into a loop trying to enter it over and over again, in the hopes that it will be released.

    "Are we there yet? How about now? How about now? How about now? How about now? How about now? How about now? How about now? How about now? How about now? How about now? How about now?"

    If the critical section is not released after the requested number of iterations, then the old slow wait code is executed.

    Note that spinning on a critical section is helpful only on multiprocessor systems, and only in the case where you know that all the protected code segments are very short in duration. If the critical section is held for a long time, then spinning is wasteful since the odds that the critical section will become free during the spin cycle are very low, and you wasted a bunch of CPU.

    Another feature added in Windows 2000 is the ability to preallocate the contention event. This avoids the dreaded "out of memory" exception in Enter­Critical­Section, but at a cost of a kernel event for every critical section, whether actual contention occurs or not.

    Windows XP solved the problem of the dreaded "out of memory" exception by using a fallback algorithm that could be used if the contention event could not be allocated. The fallback algorithm is not as efficient, but at least it avoids the "out of memory" situation. (Which is a good thing, because nobody really expects Enter­Critical­Section to fail.) This also means that requests for the contention event to be preallocated are now ignored, since the reason for preallocating (avoiding the "out of memory" exception) no longer exists.

    (And while they were there, the kernel folks also fixed Initialize­Critical­Section so that a failed initialization left the critical section object in a stable state so you could safely try again later.)

    In Windows Vista, the internals of the critical section object were rejiggered once again, this time to add convoy resistance. The internal bookkeeping completely changed; the lock count is no longer a 1-biased count of the number of Enter­Critical­Section calls which are pending. As a special concession to backward compatibility with people who violated the API contract and looked directly at the internal data structures, the new algorithm goes to some extra effort to ensure that if a program breaks the rules and looks at a specific offset inside the critical section object, the value stored there is −1 if and only if the critical section is unlocked.

    Often, people will remark that "your compatibility problems would go away if you just open-sourced the operating system." I think there is some confusion over what "go away" means. If you release the source code to the operating system, it makes it even easier for people to take undocumented dependencies on it, because they no longer have the barrier of "Well, I can't find any documentation, so maybe it's not documented." They can just read the source code and say, "Oh, I see that if the critical section is unlocked, the Lock­Count variable has the value −1." Boom, instant undocumented dependency. Compatibility is screwed. (Unless what people are saying "your compatibility problems would go away if you just open-sourced all applications, so that these problems can be identified and fixed as soon as they are discovered.")

    Exercise: Why isn't it important that the fallback algorithm be highly efficient?

  • The Old New Thing

    Welcome to Leavenworth, Washington's faux-Bavarian village

    • 19 Comments

    The dying logging town of Leavenworth, Washington reinvented itself in the 1960's as a faux-Bavarian village. Today, over a million tourists visit annually to enjoy the scenic mountain views, soak in the fake Bavarian atmosphere, and revel in events like the Leavenworth International Accordion Celebration which starts tomorrow, or the three-weekend-long Leavenworth Oktoberfest every October. (Mind you, the Leavenworth Oktoberfest doesn't actually start until the Munich Oktoberfest is nearly over, because Oktoberfest starts in September.)

    I found during a brief visit to Leavenworth that the people there may dress like they're from Bavaria, but they don't actually speak German.

    But at least I was there undercover.

    Some years ago, a colleague of mine was on assignment in Redmond from his home country of Austria. One weekend, he decided to pay a visit to our fake Bavarian village, and when he returned, we asked him what he thought of the town.

    "Well, for a fake Bavarian village, it's not too bad. I mean, nobody would for a moment think it was the real thing, but I appreciate the effort they went to, and it was quite a pleasant little town. But the weird thing was what happened whenever I opened my mouth to speak: People recognized that I spoke with a German accent and a flash of panic crossed their faces, as if I was going to blow the cover off their little ruse and reveal it to be a fraud."

    [Update 8:00AM: Various typos fixed.]

  • The Old New Thing

    Counting down to the last day of school, as students do it

    • 23 Comments

    Today is the last day of school in Seattle public school. My friend the seventh-grade teacher told me that students count down to the last day of school in a rather unusual way.

    Some people might count the number of calendar days until the end of school. For example, if there are 35 days between today and the last day of school, we say that it's 35 days until the end of school.

    Others might count only the number of school days before school is out. If today is Monday, and the last day of school is Friday, then there are five days of school remaining.

    But students, or at least seventh-grade students, count the days differently.

    First of all, you don't count today. Because today has already started, so you may as well treat it as already over.

    Next, you don't count the last day of school itself, because nobody gets anything done on the last day anyway, it's basically just one big party.

    Also, if there are any half-days or days with early dismissal, don't count those either, because days where you aren't there the whole day don't count, because the class periods are so short you don't get anything done.

    Similarly, days with special events like a field trip don't count.

    Furthermore, you don't count Mondays, because on Monday, you're still fresh off the weekend and you won't be concentrating on school anyway.

    Conversely, you don't count Fridays, because you've already mentally checked out.

    The result of all these calculations is that the students will cheerfully calculate that there are only 25 days of school left, when it's still only late April.

  • The Old New Thing

    Space Mountain as if the lights were on, and other Disneyland/World secrets

    • 5 Comments

    Many years ago, some friends of mine went to Disneyland and got to experience Space Mountain in an unusual way.

    They went through the ride the normal way, but when the car returned to the load/unload area, the cast member (because that's what Disney calls them) asked, "Do you want to go again?"

    Everybody in the car enthusiastically shouted, "Yes!"

    (Presumably they were falling behind on the loading and unloading, and waving a car through saved them a bit of time they could use to catch up.)

    The second time through the ride was qualitatively different: Their eyes had already acclimated to the dark, so even though they were going through the ride like everybody else, they could see the room as if the lights were on.

    There are a number of videos of Disneyworld Space Mountain with the lights on, captured from the PeopleMover, but that's not the same as riding it with the lights on.

    Other Disneyland secrets:

    I'm leaving for vacation today, so the blog will be on autopilot for a while. I might visit a certain theme park. You never know.

  • The Old New Thing

    How to pretend that you attended my talk at UIUC Reflections|Projections 2009

    • 12 Comments

    Step 1: Buy a 1.55-ounce Hershey's Milk Chocolate Bar from a convenience store, supermarket, or (if truly desperate) online.

    Step 2: Print out this candy bar wrapper.

    Step 3: Trim wrapper on registration marks and wrap around candy bar.

    Step 4: Stay up late the night before you plan on watching the video by partying with Ryan North and teaching him how to play beer pong.

    Step 5: Force yourself to wake up the next morning and watch the recorded video of my talk while trying desperately to stay awake. The candy bar might help.

    Note: Although most steps are optional, they are essential if you want an accurate simulation.

  • The Old New Thing

    Even if you have code to handle a message, you're allowed to call DefWindowProc, because you were doing that anyway after all

    • 16 Comments

    Just because you write case WM_SOMETHING: doesn't mean that you have to handle all possible parameters for the WM_SOMETHING message. You're still allowed to call the DefWindowProc function. After all, that's what you did when you didn't have a case WM_SOMETHING: statement in the first place.

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    default:
        return DefWindowProc(...);
    }
    

    The above code fragment doesn't handle the WM_SOMETHING message at all. Suppose the WM_SOMETHING message uses the wParam parameter to specify what type of something occurred, and you only want to override the default processing in the case where wParam has the value of 4. What do you do with the other values?

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        if (wParam == 4) { DoSomething4(...); }
        else ... ????? ...
        return 0;
    
    default:
        return DefWindowProc(...);
    }
    

    If the value is 4, then you do your special "something 4" processing, but what about all the other values? How do you handle them?

    Well, think about it: How did you handle them before? The original code, before you added a WM_SOMETHING handler, was equivalent to this:

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        return DefWindowProc(...);
    
    default:
        return DefWindowProc(...);
    }
    

    In the original code, since there was no explicit handler for the WM_SOMETHING message, control is transferred to the default case handler, which just calls the DefWindowProc function. If you really want to, you can expand the case out a bit more:

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        if (wParam == 4) return DefWindowProc(...);
        else return DefWindowProc(...);
    
    default:
        return DefWindowProc(...);
    }
    

    Because if the wParam is 4, the original code just called DefWindowProc. And if the wParam was something other than 4, the original code still just called DefWindowProc.

    Of course, I expanded the block in precisely this way so it matches up with the case we started writing when we decided to handle the WM_SOMETHING method. Written out this way, it becomes obvious what to write for the question marks.

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        if (wParam == 4) { DoSomething4(...); }
        else return DefWindowProc(...);
        return 0;
    
    default:
        return DefWindowProc(...);
    }
    

    Just because you have a case WM_SOMETHING statement doesn't mean you have to handle all the cases; you can still call DefWindowProc for the cases you don't want to handle.

    Armed with this information, you can help commenter Norman Diamond handle the VK_F10 key in his WM_SYSKEYDOWN message handler without having to "start handling a bunch of keys that really are system keys, that I didn't want to bother with."

Page 370 of 438 (4,378 items) «368369370371372»