Vous voudriez le drapeau MAP_ANONYMOUS pour mmap. Et le MAP_GROWSDOWN puisque vous voulez l'utiliser comme une pile.
Quelque chose comme :
void *stack = mmap(NULL,initial_stacksize,PROT_WRITE|PROT_READ,MAP_PRIVATE|MAP_GROWSDOWN|MAP_ANONYMOUS,-1,0);
Voir la page de manuel de mmap pour plus d'informations. Et rappelez-vous, le clone est un concept de bas niveau, que vous n'êtes pas censé utiliser à moins que vous n'ayez vraiment besoin de ce qu'il offre. Et il offre beaucoup de contrôle - comme définir sa propre pile - juste au cas où vous voudriez faire des trucs (comme avoir la pile accessible dans tous les processus associés). À moins que vous n'ayez de très bonnes raisons d'utiliser le clone, tenez-vous-en à fork ou pthreads.
Les piles ne sont pas, et ne peuvent jamais être, illimitées dans leur espace de croissance. Comme tout le reste, ils vivent dans l'espace d'adressage virtuel du processus, et la quantité dont ils peuvent croître est toujours limitée par la distance à la région de mémoire mappée adjacente.
Lorsque les gens parlent de la croissance dynamique de la pile, ils peuvent signifier l'une des deux choses suivantes :
- Les pages de la pile peuvent être des pages zéro copie sur écriture, qui ne reçoivent pas de copies privées tant que la première écriture n'est pas effectuée.
- Les parties inférieures de la région de la pile peuvent ne pas encore être réservées (et donc ne pas compter dans les frais de validation du processus, c'est-à-dire la quantité de mémoire physique/d'échange que le noyau a comptabilisée comme réservée pour le processus) jusqu'à ce qu'une page de garde soit atteinte , auquel cas le noyau valide davantage et déplace la page de garde, ou tue le processus s'il ne reste plus de mémoire à valider.
Essayer de se fier au MAP_GROWSDOWN
le drapeau n'est pas fiable et dangereux car il ne peut pas vous protéger contre mmap
créer un nouveau mappage juste à côté de votre pile, qui sera ensuite écrasé. (Voir http://lwn.net/Articles/294001/) Pour le thread principal, le noyau réserve automatiquement la taille de pile ulimit
équivalent à espace d'adressage (pas de mémoire ) sous la pile et empêche mmap
de l'attribuer. (Mais attention ! Certains noyaux corrigés par des fournisseurs défectueux désactivent ce comportement, ce qui entraîne une corruption aléatoire de la mémoire !) Pour les autres threads, vous devez simplement devoir mmap
toute la plage d'espace d'adressage dont le thread pourrait avoir besoin pour la pile lors de sa création. Il n'y a pas d'autre moyen. Vous pourriez faites-en la plupart initialement non inscriptibles/non lisibles, et changez cela en cas d'erreur, mais vous auriez alors besoin de gestionnaires de signaux et cette solution n'est pas acceptable dans une implémentation de threads POSIX car elle interférerait avec les gestionnaires de signaux de l'application. (Notez que, en tant qu'extension, le noyau pourrait offre spéciale MAP_
flags pour délivrer un signal différent au lieu de SIGSEGV
en cas d'accès illégal au mappage, puis l'implémentation des threads pourrait intercepter et agir sur ce signal. Mais Linux à l'heure actuelle n'a pas une telle fonctionnalité.)
Enfin, notez que le clone
syscall ne prend pas d'argument de pointeur de pile car il n'en a pas besoin. L'appel système doit être effectué à partir du code assembleur, car le wrapper de l'espace utilisateur est nécessaire pour modifier le pointeur de pile dans le thread "enfant" pour pointer vers la pile souhaitée et éviter d'écrire quoi que ce soit dans la pile du parent.
En fait, clone
prend un argument de pointeur de pile, car il n'est pas sûr d'attendre pour changer le pointeur de pile dans "l'enfant" après être revenu dans l'espace utilisateur. À moins que tous les signaux ne soient bloqués, un gestionnaire de signaux peut s'exécuter immédiatement sur la mauvaise pile, et sur certaines architectures, le pointeur de pile doit être valide et pointer vers une zone sûre pour écrire à tout moment.
Non seulement la modification du pointeur de pile est impossible à partir de C, mais vous ne pouvez pas non plus éviter la possibilité que le compilateur obstrue la pile du parent après l'appel système mais avant que le pointeur de pile ne soit modifié.