Stack sizes – Creating Our Own Fibers

Note

The actual addresses you get will be different every time you run the program.

In other words, the values 240, 205, 252, 56, 67, 86, 0, 0 represent the pointer to our hello() function written as u8 values.

Endianness

An interesting side note here is that the order the CPU writes an u64 as a set of 8 u8 bytes is dependent on its endianness. In other words, a CPU can write our pointer address as 240, 205, 252, 56, 67, 86, 0, 0 if it’s little-endian or 0, 0, 86, 67, 56, 252, 205, 240 if it’s big-endian. Think of it like how Hebrew, Arabic, and Persian languages read and write from right to left, while Latin, Greek, and Indic languages read and write from left to right. It doesn’t really matter as long as you know it in advance, and the results will be the same.

The x86-64 architecture uses a little-endian format, so if you try to parse the data manually, you’ll have to bear this in mind.

As we write more complex functions, our extremely small 48-byte stack will soon run out of space. You see, as we run the functions we write in Rust, the CPU will now push and pop values on our new stack to execute our program and it’s left to the programmer to make sure they don’t overflow the stack. This brings us to our next topic: stack sizes.

Stack sizes

We touched upon this topic earlier in Chapter 2, but now that we’ve created our own stack and made our CPU jump over to it, you might get a better sense of the issue. One of the advantages of creating our own green threads is that we can freely choose how much space we reserve for each stack.

When you start a process in most modern operating systems, the standard stack size is normally 8 MB, but it can be configured differently. This is enough for most programs, but it’s up to the programmer to make sure we don’t use more than we have. This is the cause of the dreaded stack overflow that most of us have experienced.

However, when we can control the stacks ourselves, we can choose the size we want. 8 MB for each task is way more than we need when running simple functions in a web server, for example, so by reducing the stack size, we can have millions of fibers/green threads running on a machine. We run out of memory a lot sooner using stacks provided by the operating system.

Anyway, we need to consider how to handle the stack size, and most production systems such as Boost.Coroutine or the one you find in Go will use either segmented stacks or growable stacks. We will make this simple for ourselves and use a fixed stack size going forward.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Post