The stack
thread attributes
int pthread_attr_setstack (pthread_attr_t *attr, void *addr, size_t ssize );
int pthread_attr_setstackaddr (pthread_attr_t *attr, void *addr);
int pthread_attr_setguardsize (pthread_attr_t *attr, size_t gsize);
int pthread_attr_setstacklazy (pthread_attr_t *attr, int lazystack);
int pthread_attr_setstackprealloc (pthread_attr_t * attr, size_t psize);
int pthread_attr_setstacksize (pthread_attr_t *attr, size_t ssize);
These functions all take the attribute structure as their first parameter; the other parameters are selected from the following:
- addr
- The address of the stack, if you're providing one.
- gsize
- The size of the
guard
area. - lazystack
- Indicates if the stack should be allocated on demand or up front from physical memory.
Note:In this release, lazy stack allocation is disabled, so setting this field has no effect.
- psize
- The amount of memory to preallocate for a thread's MAP_LAZY stack.
Note:In this release, lazy stack allocation is disabled, so setting this field has no effect.
- ssize
- The size of the stack.
The guard area is a memory area immediately after the stack that the thread can't write to.
If it does (meaning that the stack was about to overflow), the thread will
get hit with a SIGSEGV.
If the guardsize is 0, it means that there's no guard area.
This also implies that there's no stack overflow checking.
If the guardsize is nonzero, then it's set to at least the system-wide default guardsize
(which you can obtain with a call to
sysconf()
with the constant _SC_PAGESIZE).
Note that the guardsize will be at least as big as a page
(for example, 4 KB on an x86 processor).
Also, note that the guard page doesn't take up any physical memory—it's done
as a virtual address (MMU) trick.
The addr is the address of the stack, in case you're providing it.
You can set it to NULL meaning that the system will allocate (and will free!)
the stack for the thread.
The advantage of specifying a stack is that you can do postmortem stack depth analysis.
This is accomplished by allocating a stack area, filling it with a signature
(for example, the string STACK
repeated over and over), and letting the thread run.
When the thread has completed, you'd look at the stack area and see how far the thread had
scribbled over your signature, giving you the maximum depth of the stack used during this
particular run.
The ssize parameter specifies how big the stack is.
If you provide the stack in addr, then ssize should be the
size of that data area.
If you don't provide the stack in addr (meaning you passed a
NULL), then the ssize parameter tells the system how big a stack
it should allocate for you.
If you specify a 0 for ssize, the system will select the default
stack size for you.
Obviously, it's bad practice to specify a 0 for ssize and
specify a stack using addr—effectively you're saying Here's a pointer
to an object, and the object is some default size.
The problem is that there's no binding between the object size and the passed value.
Finally, the lazystack parameter indicates if the physical memory should be
allocated as required (use the value PTHREAD_STACK_LAZY) or all up front
(use the value PTHREAD_STACK_NOTLAZY).
The advantage of allocating the stack on demand
(as required) is that the thread won't
use up more physical memory than it absolutely has to.
The advantage of the all up front
method is that in a low-memory environment,
the thread won't mysteriously die some time during operation when it needs that extra
bit of stack and there isn't any memory left.
If you are using the latter method (i.e., PTHREAD_STACK_NOTLAZY),
you'll most likely want to set the actual size of the stack instead of accepting the default,
because the default is quite large.