Re: tentitive complete patch for MAP_GUARDED available

2000-02-18 Thread Matthew Dillon

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

2000-02-18 Thread Jason Evans

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

2000-02-18 Thread Alan Cox

 ...
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

2000-02-18 Thread Matthew Dillon


:
: ...
: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

2000-02-18 Thread Matthew Dillon

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

2000-02-18 Thread Matthew Dillon

: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

2000-02-18 Thread Daniel Eischen

 * 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

2000-02-18 Thread Matthew Dillon


: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

2000-02-18 Thread Daniel Eischen

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