RSS 2.0

Personal Info:

Joe Send mail to the author(s) leads the architecture of an experimental OS's developer platform, where he is also chief architect of its programming language. His current mission is to enable writing large-scale software that is reliable, secure, and scalable by-construction. Before this, Joe founded the Parallel Extensions to .NET project. He has been granted 19 patents, with 49 pending. When not working, Joe enjoys travelling with his wife, writing books, writing music, studying music theory & mathematics, and doing anything involving food & wine.

My books

My music

Disclaimer:
The content of this site are my own personal opinions and do not represent my employer's view in anyway.

© 2012, Joe Duffy

 
 Wednesday, May 03, 2006

Raymond's recent post talks about queueing user-mode APCs in Win32.

When you block in managed code, the CLR is responsible for figuring out the correct style of wait. This ends up in a CoWaitForMultipleHandles (on Win2k+) or MsgWaitForMultipleObjectsEx if you're executing in an STA; else, this ends up in a non-pumping wait, such as WaitForSingleObjectEx/WaitForMultipleObjectsEx. In any case, the wait is alertable, meaning that user-mode APCs will have a chance to run. There are various blocking calls hidden in Win32 and the CLR itself, so it's not guaranteed that all waits are alertable; but any that originate from managed code are, which we hope is a significant percentage.

This code illustrates a simple user-mode APC reentering as we do an alertable wait (via Thread.CurrentThread.Join(0)):

using System;
using System.Runtime.InteropServices;
using System.Threading;

static class Program {

    static void Main() {
        QueueUserAPC(
            delegate { Console.WriteLine("APC fired"); },
            GetCurrentThread(),
            UIntPtr.Zero);

        Console.WriteLine("Doing join");
        Thread.CurrentThread.Join(0);
        Console.WriteLine("Finishing join");
    }

    delegate void APCProc(UIntPtr dwParam);

    [DllImport("kernel32.dll")]
    static extern uint QueueUserAPC(APCProc pfnAPC,
       
IntPtr hThread, UIntPtr dwData);

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentThread();

}

While this technique seems like an effective way to reuse a thread while it is blocked -- for example, you might contemplate doing this for thread-pool threads -- a little problem called thread affinity tends to arise. I wrote about this in terms of COM reentrancy before. An APC reentering doesn't perform a context transition, so even if we used a logical context to store such state, the problem would still exist. The simple fact is that user-mode APCs are good for system bookkeeping, but not for running general purpose code that modifies arbitrary program state.

5/3/2006 8:53:38 PM (Pacific Daylight Time, UTC-07:00)  #   
Tracked by:
http://www.google.com/search?q=jkzddfce [Pingback]

 

Recent Entries:

Search:

Browse by Date:
<May 2006>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Browse by Category:

Notables: