Re: Safely implementing Thread.Abort
Russell Stuart <[email protected]>
| Newsgroups | gmane.comp.gnu.dotgnu.developer |
|---|---|
| Organization | Lube Mobile PTY LTD |
| Message-ID | <1085019497.23372.254.camel@ras> |
On Thu, 2004-05-20 at 07:36, Rhys Weatherley wrote: > Outputting abort check instructions on every backward > branch is OK with me, as long as you only do it in > programs that use Thread.Abort. This can be detected > by the loader (any assembly with a MemberRef to > Thread.Abort is a candidate). This relies on knowing whether any code calls Thread.Abort(). There are two issues with that. First of all, how are you going to know? Scan every assembly referenced when you first start up? Some of these assemblies might use Thread.Abort(), and yet it may never be called. Secondly, what about programs that do a System.Reflection.Assembly.Load? You might discover the loaded assembly might calls Thread.Abort() after you have generated some code. A variation on the theme is Remoting. A remote procedure may call Thread.Abort(). I see how you could know that. On Thu, 2004-05-20 at 08:47, Rhys Weatherley wrote: > For now, implement the check on backwards jump as-is. This will always work, but you have generate equivalent code for the JIT. Will you be able to bring yourself to do that? It won't be just an instruction or two. The "tst" op-code will overwrite the CPU's condition flags, which will have to be restored if you are doing a conditional backward jump. In any decently optimised code most of them are conditional. On Thu, 2004-05-20 at 08:18, Rhys Weatherley wrote: > How exactly are you going to do that? The CVM instruction > pointer is probably going to be in a register (esi on x86). > You cannot guarantee that the CVM instruction pointer is in > "thread->pc" when an abort occurs. This is true. In fact even in a Unix Signal you will have no idea of the "true" value of thread->pc - because you don't in general know what register it is in. Thus my original suggestion was modify every backward jump in the current method. That won't catch every case - the thread being aborted may be in the middle of constructing/destroying a frame. The only way I can see around that is the Abort() method hanging around until it sees the aborted thread has processed the abort, or until its the stack frame changes - in which case it has another go at stopping it. On Thu, 2004-05-20 at 07:36, Rhys Weatherley wrote: > You cannot use any approach that requires the method code > to be modified after it is first generated. It isn't thread safe: I am not convinced of that. Firstly, no matter what you do, you have set a thread->aborted flag, and you have to force the thread to see it, ie you have to force it into the cache of the CPU it is executing on. I think all operating systems that support multiple CPU's provide a means of doing that, as tum has noted. Forcing the CPU to see modifications you have made to its instruction stream is essentially the same problem. Secondly, on all multi CPU architectures I know of writes to a word are atomic. By this I mean a if a single instruction writes some bytes that do not cross a word boundary, no CPU will see some bytes written and some not. Either they will see the entire write, or none of it. Here "word" means the width of the narrowest memory bus - typically the one to main memory. With DIMM's this is 64 bits. With CVM, where we have control over the op-codes, life is very simple. All you need to do is have two versions of the "backward jump" opcode. The one normally generated doesn't check for Abort()'s. When Abort()'s is executed, you replace it with one that does. This can't possibly be non-thread safe. With the JIT life gets harder, because you can't typically just modify one byte. You have to insert some sort of "call" instruction. It could be a "call", or it could generate a software interrupt (like the ia32 int3). Whatever you do, providing you can make the modification with just one write to a word aligned value, you can get away with it. This means the JIT would have to word align the backward jumps and returns. I don't really think its a question of whether its possible to implement Thread.Abort() with zero overhead to programs that don't use it - it is. With CVM its not even that hard to do. With the JIT - well it sounds like an awful lot of effort to me, but I can't think of a simpler solution ATM.