• The Old New Thing

    Which windows appear in the Alt+Tab list?

    • 16 Comments

    Commenter Phil Quirk wants to know what the rules are for determining which windows appear in the Alt+Tab list. It's actually pretty simple although hardly anything you'd be able to guess on your own. Note: The details of this algorithm are an implementation detail. It can change at any time, so don't rely on it. In fact, it already changed with Flip and Flip3D; I'm just talking about the Classic Alt+Tab window here.

    For each visible window, walk up its owner chain until you find the root owner. Then walk back down the visible last active popup chain until you find a visible window. If you're back to where you're started, then put the window in the Alt+Tab list. In pseudo-code:

    BOOL IsAltTabWindow(HWND hwnd)
    {
     // Start at the root owner
     HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);
    
     // See if we are the last active visible popup
     HWND hwndTry;
     while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry) {
      if (IsWindowVisible(hwndTry)) break;
      hwndWalk = hwndTry;
     }
     return hwndWalk == hwnd;
    }
    

    The purpose of this algorithm is to assign the most meaningful representative winow from each cluster of windows related by ownership. (Notice that the algorithm doesn't care whether the owned window is modal or non-modal.)

    At least that's the simple rule if you're not playing crazy window style games. The WS_EX_TOOLWINDOW and WS_EX_APPWINDOW extended styles were created so people can play games and put their window in the Alt+Tab list or take it out even if the simple rule would normally have decided otherwise. This is one of those "Okay, if you think you're smarter than Windows, here's your chance to prove it" options. Personally, I would avoid them since it makes your window behave differently from the rest of the windows in the system.

    A window with the WS_EX_TOOLWINDOW extended style is treated as if it weren't visible, even if it is. A window with the WS_EX_APPWINDOW extended style is treated as if it has no owner, even if it does.

    Once you start adding these extended styles, you enter the world of "I'm trying to work around the rules" and the result is typically even worse confusion than what you had without them.

    I'm not sure what the original commenter is getting at. The window hierarchy described in the suggestion (which doesn't make it so much a suggestion as it is a request for me to debug their problem) says that window C is modal on both windows A and B, which doesn't make sense to me, since a window has only one owner.

    The algorithm for choosing the Alt+Tab representative from each cluster of windows may not be the best, but it's what we have. I wouldn't be surprised if the details are tweaked from time to time. No, wait, let me rephrase that. I know that the details are tweaked from time to time. The spirit of the operation is preserved (to show the windows the user can switch to, using the most "natural" candidate for each cluster of windows), but the specific details may be fined-tuned as the concept of "naturalness" is refined.

  • The Old New Thing

    The history of the Windows XP common controls

    • 63 Comments

    In the beginning, there was one control library, namely USER, the window manager itself, which provided buttons, static controls, edit controls, scroll bars, list boxes, and combo boxes. These controls were under the purview of the window manager team.

    In Windows 3.1 a second control library known as the shell common controls was added, but the library really didn't come into it own until Windows 95, where it consisted of the list view, header, tree view, tooltip, toolbar, status bar, track bar, tab, updown, progress, hotkey, and animation controls. These controls were originally custom controls written by the shell team for use in Explorer, but since they seemed to be generally useful, time was budged to do the extra work to make the controls more suitable for general use, testing the controls in combinations and scenarios that Explorer itself didn't use, and putting together formal documentation.

    The shell common controls library underwent many changes over the years, whereas the core intrinsic controls in the window manager changed much more conservatively.

    With Windows XP, the visual design team wanted to give the look of Windows a new life. Changing the non-client area (such as the window frame) was comparatively straightforward, since programs didn't have much control over that part of the window anyway. As a result, they get the Windows XP look "for free".

    The client area is another story. Programs are in control of their client area, where they can place controls that come with Windows, their own custom controls, or controls obtained from a third party library. Making major changes to the core controls or the common controls would be a high-risk endeavor since there are thousands upon thousands of Windows program that not only use them, but use them in all sorts of crazy ways.

    The initial stab at resolving these two conflicting goals (making major changes to these controls to increase visual appeal and functionality while simultaneously not changing them to maintain compatibility) was to create a new DLL that would contain the "fancy new version" of the core controls as well as the shell common controls. The old DLLs USER32 and COMCTL32 stayed where they were, so that old programs continued to get the behavior they were expecting, and the new XP-style controls were placed in a DLL named UXCTRL.DLL. UX stands for user experience, which was the hot new buzzword at the time. To avoid name collision with the old style controls, the new controls got new names beginning with Ux. For example, the UXCTRL version of the button control was called UxButton.

    New features could be added to these new Ux controls with wild abandon without heed for backward compatibility since they were brand new controls. There was nothing they had to be compatible with. Explorer was changed to use these new controls instead of the old stodgy controls, and everything worked great.

    Or so it seemed.

    We thought we had cleverly sidestepped the backward compatibility problem by creating entirely new controls, but doing that created a whole new category of compatibility bugs. Even though it's completely undocumented and unsupported, programs like to grovel into the internal data structures of other programs or otherwise manipulate those programs' windows. In Explorer's case, it turns out that a lot of programs like to go spelunking around Explorer's window hierarchy and use functions like FindWindow and EnumChildWindows to find the object of their affections. For example, a program might use EnumChildWindows to enumerate all the child windows of an Explorer browser, and then use GetClassName and lstrcmpi(szClassName, TEXT("button")) to look for a specific control. In this example, the target was a button, but it could have been a list view or a tool bar. Since all the new XP-style controls were named things like UxButton and UxListView, these programs which looked for a button by comparing against the string "button" stopped working.

    Of course, there was no guarantee that Explorer would even use buttons at all; Explorer was completely within its rights to revamp its user interface. But that's not much consolation to the customers who paid good money for these programs, especially since magazine columnists are the types of people most likely to be running (or indeed even writing!) strange off-the-wall programs that pull these sorts of nasty stunts in the first place.

    Okay, so it is now a compatibility requirement that all the new window classes have the same names as their old counterparts. This created an impasse, since these controls needed to be created by dialog boxes, and therefore they had to be globally-registered window classes. But you can't have two global window classes with the same name, because that would create ambiguity over which one the caller was asking for.

    More brainstorming ensued, and a Plan C emerged. The common controls library would take advantage of side-by-side assemblies and use the application manifest to control which DLL a given window class name would resolve to. Thus was born a new DLL also called COMCTL32, but with a new version number—version 6. Old programs would get version 5.82 just like they did in Windows 2000. New programs would have to use a manifest to specify that they wanted version 6.

    Once again, the solution came with a new problem. Since the entire COMCTL32 library got split into two versions, this meant that there were two versions of the image list code. Whole new scenarios emerged, such as putting a version 5 image list in a version 6 tree view, or vice versa. (As the linked thread notes illustrates, not all of the problems with cross-version scenarios were caught in the initial release and had to wait for a service pack for the fix to become available.)

  • The Old New Thing

    If you need anything other than natural alignment, you have to ask for it

    • 27 Comments

    If you need variables to be aligned a particular way, you need to ask for it.

    Let's say I have the following code:

    void fn() 
    { 
     int a; 
     char b; 
     long c; 
     char d[10];
    } 
    

    What would the alignment of the starting adresses of a,b,c and d be?

    What would the alignment be if the memory were allocated on heap?

    If this alignment varies for different data types within the same translation unit, is there a way to force uniform alignment for all types?

    If you need a particular alignment, you have to ask for it. By default, all you can count on is that variables are aligned according to their natural requirements.

    First, of course, there is no guarantee that local variables even reside on the stack. The optimizer may very well decide that particular local variables can reside in registers, in which case it has no alignment at all!

    There are a few ways to force a particular alignment. The one that fits the C language standard is to use a union:

    union char_with_int_alignment {
     char ch;
     int Alignment;
    } u;
    

    Given this union, you can say u.ch to obtain a character whose alignment is suitable for an integer.

    The Visual C++ compiler supports a declaration specifier to override the default alignment of a variable.

    typedef struct __declspec(align(16)) _M128 {
        unsigned __int64 Low;
        __int64 High;
    } M128, *PM128;
    

    This structure consists of two eight-byte members. Without the __declspec(align(#)) directive, the alignment of this structure would be 8-byte, since that is the alignment of the members with the most restrictive alignment. (Both unsigned __int64 and __int64 are naturally 8-byte-aligned.) But with the directive, the aligment is expanded to 16 bytes, which is more restrictive than what the structure normally would be. This particular structure is declared with more restrictive alignment because it is intended to be use to hold 128-bit values that will be used by the 128-bit XMM registers.

    A third way to force alignment with the Visual C++ compiler is to use the #pragma pack(#) directive. (There is also a "push" variation of this pragma which remembers the previous ambient alignment, which can be restored by a "pop" directive. And the /Zp# directive allows you to specify this pragma from the compiler command line.) This directive specifies that members can be placed at alignments suitable for #-byte objects rather than their natural alignment requirements, if the natural alignment is more restrictive. For example, if you set the pack alignment to 2, then all objects that are bigger than two bytes will be aligned as if they were two-byte objects. This can cause 32-bit values and 64-bit values to become mis-aligned; it is assumed that you know what you're doing any can compensate accordingly.

    For example, consider this structure whose natural alignment has been altered:

    #pragma pack(1)
    struct misaligned_members {
     WORD w;
     DWORD dw;
     BYTE b;
    };
    

    Given this structure, you cannot pass the address of the dw member to a function that expects a pointer to a DWORD, since the ground rules for programming specify that all pointers must be aligned unless unaligned pointers are explicitly permitted.

    void ExpectsAlignedPointer(DWORD *pdw);
    void UnalignedPointerOkay(UNALIGNED DWORD *pdw);
    
    misaligned_members s;
    ExpectsAlignedPointer(&s.dw); // wrong
    UnalignedPointerOkay(&s.dw);  // okay
    

    What about the member w? Is it aligned or not? Well, it depends.

    If you allocate a single structure on the heap, then the w member is aligned, since heap allocations are always aligned in a manner suitable for any fundamental data type. (I vaguely recall some possible weirdness with 10-byte floating point values, but that's not relevant to the topic at hand.)

    misaligned_members *p = (misaligned_members)
        HeapAllocate(hheap, 0, sizeof(misaligned_members));
    

    Given this code fragment, the member p->w is aligned since the entire structure is suitably aligned, and therefore so too is w. If you allocated an array, however, things are different.

    misaligned_members *p = (misaligned_members)
        HeapAllocate(hheap, 0, 2*sizeof(misaligned_members));
    

    In this code fragment, p[1].w is not aligned because the entire misaligned_members structure is 2+4+1=7 bytes in size since the packing is set to 1. Therefore, the second structure begins at an unaligned offset relative to the start of the array.

    One final issue is the expectations for alignment when using header files provided by an outside component. If you are writing a header file that will be consumed by others, and you require special alignment, you need to say so explicitly in your header file, because you don't control the code that will be including your header file. Furthermore, if your header file changes any compiler settings, you need to restore them before your header file is complete. If you don't follow this rule, then you create the situation where a program stops working if a program changes the order in which it includes seemingly-unrelated header files.

    // this code works
    #include <foo.h>
    #include <bar.h>
    
    // this code doesn't
    #include <bar.h>
    #include <foo.h>
    

    The problem was that bar.h changed the default structure alignment and failed to return it to the original value before it was over. As a result, in the second case, the structure alignment for the foo.h header file got "infected" and no longer matched the structure alignment used by the foo library.

    You can imagine an analogous scenario where deleting a header file can cause a program to stop working.

    Therefore, if you're writing a header file that will be used by others, and you require nonstandard alignment for your structures, you should use this pattern to change the default alignment:

    #include <pshpack1.h> // change alignment to 1
    ... stuff that assumes byte packing ...
    #include <poppack.h>  // return to original alignment
    

    In this way, you "leave things the way you found them" and avoid the mysterious infection scenarios described above.

  • The Old New Thing

    Book review: Advanced Windows Debugging (Mario Hewardt and Daniel Pravat)

    • 19 Comments

    Ever so often, somebody sends me a book, and most of the time I glance through it and say, "Eh."

    But not this time.

    Advanced Windows Debugging will make you the envy of your friends (if your friends are computer nerds). Even the section with the "Oh come on every moron knows this already" title Basic Debugger Tasks has stuff that I didn't know. Fortunately, you don't have to slog through the stuff you already do know in order to find it, because the nifty new debugger commands are set off in the snippets of debugger conversation. (And by debugger conversation, I mean output of a debugger based on the Windows debug engine, debuggers like ntsd, kd and windbg.)

    Once you get past the "basics", you still have loads more ahead of you. The book covers debugging scenarios like a corrupted heap, a deadlock, or 100% CPU usage, as well as debugging tasks, like following the trail of an LPC request from the client to the server, peeking at the token count of a semaphore, and reconstructing a partially-corrupted stack—and illustrates each investigation with both discussion and annotated debugger output. All the things that seasoned developers take for granted (because they have become instinctual after years of experience) are spelled out for you. Learn more from the book's web site, not unsurprisingly named advancedwindowsdebugging.com.

    I'm keeping this book on my shelf. You can borrow it, but I'm going to insist that you return it when you're done.

  • The Old New Thing

    The magical healing properties of safe mode - bonus content

    • 35 Comments

    Okay, so you already read The healing properties of safe mode in TechNet Magazine. Here's the bonus content that was cut for space.

    First, the original title was "The Magical Healing Powers of Safe Mode," but it got trimmed for space reasons. (Ich bin mit der deutschen Übersetzung des ersten Satzes ein bisschen enttäuscht. Die eingeklammerte Phrase bittet um einen von den berühmten nur auf Deutsch gesehenen unverständlich langen adjektivischen Ausdrücken. Anstatt dessen hat der Übersetzer aufgegeben und die Phrase einfach weggelassen. Anderseits benutzt die deutsche Version den ursprünglichen Titel, so vielleicht ist es ja nicht so schlecht.)

    Useless Windows history: The feature now known as safe mode went through many other names before the final name was settled upon.

    • Fail-safe boot
    • FailSafe boot
    • Fail-safe mode
    • Safe mode
  • The Old New Thing

    How do I get the reference count of a CLR object?

    • 41 Comments

    A customer asked the rather enigmatic question (with no context):

    Is there a way to get the reference count of an object in .Net?

    Thanks,
    Bob Smith
    Senior Developer
    Contoso

    The CLR does not maintain reference counts, so there is no reference count to "get". The garbage collector only cares about whether an object has zero references or at least one reference. It doesn't care if there is one, two, twelve, or five hundred—from the point of view of the garbage collector, one is as good as five hundred.

    The customer replied,

    I am aware of that, yet the mechanism is somehow implemented by the GC...

    What I want to know is whether at a certain point there is more then one variable pointing to the same object.

    As already noted, the GC does not implement the "count the number of references to this object" algorithm. It only implements the "Is it definitely safe to reclaim the memory for his object?" algorithm. A null garbage collector always answers "No." A tracing collector looks for references, but it only cares whether it found one, not how many it found.

    The discussion of "variables pointing to the same objects" is somewhat confused, because you can have references to an object from things other than variables. Parameters to a method contain references, the implicit this is also a reference, and partially-evaluated expressions also contain references. (During execution of the line string s = o.ToString();, at the point immediately after o.ToString() returns and before the result is assigned to s, the string has an active reference but it isn't stored in any variable.) And as we saw earlier, merely storing a reference in a variable doesn't prevent the object from being collected.

    It's clear that this person solved half of his problem, and just needs help with the other half, the half that doesn't make any sense. (I like how he immediately weakened his request from "I want the exact reference count" to "I want to know if it is greater than one." Because as we all know, the best way to solve a problem is to reduce it to an even harder problem.)

    Another person used some psychic powers to figure out what the real problem is:

    If I am reading properly into what you mean, you may want to check out the Weak­Reference class. This lets you determine whether an object has been collected. Note that you don't get access to a reference count; it's a zero/nonzero thing. If the Weak­Reference is empty, it means the object has been collected. You don't get a chance to act upon it (as you would if you were the last one holding a reference to it).

    The customer explained that he tried Weak­Reference, but it didn't work. (By withholding this information, the customer made the mistake of not saying what he already tried and why it didn't work.)

    Well this is exactly the problem: I instantiate an object and then create a Weak­Reference to it (global variable).

    Then at some point the object is released (set to null, disposed, erased from the face of the earth, you name it) yet if I check the Is­Alive property it still returns true.

    Only if I explicitly call to GC.Collect(0) or greater before the check it is disposed.

    The customer still hasn't let go of the concept of reference counting, since he says that the object is "released". In a garbage-collected system, object are not released; rather, you simply stop referencing them. And disposing of an object still maintains a reference; disposing just invokes the IDisposable.Dispose method.

    FileStream fs = new FileStream(fileName);
    using (fs) {
     ...
    }
    

    At the end of this code fragment, the File­Stream has been disposed, but there is still a reference to it in the fs variable. Mind you, that reference isn't very useful, since there isn't much you can do with a disposed object, Even if you rewrite the fragment as

    using (FileStream fs = new FileStream(fileName)) {
     ...
    }
    

    the variable fs still exists after the close-brace; it simply has gone out of scope (i.e., you can't access it any more). Scope is not the same as lifetime. Of course, the optimizer can step in and make the object eligible for collection once the value becomes inaccessible, but there is no requirement that this optimization be done.

    The fact that the Is­Alive property says true even after all known references have been destroyed is also no surprise. The environment does not check whether an object's last reference has been made inaccessible every time a reference changes. One of the major performance benefits of garbage collected systems comes from the de-amortization of object lifetime determination. Instead of maintaining lifetime information about an object continuously (spending a penny each time a reference is created or destroyed), it saves up those pennies and splurges on a few dollars every so often. The calculated risk (which usually pays off) is that the rate of penny-saving makes up for the occasional splurges.

    It does mean that between the splurges, the garbage collector does not know whether an object has outstanding references or not. It doesn't find out until it does a collection.

    The null garbage collector takes this approach to an extreme by simply hoarding pennies and never spending them. It saves a lot of money but consumes a lot of memory. The other extreme (common in unmanaged environments) is to spend the pennies as soon as possible. It spends a lot of money but reduces memory usage to the absolute minimum. The designers of a garbage collector work to find the right balance between these two extremes, saving money overall while still keeping memory usage at a reasonable level.

    The customer appears to have misinterpreted what the Is­Alive property means. The property doesn't say whether there are any references to the object. It says whether the object has been garbage collected. Since the garbage collector can run at any time, there is nothing meaningful you can conclude if Is­Alive returns true, since it can transition from alive to dead while you're talking about it. On the other hand, once it's dead, it stays dead; it is valid to take action when Is­Alive is false. (Note that there are two types of Weak­Reference; the difference is when they issue the death certificate.)

    The name Is­Alive for the property could be viewed as misleading if you just look at the property name without reading the accompanying documentation. Perhaps a more accurate (but much clumsier) name would have been Has­Not­Been­Collected. The theory is, presumably, that if you're using an advanced class like Weak­Reference, which works "at the GC level", you need to understand the GC.

    The behavior the customer is seeing is correct. The odds that the garbage collector has run between annihilating the last live reference and checking the Is­Alive property is pretty low, so when you ask whether the object has been collected, the answer will be No. Of course, forcing a collection will cause the garbage collector to run, and that's what does the collection and sets Is­Alive to false. Mind you, forcing the collection to take place messes up the careful penny-pinching the garbage collector has been performing. You forced it to pay for a collection before it had finished saving up for it, putting the garbage collector in debt. (Is there a garbage collector debt collector?) And the effect of a garbage collector going into debt is that your program runs slower than it would have if you had let the collector spend its money on its own terms.

    Note also that forcing a generation-zero collection does not guarantee that the object in question will be collected: It may have been promoted into a higher generation. (Generational garbage collection takes advantage of typical real-world object lifetime profiles by spending only fifty cents on a partial collection rather than a whole dollar on a full collection. As a rough guide, the cost of a collection is proportional to the number of live object scanned, so the most efficient collections are those which find mostly dead objects.) Forcing an early generation-zero collection messes up the careful balance between cheap-but-partial collections and expensive-and-thorough collections, causing objects to get promoted into higher generations before they really deserve it.

    Okay, that was a long discussion of a short email thread. Maybe tomorrow I'll do a better job of keeping things short.

    Bonus chatter: In addition to the Weak­Reference class, there is also the GC­Handle structure.

    Bonus reading: Maoni's WebLog goes into lots of detail on the internals of the CLR garbage collector. Doug Stewart created this handy index.

  • The Old New Thing

    Understanding the consequences of WAIT_ABANDONED

    • 27 Comments

    One of the important distinctions between mutexes and the other synchronization objects is that mutexes have owners. If the thread that owns a mutex exits without releasing the mutex, the mutex is automatically released on the thread's behalf.

    But if this happens, you're in big trouble.

    One thing many people gloss over is the WAIT_ABANDONED return value from the synchronization functions such as WaitForSingleObject. They typically treat this as a successful wait, because it does mean that the object was obtained, but it also tells you that the previous owner left the mutex abandoned and that the system had to release it on the owner's behalf.

    Why are you in big trouble when this happens?

    Presumably, you created that mutex to protect multiple threads from accessing a shared object while it is an unstable state. Code enters the mutex, then starts manipulating the object, temporarily making it unstable, but eventually restabilizing it and then releasing the mutex so that the next person can access the object.

    For example, you might have code that manages an anchored doubly-linked list in shared memory that goes like this:

    void MyClass::ReverseList()
    {
     WaitForSingleObject(hMutex, INFINITE);
     int i = 0; // anchor
     do {
      int next = m_items[i].m_next;
      m_items[i].m_next = m_items[i].m_prev;
      m_items[i].m_prev = next;
      i = next;
     } while (i != 0);
     ReleaseMutex(hMutex);
    }
    

    There is nothing particularly exciting going on. Basic stuff, right?

    But what if the program crashes while holding the mutex? (If you believe that your programs are bug-free, consider the possiblity that the program is running over the network and the network goes down, leading to an in-page exception. Or simply that the user went to Task Manager and terminated your program while this function is running.)

    In that case, the mutex is automatically released by the operating system, leaving the linked list in a corrupted state. The next program to claim the mutex will receive WAIT_ABANDONED as the status code. If you ignore that status code, you end up operating on a corrupted linked list. Depending on how that linked list is used, it may result in a resource leak or the system creating an unintended second copy of something, or perhaps even a crash. The unfortunate demise of one program causes other programs to start behaving strangely.

    Then again, the question remains, "What do you do, then, if you get WAIT_ABANDONED?" The answer is, "Good question."

    You might try to repair the corruption, if you keep enough auxiliary information around to recover a consistent state. You might even design your data structures to be transactional, so that the death of a thread manipulating the data structures does not leave them in a corrupted state. Or you might just decide that since things are corrupted, you should throw away everything and start over, losing the state of work in progress, but at least allowing new work to proceed unhindered.

    Or you might simply choose to ignore the error and continue onwards with a corrupt data structure, hoping that whatever went wrong won't result in cascade failures down the line. This is what most people do, though usually without even being aware that they're doing it. And it's really hard to debug the crashes that result from this approach.

    Exercise: Why did we use indices instead of pointers in our linked list data structure?

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    If you say that you don't care about something, you shouldn't be upset that it contains garbage

    • 32 Comments

    There are many situations where you pass a structure to a function, and the function fills in the structure with information you request. In some cases, the function always fills in the entire structure (example: GlobalMemoryStatus). In other cases, you tell the function which bits of information you care about, to save the function the effort of computing something you weren't interested in anyway (example: TreeView_GetItem).

    In the latter case, if you say that you aren't interested in certain parts of the structure, and then you change your mind and start paying attention to them, don't be surprised if you find that there's nothing interesting there. After all, you said you didn't care.

    For example, if you call TreeView_GetItem and set the mask to TVIF_IMAGE | TVIF_PARAM, this means that you want the function to set the iImage and lParam members of the TVITEM structure and that you don't care about the rest. After the call returns, the values of those two members are defined, since you said that's what you wanted, and the remainder of the output fields are undefined. They might contain useful information, they might contain garbage, you're not supposed to care since you said that you didn't.

    Why might fields you said you didn't care about still contain information (correct or incorrect)? It might be that the value is so easy to compute that checking whether the value should be set takes more work than actually setting it! In such a case, the function might choose to set the value even if you didn't say that you needed it.

    On the other hand, the value might be an artifact of a translation layer: You pass a structure saying, "I'm interested in two out of the four members." The function in turn calls a lower lever function with a different structure, saying, "I'm interested in two out of the five members of this different structure." After the call returns, the middle-man function converts the lower-level structure to the higher-level structure. Sure, it may also "convert" stuff that was never asked for, but you said you weren't interested, so they just get garbage. In other words, the function you're calling might be defined like this:

    // The pinfo parameter points to this structure
    struct FOOINFO {
     DWORD dwInUse;
     DWORD dwAvailable;
     DWORD dwRequested;
     DWORD dwDenied;
    };
    
    // The dwMask parameter can be a combination of these values
    #define FOOINFO_INUSE     0x0001
    #define FOOINFO_AVAILABLE 0x0002
    #define FOOINFO_REQUESTED 0x0004
    #define FOOINFO_DENIED    0x0008
    
    BOOL GetFooInfo(FOOINFO *pinfo, DWORD dwMask);
    

    Now, the GetFooInfo function might just be a middle man that talks to another component to do the real work.

    // lowlevel.h
    
    struct LOWLEVELSTATS {
     DWORD dwUnitSize;
     DWORD dwUnitsInUse;
     DWORD dwUnitsAvailable;
     DWORD dwUnitsRequested;
     DWORD dwUnitsGranted;
     DWORD dwTotalRequests;
    };
    
    // The dwMask parameter can be a combination of these values
    #define LLSTATS_UNITSIZE  0x0001
    #define LLSTATS_INUSE     0x0002
    #define LLSTATS_AVAILABLE 0x0004
    #define LLSTATS_REQUESTED 0x0008
    #define LLSTATS_GRANTED   0x0020
    #define LLSTATS_REQUESTS  0x0040
    
    BOOL GetLowLevelStatistics(LOWLEVELSTATS *pstats, DWORD dwMask);
    

    The resulting GetFooInfo function merely translates the call from the application into a call to the GetLowLevelStatistics function:

    BOOL GetFooInfo(FOOINFO *pinfo, DWORD dwMask)
    {
     LOWLEVELSTATS stats;
     DWORD dwLowLevelMask = LLINFO_UNITSIZE;
    
     if (dwMask & FOOINFO_INUSE)
      dwLowLevelMask |= LLSTATS_INUSE;
     if (dwMask & FOOINFO_AVAILABLE)
      dwLowLevelMask |= LLSTATS_AVAILABLE;
     if (dwMask & FOOINFO_REQUESTED)
      dwLowLevelMask |= LLSTATS_REQUESTED;
     if (dwMask & FOOINFO_DENIED)
      dwLowLevelMask |= LLSTATS_REQUESTED | LLSTATS_GRANTED;
    
     if (!GetLowLevelStats(&info;stats, dwLowLevelMask))
      return FALSE;
    
     // Convert the LOWLEVELSTATS into a FOOINFO
     pinfo->dwInUse = stats.dwUnitSize * stats.dwUnitsInUse;
     pinfo->dwAvailable = stats.dwUnitSize * stats.dwUnitsAvailable;
     pinfo->dwRequested = stats.dwUnitSize * stats.dwUnitsRequested;
     pinfo->dwDenied = stats.dwUnitSize *
                       (stats.dwUnitsRequested - stats.dwUnitsGranted);
    
     return TRUE;
    }
    

    Notice that if you ask for just FOOINFO_DENIED, you still get the dwRequested as a side effect, since computing the number of requests that were denied entails obtaining the total number of requests. On the other hand, you also get garbage for dwInUse since the call to GetLowLevelStats didn't ask for LLSTATS_INUSE, but the code that converts the LOWLEVELSTATS to a FOOINFO doesn't know that and converts the uninitialized garbage. But since you said that you didn't care about the dwInUse member, you shouldn't be upset that it contains garbage.

    You now know enough to answer this person's question.

    (Note of course that I'm assuming we are not returning uninitialized garbage across a security boundary.)

  • The Old New Thing

    Performance consequences of polling

    • 52 Comments

    Polling kills.

    A program should not poll as a matter of course. Doing so can have serious consequences on system performance. It's like checking your watch every minute to see if it's 3 o'clock yet instead of just setting an alarm.

    First of all, polling means that a small amount of CPU time gets eaten up at each poll even though there is nothing to do. Even if you tune your polling loop so its CPU usage is only, say, a measly one tenth of one percent, once this program is placed on a Terminal Server with 800 simultaneous connections, your 0.1% CPU has magnified into 80% CPU.

    Next, the fact that a small snippet of code runs at regular intervals means that it (and all the code that leads up to it) cannot be pruned from the system's working set. They remain present just to say "Nope, nothing to do." If your polling code touches any instance data (and it almost certainly will), that's a minimum of one page's worth of memory per instance. On an x86-class machine, that 4K times the number of copies of the program running. On that 800-user Terminal Server machine, you've just chewed up 3MB of memory, all of which is being kept hot just in case some rare event occurs.

    Finally, polling has deleterious effects even for people who aren't running humongous Terminal Server machines with hundreds of users. A single laptop will suffer from polling, because it prevents the CPU from going to more power-efficient sleep states, resulting in a hotter laptop and shorter battery life.

    Of course, Windows itself is hardly blame-free in this respect, but the performance team remains on the lookout for rogue polling in Windows and "politely reminds" teams they find engaging in polling that they should "strongly consider" other means of accomplishing what they're after.

  • The Old New Thing

    When do I need to use GC.KeepAlive?

    • 34 Comments

    Finalization is the crazy wildcard in garbage collection. It operates "behind the GC", running after the GC has declared an object dead. Think about it: Finalizers run on objects that have no active references. How can this be a reference to an object that has no references? That's just crazy-talk!

    Finalizers are a Ouija board, permitting dead objects to operate "from beyond the grave" and affect live objects. As a result, when finalizers are involved, there is a lot of creepy spooky juju going on, and you need to tread very carefully, or your soul will become cursed.

    Let's step back and look at a different problem first. Consider this class which doesn't do anything interesting but works well enough for demonstration purposes:

    class Sample1 {
     private StreamReader sr;
     public Sample1(string file) : sr(new StreamReader(file)) { }
     public void Close() { sr.Close(); }
     public string NextLine() { return sr.ReadLine(); }
    }
    

    What happens if one thread calls Sample1.NextLine() and another thread calls Sample1.Close()? If the NextLine() call wins the race, then you have a stream closed while it is in the middle of its ReadLine method. Probably not good. If the Close() call wins the race, then when the NextLine() call is made, you end up reading from a closed stream. Definitely not good. Finally, if the NextLine() call runs to completion before the Close(), then the line is successfully read before the stream is closed.

    Having this race condition is clearly an unwanted state of affairs since the result is unpredictable.

    Now let's change the Close() method to a finalizer.

    class Sample2 {
     private StreamReader sr;
     public Sample2(string file) : sr(new StreamReader(file)) { }
     ~Sample2() { sr.Close(); }
     public string NextLine() { return sr.ReadLine(); }
    }
    

    Remember that we learned that an object becomes eligible for garbage collection when there are no active references to it, and that it can happen even while a method on the object is still active. Consider this function:

    string FirstLine(string fileName) {
     Sample2 s = new Sample2(fileName);
     return s.NextLine();
    }
    

    We learned that the Sample2 object becomes eligible for collection during the execution of NextLine(). Suppose that the garbage collector runs and collects the object while NextLine is still running. This could happen if ReadLine takes a long time, say, because the hard drive needs to spin up or there is a network hiccup; or it could happen just because it's not your lucky day and the garbage collector ran at just the wrong moment. Since this object has a finalizer, the finalizer runs before the memory is discarded, and the finalizer closes the StreamReader.

    Boom, we just hit the race condition we considered when we looked at Sample1: The stream was closed while it was being read from. The garbage collector is a rogue thread that closes the stream at a bad time. The problem occurs because the garbage collector doesn't know that the finalizer is going to make changes to other objects.

    Classically speaking, there are three conditions which in combination lead to this problem:

    1. Containment: An entity a retains a reference to another entity b.
    2. Incomplete encapsulation: The entity b is visible to an entity outside a.
    3. Propagation of destructive effect: Some operation performed on entity a has an effect on entity b which alters its proper usage (usually by rendering it useless).

    The first condition (containment) is something you do without a second's thought. If you look at any class, there's a very high chance that it has, among its fields, a reference to another object.

    The second condition (incomplete encapsulation) is also a common pattern. In particular, if b is an object with methods, it will be visible to itself.

    The third condition (propagation of destructive effect) is the tricky one. If an operation on entity a has a damaging effect on entity b, the code must be careful not to damage it while it's still being used. This is something you usually take care of explicitly, since you're the one who wrote the code that calls the destructive method.

    Unless the destructive method is a finalizer.

    If the destructive method is a finalizer, then you do not have complete control over when it will run. And it is one of the fundamental laws of the universe that events will occur at the worst possible time.

    Enter GC.KeepAlive(). The purpose of GC.KeepAlive() is to force the garbage collector to treat the object as still live, thereby preventing it from being collected, and thereby preventing the finalizer from running prematurely.

    (Here's the money sentence.) You need to use GC.KeepAlive when the finalizer for an object has a destructive effect on a contained object.

    The problem is that it's not always clear which objects have finalizers which have destructive effect on a contained object. There are some cases where you can suspect this is happening due to the nature of the object itself. For example, if the object manages something external to the CLR, then its finalizer will probably destroy the external object. But there can be other cases where the need for GC.KeepAlive is not obvious.

    A much cleaner solution than using GC.KeepAlive is to use the IDisposable interface, formalized by the using keyword. Everybody knows that the using keyword ensures that the object being used is disposed at the end of the block. But it's also the case (and it is this behavior that is important today) that the using keyword also keeps the object alive until the end of the block. (Why? Because the object needs to be alive so that we can call Dispose on it!)

    This is one of the reasons I don't like finalizers. Since they operate underneath the GC, they undermine many principles of garbage collected systems. (See also resurrection.) As we saw earlier, a correctly-written program cannot rely on side effects of a finalizer, so in theory all finalizers could be nop'd out without affecting correctness.

    The garbage collector purist in me also doesn't like finalizers because they prevent the running time of a garbage collector to be proportional to the amount of live data, like say in a classic two-space collector. (There is also a small constant associated with the amount of dead data, which means that the overall complexity is proportional to the amount of total data.)

    If I ruled the world, I would decree that the only thing you can do in a finalizer is perform some tests to ensure that all the associated external resources have already been explicitly released, and if not, raise a fatal exception: System.Exception.Resource­Leak.

    Bonus reading

Page 5 of 458 (4,571 items) «34567»