Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!cmcl2!rutgers!ucla-cs!zen!ucbvax!apollo.UUCP!rees From: rees@apollo.UUCP (Jim Rees) Newsgroups: comp.sys.apollo Subject: Re: SET_SBRK_SIZE() considered brain damaged ... Message-ID: <8709161235.AA06006@apollo.UUCP> Date: Wed, 16-Sep-87 08:27:09 EDT Article-I.D.: apollo.8709161235.AA06006 Posted: Wed Sep 16 08:27:09 1987 Date-Received: Fri, 18-Sep-87 07:13:48 EDT Sender: daemon@ucbvax.BERKELEY.EDU Organization: The ARPA Internet Lines: 78 What is it about Domain-IX/AEGIS which keeps "sbrk()" from just allocating some more turf when it runs out of heap space up to the virtual memory limit? The semantics of sbrk() don't fit into a modern computer address space. Sbrk() was invented back in the days when you had some limited amount of real, physical memory. You started allocating from the end of your fixed-size data region, and stopped when you ran out. Now consider a system in which the data region is not fixed size. In fact, you can have any number of things ("objects") mapped at arbitrary places in your address space. You can dynamically map new ones, extend the size of or unmap old ones, shrink them, relocate them, etc. Now, how would you implement a call (like malloc()) that returns some heap storage for you to use? You would just pick some hole in the address space that's big enough, map a temporary object there, and return a pointer to it. Unfortunately, we couldn't do that. There are lots of programs out there that don't just use malloc() to allocate space, they make assumptions about the internal workings of malloc(). I claim that this is a Bad Thing. They assume, for example, that they can continue to use free()d space until the next malloc(). So, we have to reserve some pool of storage just for malloc(), and not let any other clients of the mapping system (like the file I/O system) use that space. Now consider sbrk(). Note that it doesn't just return storage space; it makes certain guarantees about that space. For example, it guarantees that the next time you call sbrk(), you will get a piece of storage contiguous with the last piece you got. And when you free some storage, then allocate more, you get back the same piece you just freed. Programs depend on this behavior. We aren't at liberty to change those programs, because some of them were written by customers. This means that any space you will ever want to allocate with sbrk() has to be pre-allocated at the time the program is started (not the actual storage, but at least the address space). In AT&T and Berkeley Unix, this is no problem, because address space is allocated statically at the time your program is loaded. The text, data, and bss sizes are all fixed. Nothing more ever gets mapped in once the program is running. But in the Domain system, things are much more dynamic. Things are popping in and out of your address space all the time. So we need some way to reserve space for sbrk(). Hence, set_sbrk_size(). One way to fix this would be to give up the advantages of the dynamic address space allocation. This would mean, for example, no type managers in user space. No NFS without putting it in the kernel. No user defined types. Just like Unix. Another way to fix it, and the approach we took, is to re-arrange the address space. Put text at the bottom, then data, then bss, just like unix. Put the stack at the top and let it grow down towards bss. Go through various gyrations to try to keep sbrk() separate from the other users of the address space. This reduces the generality of the system, but it may be worth it if it eliminates the dreaded set_sbrk_size() (we hate it as much as you do). I'm not sure whether you really care about the implementation details. The bottom line is that set_sbrk_size has gone away (actually, it's a no-op) in sr9.5. But now I want my program to "fork()". Yeah, real tough code like: if (pid = fork()){ ... /* more real stuff */ and the "fork()" fails. Good old "perror()" says "I/O ERROR"; pretty informative huh. And I was a real nice guy and the heap is virtually empty at the point I "fork()", so it doesn't seem possible it barfed because it didn't have space to replicate the data areas. Remember that the semantics of sbrk() demand that you pre-allocate the space, regardless of whether you ever intend to use it. -------