So today I gave Scott Holden of Compact Framework Dev Team fame to discuss my obsession with the GC. These were my take-aways from the call:
- The GC actually runs *on* the executing thread, so there’s no specific GC thread to get ahold of. So much for that idea (at least I got a real Process Viewer out of it, not that piece of crap Running Programs thing).
- Since GC won’t happen during a P/Invoke call I was considering calling an unmanaged DLL that would host the EE, pass it a function pointer (evidently available in CF 2.0 – been too busy to actually investigate), and have the DLL run the ISR. Evidently when you step across the managed/unmanaged boundary in either direction, the GC is given a chance to run. There goes that idea.
- The GC has no mechanisms for telling it not to run. The only way to prevent it’s running in any piece of code is to not make an allocation (simple for the ISR itself). You must be guaranteed that no allocation happens in the process. Since the ISR really must run in its own thread, you’d have to have some sort of locking mechanism against *all* memory allocations during the ISR execution. Ugly if possible at all. There goes that idea.
- Scott believes that “impossible“ is rare in software, though this one borders on very, very difficult. He said getting a driver hosted in device.exe might be more difficult, but the two are probably the closest to the impossible line he can think of.
So the call left me a bit disappointed.
Since nothing fun ever comes easy, I back-burnered the idea for a while – until I was washing dishes tonight to be precise – and then I had an epiphany – “what alcoholics refer to as a moment of clarity” if you will.
Given that the GC runs on the current thread and given that if you make no allocations during the execution of a section of code (your ISR) then the GC won’t run, then all we have to do is to make sure that our ISR makes no allocations and is guaranteed to be the running thread, right? Well why not use CeSetThreadPriority to set our ISR/IST thread priority higher (well lower numerically) than any other managed thread can go?
Think of it this way: you have your main thread at priority 251, it creates an IST and sets it’s priority to 245 or so. The IST allocates whatever it needs for the ISR execution and then blocks on a WaitForSingleObject waiting for the interrupt event. The main thread then runs along merrily until blam! We get an interrupt. The IST unblocks and interrupts the primary thread because of its priority (setting a high quantum may be a good idea too?). The ISR runs, does its thing, then blocks again at WaitForSingleObject.
In theory it sounds good, but right now it’s just an idea. I’ll attempt to find time to give it a try in the next few days. The only problem I see right now is what if the GC is already collecting at the time of the interrupt? Will the IST be blocked until the GC is done, or will the GC be running on the primary thread, so it in turn will be interrupted by the higher priority IST? Only experimentation will tell.