So I’ve been playing with the idea of how you could get deterministic behaviour out of managed code. Of course the party line is that it’s not possible, but to me that’s just throwing down the gauntlet. They also say you can’t suspend and resume a managed thread, to which I replied “Yeah? Watch me!”
This was fueled when I was at DevCon and sat in on a lab of Nat Frampton’s where you simply create an ISR that responds to a contact on a serial port pin. I wondered “well why the hell can’t I do that in managed code?” No reason really – I mean it’s simply setting up an event to fire when an interrupt is received, and all of that can be P/Invoked (I haven’t actually written the code yet, but there’s nothing magic about it). The problem comes with determinism.
Conventional wisdom says that the GC suspends all managed threads when it’s doing its work (which can be annoying in most cases). If this were to happen while you were doing your ISR work, you could get a really bad outlier. So your system responds in milliseconds most of the time, but occasionally it takes a few seconds. That’s unacceptable – a box flies of the conveyor and hits the floor, making a mess.
So how do we handle this? How about setting the GC thread priority to 255 at the start of your ISR, then back to it’s original priority afterward? To even better handle it, your ISR priority needs to be set high.
How do we proceed then? We need the GC thread handle to manipulate its priority. In comes the toolhelp libraries. I wrote a ToolHelp wrapper for the SDF earlier in this quest, but I just realized yesterday I only had the PROCESSENTRY32 stuff done, not the THREADENTRY32, so I spent last night doing that piece.
Still, the THREADENTRY32 only has a ThreadID – how are we to determine which thread is the GC as opposed to all the other threads we may have in our process? Well, I ran a quick check with a slap-together process viewer app based on my new toolhelp wrappers and I see this:
Notice the Priority 248 thread then think about managed priorities – there are five ranging from Lowest (0) to Highest(4), which presumably equate to 255 to 251, though I’ve yet to check.
My initial thought was that the 248 priority might be the GC, after all it would make sense that it’s higher priority, though I also recall that all manged apps need 3 threads. So why do I have 5? Well the answer is that this was running through the debugger. When run stand-alone, I get 3 threads, all with a priority of 251.
So where does that leave us? Well first, it’s evident that 251 is “Normal” priority, so I’ll need to map out the actual values for the managed equivalents, but more importantly we still have no way to uniquely identify the GC thread (that I’ve found anyway).
Right now that’s the show stopper. If you’ve got any ideas on how to reliably identify the GC thread handle, I’d love to hear them.
I guess on the plus side, outside of the designer work, it’s only about 10 lines of code to create the process viewer you see here. I’ll probably add a few features and turn it into a sample for using the SDF.