jd@csd4.milw.wisc.edu (James R Drinkwater) (02/22/89)
Signals that are caught and assigned a signal handler are reset after a call to exec. Besides the fact that if they were not reset, a security problem would result with set-uid programs that are exec'ed, the only other reason I can think of is that exec overlays the calling process, so all code is lost. Are there other reasons that I am missing? Can you think of examples in which you would like to keep a signal handler installed across exec? -- Jim Drinkwater Internet: jd@csd4.milw.wisc.edu UUCP: uwvax!uwmcsd1!uwmcsd4!jd
gwyn@smoke.BRL.MIL (Doug Gwyn ) (02/23/89)
In article <1187@csd4.milw.wisc.edu> jd@csd4.milw.wisc.edu (James R Drinkwater) writes: >Can you think of examples in which you would like to keep a signal handler >installed across exec? Since it's not possible, what's the point?
lm@snafu.Sun.COM (Larry McVoy) (02/23/89)
In article <1187@csd4.milw.wisc.edu> jd@csd4.milw.wisc.edu (James R Drinkwater) writes: >Can you think of examples in which you would like to keep a signal handler >installed across exec? This makes no sense. A signal handler is part of your address space. That goes away on an exec. Larry McVoy, Lachman Associates. ...!sun!lm or lm@sun.com
greg@ncr-sd.SanDiego.NCR.COM (Greg Noel) (02/24/89)
In article <1187@csd4.milw.wisc.edu> jd@csd4.milw.wisc.edu (James R Drinkwater) writes: >Can you think of examples in which you would like to keep a signal handler >installed across exec? In other articles, Larry McVoy and other folks argue that this doesn't make much sense, since a signal handler is part of your address space, which is lost upon an exec. This was my initial reaction, too, but then I remembered a paper at the Winter USENIX conference that presented something called "variable-weight processes." This paper very neatly unified the model of a thread and a process by defining groups of resources, including memory map, file descriptors, signals, and other resources, that could be shared between a parent and child thread. At the one extreme, sharing everything, this gives a "traditional" thread, while at the other extreme, sharing nothing, this gives a "traditional" (heavy-weight) process. In between are some interesting options, including the possibility of sharing signals, but not sharing an address map. If anybody knows how this kind of semantics was worked out (my copy of the Proceedings isn't here, and my fuzzy memory of the paper itself says that they didn't discuss it), I'd be interesting in hearing about it. -- -- Greg Noel, NCR Rancho Bernardo Greg.Noel@SanDiego.NCR.COM or greg@ncr-sd
ram@lcuxlm.ATT.COM (Miani Rich) (02/28/89)
In article <941@ncr-sd.SanDiego.NCR.COM>, greg@ncr-sd.SanDiego.NCR.COM (Greg Noel) writes: > > This was my initial reaction, too, but then I remembered a paper at the > Winter USENIX conference that presented something called "variable-weight > processes." This paper very neatly unified the model of a thread and a > process by defining groups of resources, including memory map, file > descriptors, signals, and other resources, that could be shared between I think the paper was entitled "Lightweight Processes" if that helps anyone. I have a copy somewhere ... I'll try and dig it up for those that want it...
greg@ncr-sd.SanDiego.NCR.COM (Greg Noel) (02/28/89)
In article <941@ncr-sd.SanDiego.NCR.COM>, I write: > This was my initial reaction, too, but then I remembered a paper at the > Winter USENIX conference that presented something called "variable-weight > processes." This paper very neatly unified the model of a thread and a > process by defining groups of resources, including memory map, file > descriptors, signals, and other resources, that could be shared between In article <2071@lcuxlm.ATT.COM> ram@lcuxlm.ATT.COM (Miani Rich) writes: >I think the paper was entitled "Lightweight Processes" .... The citation is "Variable-Weight Processes with Flexible Shared Resources" by Ziya Aral, Illya Gertner, Alan Langerman, and Greg Schaffer of Encore Computer Group and James Bloom and Thomas Doepplner of Brown University. It's in the proceedings of the Winter 1989 USENIX Technical Conference, pages 405-412. It's this sort of model that allows the Unix operating system to grow and still remain compatible with earlier versions -- identifying the common concept behind different things. This particular model unifies processes and threads in a way so that a program can have greater control over its resources. I hope those architects who are designing our follow- on operating systems (I'm thinking of Mach, 4.4BSD, SysV.4, ...) should look at this paper and think seriously about this model. Encore is on the the net, and I think Brown is, as well. Do any of the authors (or others) wish to discuss the subject further? -- -- Greg Noel, NCR Rancho Bernardo Greg.Noel@SanDiego.NCR.COM or greg@ncr-sd
aral@pinocchio.Encore.COM (Ziya Aral) (03/02/89)
In article <963@ncr-sd.SanDiego.NCR.COM>, greg@ncr-sd.SanDiego.NCR.COM (Greg Noel) writes: [After referencing our USENIX paper on "variable-weight" processes] > ... If anybody knows how this kind of semantics was worked out (my > copy of the Proceedings isn't here, and my fuzzy memory > of the paper itself says that they didn't discuss it), I'd be interesting > in hearing about it. In article <963@ncr-sd.SanDiego.NCR.COM>, greg@ncr-sd.SanDiego.NCR.COM (Greg Noel) writes: [After some much appreciated praise of our paper again asks: ] > Encore is on the the net, and I think Brown is, as well. Do any of the > authors (or others) wish to discuss the subject further? Ok, Greg, you asked for it... Actually, the work on variable-weight processes was motivated by Parasight, a parallel debugging/programmming environment for shared-memory multis under MACH and BSD. Parasight runs parallel applications and various development tools in the same space. Since this introduces a large degree of heterogenity in the threads of control sharing one address space, it also violates the assumption that multiple light-weight threads of control will be essentially homogeneous (i.e. that they will share their entire environment). That is really the underlying assumption of "light-weight" threads. Our experience indicates that with real parallel programs, the assumption of an entirely shared environment with multiple identical threads of control: a) Is not always true. b) Is almost never entirely true. There are many cases of private file descriptors or private signal handlers being quite useful to otherwise similar threads of control. At a higher level, the idea of "light-weight" threads also complicates the semantics of UNIX. In place of a single fundamental unit of execution, such as a process, we now have to deal with two, one "light-weight" and the other "heavy-weight". A semantic "gap" seems to inevitably appear between them. In MACH for example, a group of threads shares a common signal handler. So which one takes the signal? The answer is that the first available takes it. This is not always appropriate behavior and the answer "don't use signals" is not very helpful. We took a slightly different approach. Instead of introducing a light- weight process or "thread", we asked what gives UNIX processes their "weight". It turns out that very little does so inherently. UNIX carries its history around with it. When a process is created, it defines its system context, or resource set, in-line. It assumes that this resource set will be private to that process, in keeping with its original time-sharing perspective. It then proceeds to initialize this entire environment. This is the only thing that makes a process "heavy": the need to intialize and then drag around a private universe, a seperate address space being by far the most important component. But if we seperate a resource from its process and make it idependently usable by many processes, then we don't have to initialize but once. The idea of sharable resources is really identical to things like SysV shared memory regions supported at the process level. The result is that processes become variably "weighted", their cost depending on the number of private resources they initialize. In practice, the transformation is very easy. A level of indirection is added to the PROC and USER data structures to reference resources externally. Resources exist independently and have a link count assosciated with them. When the link count goes to zero, the resource automagically disappears. Linking to resources is through inheritance. A single new system call, resctl(), specifies whether the children of a process will inherit links to its existing resources (or a subset of them), or whether it will create new ones. The default is existing process behavior. The actual changes to the kernel are almost trivial, especially in comparison to the very real work assosciated with making individual resources multi-threaded and sharable. It is more a conceptual change than a code change. The result is "heavy-weight" processes which have the same startup costs and are identical to existing processes, "light-weight" processes which have the same startup costs as MACH threads (somewhat faster actually, we will publish some interesting numbers soon...), and every combination in between with the added benefit of semantic uniformity across the whole range. Similar benefits should accrue to context switch times and so on. For example, if 2 processes share the same memory resource, it should not be necessary to reload the MMU, etc. when they are switched, provided either that the scheduler knows about it or that second level scheduling is provided. Our nUNIX kernel does not yet do this optimization. As to the amount of state an execution unit absolutely has to carry around with it, that is largely fixed and will not change whether we call it a process, a thread, or a banana. So why invent new paradigms? To be honest, the idea that this whole thing might be useful to uniprocessors and a conventional, co-operating processes model did not occur to us till much later. In fact, it is just the inverse of the parallel case; while conventional processes are largely private, they can often benefit from a degree of sharing. PHEW!!! I will be happy to fill in any details if anyone is left awake. This should teach Greg NEVER to ask an author to "elaborate" on his work :-) Ziya Aral aral@multimax.encore.com My opinions are my own.
greg@ncr-sd.SanDiego.NCR.COM (Greg Noel) (03/03/89)
In article <5025@xenna.Encore.COM> aral@pinocchio.UUCP (Ziya Aral) writes: >I will be happy to fill in any details if anyone is left awake. >This should teach Greg NEVER to ask an author to "elaborate" on his work :-) Er, no, it doesn't -- but it does bring us back to the initial topic, which was, what happens if you have shared signals between two processes, but separate address spaces? How do the semantics of that work out? -- Greg -- -- Greg Noel, NCR Rancho Bernardo Greg.Noel@SanDiego.NCR.COM or greg@ncr-sd
aral@pinocchio.Encore.COM (Ziya Aral) (03/10/89)
In article <986@ncr-sd.SanDiego.NCR.COM> greg@ncr-sd.SanDiego.NCR.COM (Greg Noel) writes: >Er, no, it doesn't -- but it does bring us back to the initial topic, which >was, what happens if you have shared signals between two processes, but >separate address spaces? How do the semantics of that work out? I will have to be forgiven because I don't make it to the net every week and am not entirly familiar with the history of this discussion. I assume that the original discussion is implied by the subject "Signals after exec". The nUNIX kernel does not address the propogation of anything across execs. It basically specifies that whenever a resource is copied (via fork), it can instead be shared. As far as forks go, there is no semantic problem. A conventional fork propogates the signal handler by copying the address space of the parent, including the signal handler, to the child. The only change that nUNIX adds is that the memory and/or signal resource of the parent may be shared rather than copied. All possible combinations are legitimate because the signal handler, whether shared or private, remains visible after the fork. The only difference in a shared signal resource is that changes made to it by any one process which uses it impact all processes which share it... i.e. the table of signal handlers plus some additional state is made sharable. When we implemented shared signal handlers, we discussed whether the signal event itself should be shared (as in MACH). We opted for the more conservative approach of only sharing handlers as this is much better defined. The nUNIX prototype also takes a very conservative view of what constitutes a "resource". Essentially it defines independent resources as only the the six classes of resources currently broken out in the user.h header (i.e. memory, signals, file descriptors, process stats, protection, and resource control). While it is clear that other process attributes could be broken out as independently sharable resources and that additional resources could be easily added (the direction of our current research), this would not really impact existing semantics. The reason shared resources do not impact exec is that exec implies a process transformation in which only some of the original process state is retained. In particular, it means that a new memory resource, and thus also a new signal resource must be created. The retention of existing semantics means that memory sharing stops at an exec. For what is inherited across an exec, instead of inheriting the the appropriate values of the exec'ing process, the execee transparently inherits the link to the resource and whether that resource is shared or not is largely irrelevent. If additional process attributes were to be made independently sharable resources (for example, interval timers), the same would apply. If exec semantics were to be changed to allow the inheritance of more process state, the same answer would again be valid PROVIDED that such a change did not fundamentally change UNIX semantics. The propogation of signal handlers across exec() is an entirely different issue in that it violates the last point above quite apart from the issues of shared vs private resources. UNIX semantics define signal handlers as mere user subroutines of arbitrary complexity and execs as chaining operations. The contradiction that other posters must have mentioned becomes immediately obvious. There is no way to reconcile the inheritance of signal handlers without inheriting the image (shared or not) of the exec'ing process and that is the exact opposite of what an exec is meant to do. Here it is not even possible to retain part of the original image because there are no limits on the dependencies of signal handlers. Since the original image AND its logic disappears, the signal handlers must disappear with it. While it could be argued that UNIX's address space and its user-level exception handling are thus too tightly coupled, other solutions would be less general. It may be possible to exercise a much more restricted form of control over the exec'ed child by making the sigmask (currently process private in nUNIX) and some additional signal state into an independently sharable resource but I have not really thought about it. Ziya Aral aral@multimax.encore.com