O mecanismo exato é fornecido aqui, no Linux: ao lidar com uma falha de página em mapeamentos anônimos, você verifica se é uma "alocação crescente" que você deve expandir como uma pilha. Se o registro da área da VM disser que você deveria, ajuste o endereço de início para expandir a pilha.
Quando ocorre uma falha na página, dependendo do endereço, ela pode ser reparada (e a falha anulada) via expansão da pilha. Esse comportamento "crescente em caso de falha" da memória virtual pode ser solicitado por programas arbitrários do usuário, com o MAP_GROWSDOWN
sinalizador sendo passado para o mmap
syscall.
Você também pode mexer com esse mecanismo em um programa do usuário:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
long page_size = sysconf(_SC_PAGE_SIZE);
void *mem = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_GROWSDOWN|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if (MAP_FAILED == mem) {
perror("failed to create growsdown mapping");
return EXIT_FAILURE;
}
volatile char *tos = (char *) mem + page_size;
int i;
for (i = 1; i < 10 * page_size; ++i)
tos[-i] = 42;
fprintf(stderr, "inspect mappping for originally page-sized %p in /proc... press any key to continue...\n", mem);
(void) getchar();
if (munmap(mem, page_size))
perror("failed munmap");
return EXIT_SUCCESS;
}
Quando solicitado, você encontra o pid do programa (via ps
) e /proc/$THAT_PID/maps
veja como a área original cresceu.
ulimit -s
).