Most of this lokos really good :-)
>1) Named pipe server creates new thread on receipt of signal
I'm assuming you read the signal number somewhere in between here?
Before the WriteFile, no?
>2) New Thread issues WriteFile (thereby immediately informing
>the signaller
>of the receipt of the signal)
[snip]
>4) Changes to the current signalling state would simply
>PulseEvent(someManualEvent)
Please note that the documentation says: Note This function is
unreliable and should not be used. It exists mainly for backward
compatibility.
We might be immune to the problems with it, but we need to check that
really carefullyi before using it. I try to stay away from functions
like that, since it can come back and bite you later when something is
modified :-)
>[Note: we'd need to protect the "current signal is blocked"
>test with the
>existing Critical section (faster, but haven't convinced myself this is
>completely safe), or change all the existing crictical section
>calls to be
>locks/releases on the above "someMutex" (slower, but bulletproof)]
What would the problem with the critical section be? It should be just
as safe as a mutex only a lot faster. The limitation it has compared to
a mutex is that it can only be used between threads in a processes,
whereas the mutex exists in the global namespace.
The only thing you really can't do with critical sections, AFAIK, is
that a thread can only block on one CS at a time. With mutexes, you can
use WaitForMultipleObjects() on two mutexes and go with whichever became
available first.
>However, there is nothing in either my nor your suggestion that guards
>against the following race-condition. Essentially, nothing is
>stopping the
>APC actually being run at some later time (because, as you'll
>note, we've
>only stopped the queuing of the APC, not the actual execution) when it
>should be blocked.
>
>AFAICS, a simple solution to this exists. Execute a SleepEx(0,TRUE)
>(strictly, whatever __pg_poll_signals ends up being) on entry to any
>function that changes the current signalling state. That way, we'll
>guarantee that our signals will be delivered + executed before
>it becomes
>unsafe to do so.
Sounds like a good solution to me.
Here's another idea altogether for the blocking signals (just occured to
me, may be seriously flawed, but I figured I should at least get it out
there):
How about keepnig a bitmask of "queued signals". These are signals that
were "fired while blocked". Then at the top of the functions that modify
the signal blocking mask, check if there are any queued executions for
signals that are currently not blocked (meaning they just became
unblocked). (And of course, clear the queue of that signal).
Doing this should remove a lot of the complexity from the signal
handling threads, since they don't have to stay around until the actual
execution of the signal.
If a signal is queued twice while blocked, should the handler execute
twice once the signal is unblocked? If so, the bitmask would have to be
replaced with an array of counters, but the general idea still remains.
Thoughs?
//Magnus