Re: tentitive complete patch for MAP_GUARDED available
Ok, this time for sure... version 3 of the MAP_GUARDED patch is out. http://www.backplane.com/FreeBSD4/ http://www.backplane.com/FreeBSD4/guard-3.diff http://www.backplane.com/FreeBSD4/guard3.c MAP_GUARDED mmap(addr/NULL, len, prot, MAP_GUARDED, fd, offset) The offset field specifies the number of bytes at the base of the returned map which are guarded and should be a multiple of the system page size. Pages at the end of the map are not guarded (any more). MAP_STACK Works as per normal except that the per-process stack resource limit applies to each mmap() separately. MAP_GUARDED|MAP_STACK Useful combination to place guard page(s) at the beginning of a thread stack. Also in this patch set I optimized vm_map_entry creation during normal stack growth operations. Normally the system tries to chunk vm_map_entry allocation for stacks by SGROWSIZ, which is typically 128K. But now the vm_map_entry_insert() optimization is able to optimize standard stack growth, which means that the actual vm_map_entry creation is governed by the more generous vm.map_entry_blk_opt value (512K by default). I like this implementation a lot better. By removing the guard pages at the end of the map MAP_GUARDED|MAP_STACK operation is much, much more intuitive. You don't have to do a blessed thing to the threading code except change MAP_STACK to MAP_STACK|MAP_GUARDED, and bump up the size of the mmap() allocation to include what used to be the skipped 'dead' page. -Matt Matthew Dillon [EMAIL PROTECTED] To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
On Fri, Feb 18, 2000 at 11:05:31AM -0800, Matthew Dillon wrote: I also think that a single guard page at the base of the stack may be insufficient for some applications. I'm considering adding yet another field to vm_map_entry 'vm_pindex_t guard_pages' which allows the number of guard pages to be specified (we can use mmap()'s offset argument to pass the parameter). In general, a given number of guard pages is insufficient for some (perhaps non-existent) applications. The basic idea is to catch typical stack overflow. Trying to always catch stack overflow is not practical. Since this is a heuristic error detection technique, I'm not sure how much work/complexity it's worth to paramaterize the number of guard pages for each mapping. Jason To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
... Resource limits are still an issue. It turns out that the MAP_STACK code does not deal with the stack resource limit well at all -- sometimes it catches it, sometimes it doesn't. In what sense? My recollection is that resource limits are enforced on the "regular" process stack but not (except perhaps by accident of placement) on other stacks, such as those created by pthreads. At a higher level, it's not been obvious to me how the resource limit on stack size should be interpreted in a multithreaded program. In other words, I don't see one interpretation as obviously best, much less correct. At least three possibilies are: 1. It represents the maximum size of the "legacy" process stack and nothing else, which is what the code currently implements. (pthreads stacks are bounded by other means.) 2. It represents the maximum size of each and every stack, whether it's the "legacy" process stack or for example a pthreads stack. 3. It represents the sum of the size of all of the stacks. There are problems/drawbacks to each and every possibility. So, in conclusion, I think the first order of business is to determine what semantics (1) there may be good precedent for and (2) that threads programmers are comfortable with. Alan To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
: : ... :Resource limits are still an issue. It turns out that the :MAP_STACK code does not deal with the stack resource limit :well at all -- sometimes it catches it, sometimes it doesn't. : :In what sense? My recollection is that resource limits are :enforced on the "regular" process stack but not (except :perhaps by accident of placement) on other stacks, such as :those created by pthreads. It's because the threads library is allocating the thread stacks *ON* the user stack. Stacks created with MAP_STACK, including the user stack, are not entirely reserved at creation time. So if you have an 8m stack resource limit your user stack is actually only as large (growing from the top down) as the lowest address you have yet allocated from it. The kernel can't tell the difference between the default user stack and new MAP_STACK stacks the threads library allocates when they fall within the resource limit. On the otherhand if you mmap a stack well outside the resource limit, the kernel doesn't care either. It's only when you try to 'grow' a stack (any MAP_STACK stack) that is sitting within the resource such that it would grow beyond the resource limit that an error is generated. :At a higher level, it's not been obvious to me how the resource limit :on stack size should be interpreted in a multithreaded program. In :other words, I don't see one interpretation as obviously best, much :less correct. At least three possibilies are: : :1. It represents the maximum size of the "legacy" process stack :and nothing else, which is what the code currently implements. :(pthreads stacks are bounded by other means.) : :2. It represents the maximum size of each and every stack, whether :it's the "legacy" process stack or for example a pthreads stack. : :3. It represents the sum of the size of all of the stacks. : :There are problems/drawbacks to each and every possibility. : :So, in conclusion, I think the first order of business is :to determine what semantics (1) there may be good precedent :for and (2) that threads programmers are comfortable with. : :Alan I think the issue is plain and simply that our implementation is broken. I think the resource limit should only apply to the main user stack and not to any old MAP_STACK one happens to mmap(). Thread stacks should not in any way fall under the system stack resource. It just doesn't apply. I also think that a single guard page at the base of the stack may be insufficient for some applications. I'm considering adding yet another field to vm_map_entry 'vm_pindex_t guard_pages' which allows the number of guard pages to be specified (we can use mmap()'s offset argument to pass the parameter). I also think we should get rid of the avail_ssize field in vm_map_entry and instead simply have a flag for the main user stack's vm_map_entry that allows it to grow downward to be sized up to the resource limit in size. Should the resource limit apply to any MAP_STACK mapping (separately and independantly)? Yes, I think so. It shouldn't matter at all for threads but I can see using MAP_STACK mmaping's to dynamically load programs and run them (rather then fork/exec), in certain cases. What do you think? The above changes would be easy to add, I've already done the hard work of optimizing the VM system. -Matt Matthew Dillon [EMAIL PROTECTED] To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
Ok, I just finished making the modifications, essentially rewriting vm_map_growstack() and vm_map_stack(). http://www.backplane.com/FreeBSD4/ http://www.backplane.com/FreeBSD4/guard-3.diff http://www.backplane.com/FreeBSD4/guard3.c Here are the proposed semantics: * When you mmap() with MAP_STACK, the stack you map is limited to the number of bytes specified in the mmap() AND ALSO limited by the process stack resource limit (on a per-mmap basis). That is, *EACH* MAP_STACK mmaping may utilize up to the process stack resource and no more, even if you mmap a larger area. This may be a little controversial but it's basically how the kernel allocates the default user stack -- it allocates the maximum kernel limit and assumes the stack will be limited by the stack resource. I think it could be useful for debugging, too. (Also, with MAP_STACK, a fixed address and an anonymous mmap is implied, and the mmap() will fail if the specified region already contains mappings). * When you mmap() with MAP_GUARDED, the offset field in the mmap() call specifies the number of guard pages at the beginning and end of the map. If you specify 0, you don't get any guard pages (which is kinda useless). Normally getpagesize() bytes is specified. An anonymous mmap is implied. * When you mmap() with MAP_GUARDED|MAP_STACK, you get a guarded stack. The system will not create a growable stack, though, it pre-reserves the space (but, of course, does not allocate physical pages for things you haven't touched). The new semantics use the offset field in the mmap to indicate the number of guard pages at the beginning and end of the map, in bytes, so the semantics of MAP_GUARDED mmap's has been changed somewhat. You nominally have to call it with an offset of getpagesize() to get the 'single guard page at beginning and end' behavior. So, to make the threads library use this you mmap MAP_STACK|MAP_GUARDED with an offset of getpagesize() (or more). -Matt To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
:Currently, the threads library only creates one guard page :at the top (or bottom depending on how you look at it) of :each threads stack (for stacks of default size). Thread :stacks are allocated in sequential zones, so they are always :placed on top of the previous threads stack, and thus already :have a guard page below the stack. : :Correct me if I'm wrong, but using MAP_STACK|MAP_GUARDED :would allocate one additional guard page for each threads :stack. : :DanE. Correct. At the moment MAP_GUARDED is a 'generic' guarding flag and makes no assumptions about the areas being adjoining. It doesn't cost us anything. -Matt Matthew Dillon [EMAIL PROTECTED] To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
* When you mmap() with MAP_GUARDED|MAP_STACK, you get a guarded stack. The system will not create a growable stack, though, it pre-reserves the space (but, of course, does not allocate physical pages for things you haven't touched). The new semantics use the offset field in the mmap to indicate the number of guard pages at the beginning and end of the map, in bytes, so the semantics of MAP_GUARDED mmap's has been changed somewhat. You nominally have to call it with an offset of getpagesize() to get the 'single guard page at beginning and end' behavior. So, to make the threads library use this you mmap MAP_STACK|MAP_GUARDED with an offset of getpagesize() (or more). Currently, the threads library only creates one guard page at the top (or bottom depending on how you look at it) of each threads stack (for stacks of default size). Thread stacks are allocated in sequential zones, so they are always placed on top of the previous threads stack, and thus already have a guard page below the stack. Correct me if I'm wrong, but using MAP_STACK|MAP_GUARDED would allocate one additional guard page for each threads stack. DanE. To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
:Ok, I just finished making the modifications, essentially :rewriting vm_map_growstack() and vm_map_stack(). : : http://www.backplane.com/FreeBSD4/ : http://www.backplane.com/FreeBSD4/guard-3.diff : http://www.backplane.com/FreeBSD4/guard3.c Oops, withdrawn... I muffed it up. I'll get it up later today. -Matt To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message
Re: tentitive complete patch for MAP_GUARDED available
On Fri, 18 Feb 2000, Matthew Dillon wrote: :Currently, the threads library only creates one guard page :at the top (or bottom depending on how you look at it) of :each threads stack (for stacks of default size). Thread :stacks are allocated in sequential zones, so they are always :placed on top of the previous threads stack, and thus already :have a guard page below the stack. : :Correct me if I'm wrong, but using MAP_STACK|MAP_GUARDED :would allocate one additional guard page for each threads :stack. : :DanE. Correct. At the moment MAP_GUARDED is a 'generic' guarding flag and makes no assumptions about the areas being adjoining. It doesn't cost us anything. Any problem if we overlay a previously MAP_GUARDED page with another (to save an extra guard page)? Dan Eischen [EMAIL PROTECTED] To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message