Path: utzoo!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!att!cbnewsh!dwc From: dwc@cbnewsh.ATT.COM (Malaclypse the Elder) Newsgroups: comp.arch Subject: Re: Why fork? (long, was Re: IBM PC prehistory) Message-ID: <7446@cbnewsh.ATT.COM> Date: 17 Jan 90 18:42:19 GMT References: <610@ssp11.idca.tds.philips.nl> <952@dms.UUCP> Organization: The Legion of Dynamic Discord Lines: 100 In article <952@dms.UUCP>, albaugh@dms.UUCP (Mike Albaugh) writes: > > > Fortunately, this is normally not much of a problem, since usually a program > > does an exec() shortly after the fork() and this exec() can fix the problem. > > > > This scheme is not very elegant, but it allows one to run a unix system > > on hardware like ST, Mac and Amiga. > > SO--- Why do we _still_ use fork() for all these near-trivial > cases. I have been mucking around with computers for over 20 years but am > not really familiar with *nix. I would like a reality check on this. > I'm also not asking on comp.unix... because I'm afraid that would be > like asking pointed questions about the trinity in a seminary :-) Since > comp.arch folk have to deal with _implementing_ this stuff, I thought I'd > get a more reasoned response ( 1/2 :-). Anyway, I can see a few reasons > to use fork: > > 1) It can be used for part of spawn _and_ for actual task-splitting > (problem subdivision). Why have two calls when one will do? > 2) On machines that are only (or mainly) swapping anyway, there is no > penalty, so what the heck. > 3) By just (effectively) copying the entire memory space, we don't > need to keep track of just which parts actualy _need_ to be > passed to the new task (laziness as a virtue :-). > 4) "We have always done it this way". > > (my personal feelings are that 1 & 2 were the original reasons while > 3 & 4 are the reason we are stuck with it now) > actually, we indirectly address this type of question in a paper we are presenting at the winter usenix in washington next week. the paper is titled "insuring improved vm performance: some no-fault policies" and discusses some things we did to improve vm performance in unix system v release 4. in it, we argue that the idea that all forks are followed IMMEDIATELY by execs is misunderstood. it all depends on what you mean by IMMEDIATELY. to fully understand the scale of IMMEDIATELY, you have to think about how forks and execs are used. on MOST systems, the majority of forks are executed by programs that are classified as "shells". these shells are command interpreters whose function is to provide a command level interface to users and often also provide a programming language for executing "shell scripts". all major shells (bourne shell, ksh, csh) provide for such things as i/o redirection, argument expansion, etc. in other words, the shell must allow for the child to have an environment that may be substantially different than the parent. and some shells provide such things as history files, command recall, etc. the bottom line is that for these shells, more than just "a couple of instructions" are executed between fork and exec. thus, it really was a stroke of genius to have a fork call that duplicates the parent and allow the child to craft its environment the way that it wants to since you have to provide primitives to allow a process to change its environment anyway. the alternative is to have a single call with a HUGE argument list to specify all the options. and maintaining compatibility with new release would be a major hassle under this scheme. > Against this we have the problems mentioned above with handling *nix > programs on machines without dynamic relocation. Also, even machines > that _can_ do relocation don't get fork for free: > > 1) Machines with base/bounds registers may need to copy the whole > memory image to a new area. If they have two sets (e.g. KA10) > they might get away with "only" copying the data segment. > 2) Paging machines still need to at least mark all data pages > "copy on write", which may involve traversing the segment > and page tables in software. For a large image this can > be time consuming. Also, I'd imagine it's a real judgement > call whether to deal with a page at a time or just punt and > do the copy as soon as "enough" of the image has changed to > make write-trap handling a nuisance. > > And all this hassle so that three or four instructions later the > program can overlay itself (most of the time). I must be missing something > major here. Can someone tell me what? > on one hand its a matter of your point of view. do you design the operating system to fit the machine or do you design it to provide a nice interface to programmers/users (and put minimal requirements on the machine to support your operating system design)? we can argue religiously about it but it all comes down to costs and market niches. for some, increasing the system cost for an mmu more than offsets the cost of having programmers write code to "do it with mirrors". for others (depending on market niche), it may not pay. to summarize, i believe that people argue about fork/exec without really thinking about who uses it and how it is used. if you accept my assertion that shells are the almost exclusive users of the fork/exec interface, you will realize that more than just 3 or 4 instructions are executed between forks and execs. and since shells tend to be reasonably sized processes, the concern about doing forks of large processes is currently unjustified. but nothing stays constant and these large new graphical user interfaces may change things. as a final plug, read the paper in the conference proceedings. i even present a nice new way of avoiding copy on write faults after forks which is pretty clever (a biased opinion). danny chen att!hocus!dwc