Re: Safety of running and stopping dynamically loaded code


Doug Lea (dl@cs.oswego.edu)
Thu, 18 Mar 1999 08:55:51 -0500 (EST)


(Cross-posted since this is also a reply of sorts to Bela's `Can you stop this thread?' post on dist-obj-tech.) Stopping threads can be hard. Not just in Java. Safe yet effective stops require that all parts of a JVM and all other application code except possibly the code you are cancelling needs to be asynch-signal-safe, that is, capable of responding sensibly (normally via rollbacks of some sort) to an asynchrononous interruption after every bytecode. (For some simple examples, see my http://gee.cs.oswego.edu/dl/cpj/cancel.html). Even restricting to asynch-cancel-safe (i.e., only guaranteeing safety wrt cancellation signals, not arbitrary signals) is hard. Historically, programmers have been unable to cope with this requirement. For example, in POSIX, only a small number of system routines are required to be asynch-cancel-safe. NO system-level methods supported in any JVM are guaranteed to be asynch-cancel-safe, and it is extremely unlikely that any significant chunk of code you or I or any Java developer writes is asynch-cancel-safe. (Try it sometime, in any language.) These kinds of concerns led me to be among the people arguing for deprecation of Thread.stop last year or so. (So feel free to blame me, (although mainly Josh Bloch and David Stoutamire) for this state of affairs!) We knew that this would cause almost as many problems as it solved, but the problems it creates are all liveness issues, which I think must be treated as secondary to the safety issues here. Digression: Here is a common objection: Most Java code isn't very robust, and objects will be broken when all sorts of run-time exceptions occur, not just via stop. So stop isn't particularly special. I think this is a non-issue. I want the ability to write a fully robust servlet runner or mobile code engine or web browser. Stop() is the only thing getting in the way of this. I don't care if other people write code that breaks THEIR objects, but I do need to be confident about the states of MY objects. But the problems are very real when the code you are trying to kill is not designed to be gracefully cancelled via Thread.interrupt. My take on this though is that you probably don't want much more than is currently available in the language. But definitely a little more: Perhaps surprisingly, the thing you need most is some kind of weak fairness guarantee: That an enabled thread will eventually execute. (Or acceptably weaker yet: it will eventually, with probability 1, execute.) Additionally, there need to be tighter (although still acceptably probabalistic) rules surrounding priorities. You actually get the right behavior (although unprovably so) on all JVMs I know running on native threads (via preemption+aging), so this is more a spec issue than a pragmatic problem. But addressing it would provide a guarantee that a supervisory thread that is trying to kill another will eventually get a chance to do so, and that one of the things the supervisory thread can do is lower the priority of others. The second thing you need is better resource control, so that if a thread does not respond to interrupts, you can still deny it resources that it would need in order to continue. The nice thing about resource-based intervention is that it is synchronous, so JVMs and application-level engines have a finite chance of being able to pull it off safely. Currently, there are only two ways to do this: * Resource denial: Writing dynamic SecurityManagers that will start denying all accesses to a certain Thread (or ThreadGroup, or whatever) on demand. As I say a lot, many kinds of resource control in Java are best construed as dynamic versions of access control. For example, instead of statically controlling whether a caller can open a file, a dynamic manager controls whether it can open a file given that it has been cancelled (among other environmental factors that it might consider). The 1.2 security framework is pretty good. I'd love to see it leveraged to deal better with dynamics. * Resource revocation: Using asynchronous closes() of files and sockets that these threads are using. This actually works very well and would handle perhaps even the majority of cases that arise in practice, except that it requires that you somehow know which files/sockets to close, which you often do not. It's clear that more work is needed to better guarantee scheduling etc properties as well as to control resources of cancelled activities. But at the moment, I'm not at all convinced that anything further is necessary or desirable. If you can: 1. Guarantee that supervisory threads will be able to run in order to cancel others. 2. Prevent cancelled threads from attaining further resources, and revoking at least some of the ones they already own. 3. Lower priorities on cancelled threads that do not respond to interruptions and do not access further resources. Then what more do you want, and why? There ARE some outstanding problematic scenario I can think of, but I don't think they are directly related to cancellation. For example, what to do about the possibility of weird denial-of-service attacks in which large numbers of new threads are created and then do nothing, yet ignore interrupts -- for example, spinning on `for(;;);'. Even though each one can be made to minimize resource consumption (running at lowest priority, not being able to acquire additional resources, etc), the fact that there are so many of these threads can be a problem. But a very different kind of problem -- one for which certificate-based trust frameworks employed at foreign code-loading time probably best apply. The flip side of these issues is how to make code essentially immediately responsive to interrupts when you need it to be. Right now the only answer in Java is that you must frequently poll for interrupts. The POSIX folks took a different line of attack. In POSIX threads, you can dynamically set the mode of cancellation to be either synch or asynch. This is vaguely analogous to unmasking interrupts. I think that someone has suggested something similar for Java real-time extensions. I can't quite get myself to appreciate the utility of this in Java though. In the limited cases where it applies, frequent polling seems like an acceptable solution. -- Doug Lea, Computer Science Department, SUNY Oswego, Oswego, NY 13126 USA dl@cs.oswego.edu 315-341-2688 FAX:315-341-5424 http://gee.cs.oswego.edu/ ---------------------------------------------------------------------------- To unsubscribe (or other requests) mailto:majordomo@media.mit.edu List archives, FAQ, member list, etc. http://gee.cs.oswego.edu/dl/javares/



This archive was generated by hypermail 2.0b3 on Thu Mar 18 1999 - 09:33:16 EST