| Home | Libraries | People | FAQ | More

## Stack allocation

A `fiber` uses internally an execution_context which manages a set of registers and a stack. The memory used by the stack is allocated/deallocated via a stack_allocator which is required to model a stack-allocator concept.

A stack_allocator can be passed to `fiber::fiber()` or to `fibers::async()`.

#### stack-allocator concept

A stack_allocator must satisfy the stack-allocator concept requirements shown in the following table, in which `a` is an object of a stack_allocator type, `sctx` is a `stack_context`, and `size` is a `std::size_t`:

expression | return type | notes
--- | --- | ---
`a(size)` |  | creates a stack allocator
`a.allocate()` | `stack_context` | creates a stack
`a.deallocate( sctx)` | `void` | deallocates the stack created by `a.allocate()`

| Important
The implementation of `allocate()` might include logic to protect against exceeding the context's available stack size rather than leaving it as undefined behaviour.

| Important
Calling `deallocate()` with a `stack_context` not obtained from `allocate()` results in undefined behaviour.

| Note
The memory for the stack is not required to be aligned; alignment takes place inside execution_context.

See also Boost.Context stack allocation. In particular, `traits_type` methods are as described for `boost::context::stack_traits`.

##### Class `protected_fixedsize_stack`

Boost.Fiber provides the class `protected_fixedsize_stack` which models the stack-allocator concept. It appends a guard page at the end of each stack to protect against exceeding the stack. If the guard page is accessed (read or write operation) a segmentation fault/access violation is generated by the operating system.

| Important
Using `protected_fixedsize_stack` is expensive. Launching a new fiber with a stack of this type incurs the overhead of setting the memory protection; once allocated, this stack is just as efficient to use as `fixedsize_stack`.

| Note
The appended `guard page` is not mapped to physical memory, only virtual addresses are used.

    #include <boost/fiber/protected_fixedsize.hpp>

    namespace boost {
    namespace fibers {

    struct protected_fixedsize {
        protected_fixesize(std::size_t size = traits_type::default_size());

        stack_context allocate();

        void deallocate( stack_context &);
    }

    }}

##### Member function `allocate`()

    stack_context allocate();

Preconditions:

  `traits_type::minimum_size() <= size` and `traits_type::is_unbounded() || ( size <= traits_type::maximum_size() )`.

Effects:

  Allocates memory of at least `size` bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is the highest/lowest address of the stack.

##### Member function `deallocate`()

    void deallocate( stack_context & sctx);

Preconditions:

  `sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and `traits_type::is_unbounded() || ( sctx.size <= traits_type::maximum_size() )`.

Effects:

  Deallocates the stack space.

##### Class `pooled_fixedsize_stack`

Boost.Fiber provides the class `pooled_fixedsize_stack` which models the stack-allocator concept. In contrast to `protected_fixedsize_stack` it does not append a guard page at the end of each stack. The memory is managed internally by `boost::pool<>`.

    #include <boost/fiber/pooled_fixedsize_stack.hpp>

    namespace boost {
    namespace fibers {

    struct pooled_fixedsize_stack {
        pooled_fixedsize_stack(std::size_t stack_size = traits_type::default_size(), std::size_t next_size = 32, std::size_t max_size = 0);

        stack_context allocate();

        void deallocate( stack_context &);
    }

    }}

##### Constructor

    pooled_fixedsize_stack(std::size_t stack_size, std::size_t next_size, std::size_t max_size);

Preconditions:

  `traits_type::is_unbounded() || ( traits_type::maximum_size() >= stack_size)` and `0 < next_size`.

Effects:

  Allocates memory of at least `stack_size` bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is the highest/lowest address of the stack. Argument `next_size` determines the number of stacks to request from the system the first time that `*this` needs to allocate system memory. The third argument `max_size` controls how much memory might be allocated for stacks — a value of zero means no upper limit.

##### Member function `allocate`()

    stack_context allocate();

Preconditions:

  `traits_type::is_unbounded() || ( traits_type::maximum_size() >= stack_size)`.

Effects:

  Allocates memory of at least `stack_size` bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is the highest/lowest address of the stack.

##### Member function `deallocate`()

    void deallocate( stack_context & sctx);

Preconditions:

  `sctx.sp` is valid, `traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size)`.

Effects:

  Deallocates the stack space.

| Note
This stack allocator is not thread safe.

##### Class `fixedsize_stack`

Boost.Fiber provides the class `fixedsize_stack` which models the stack-allocator concept. In contrast to `protected_fixedsize_stack` it does not append a guard page at the end of each stack. The memory is simply managed by `std::malloc()` and `std::free()`.

    #include <boost/context/fixedsize_stack.hpp>

    namespace boost {
    namespace fibers {

    struct fixedsize_stack {
        fixedsize_stack(std::size_t size = traits_type::default_size());

        stack_context allocate();

        void deallocate( stack_context &);
    }

    }}

##### Member function `allocate`()

    stack_context allocate();

Preconditions:

  `traits_type::minimum_size() <= size` and `traits_type::is_unbounded() || ( traits_type::maximum_size() >= size)`.

Effects:

  Allocates memory of at least `size` bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is the highest/lowest address of the stack.

##### Member function `deallocate`()

    void deallocate( stack_context & sctx);

Preconditions:

  `sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and `traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size)`.

Effects:

  Deallocates the stack space.

##### Class `segmented_stack`

Boost.Fiber supports usage of a `segmented_stack`, i.e. the stack grows on demand. The fiber is created with a minimal stack size which will be increased as required. Class `segmented_stack` models the stack-allocator concept. In contrast to `protected_fixedsize_stack` and `fixedsize_stack` it creates a stack which grows on demand.

| Note
Segmented stacks are currently only supported by gcc from version 4.7 and clang from version 3.4 onwards. In order to use a `segmented_stack` Boost.Fiber must be built with property `segmented-stacks`, e.g. toolset=gcc segmented-stacks=on at b2/bjam command line.

    #include <boost/fiber/segmented_stack.hpp>

    namespace boost {
    namespace fibers {

    struct segmented_stack {
        segmented_stack(std::size_t stack_size = traits_type::default_size());

        stack_context allocate();

        void deallocate( stack_context &);
    }

    }}

##### Member function `allocate`()

    stack_context allocate();

Preconditions:

  `traits_type::minimum_size() <= size` and `traits_type::is_unbounded() || ( traits_type::maximum_size() >= size)`.

Effects:

  Allocates memory of at least `size` bytes and stores a pointer to the stack and its actual size in `sctx`. Depending on the architecture (the stack grows downwards/upwards) the stored address is the highest/lowest address of the stack.

##### Member function `deallocate`()

    void deallocate( stack_context & sctx);

Preconditions:

  `sctx.sp` is valid, `traits_type::minimum_size() <= sctx.size` and `traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size)`.

Effects:

  Deallocates the stack space.

| Note
If the library is compiled for segmented stacks, `segmented_stack` is the only available stack allocator.