问题描述
Linux上的clone()系统调用采用指向堆栈的参数,供新创建的线程使用.这样做的显而易见的方法是简单地分配一些空间并传递该空间,但随后必须确保已分配了该线程将使用的尽可能多的堆栈空间(很难预测).
The clone() system call on Linux takes a parameter pointing to the stack for the new created thread to use. The obvious way to do this is to simply malloc some space and pass that, but then you have to be sure you've malloc'd as much stack space as that thread will ever use (hard to predict).
我记得在使用pthreads时不必这样做,所以我很好奇它做了什么.我遇到了此站点,其中解释道:"Linux pthreads实现使用的最佳解决方案是使用mmap分配内存,并使用标志指定使用时分配的内存区域,这样,将根据需要为堆栈分配内存,如果系统无法分配其他内存,则会发生分段冲突记忆."
I remembered that when using pthreads I didn't have to do this, so I was curious what it did instead. I came across this site which explains, "The best solution, used by the Linux pthreads implementation, is to use mmap to allocate memory, with flags specifying a region of memory which is allocated as it is used. This way, memory is allocated for the stack as it is needed, and a segmentation violation will occur if the system is unable to allocate additional memory."
我听说过mmap的唯一上下文是将文件映射到内存,并且确实要读取mmap手册页,它需要一个文件描述符.如何将其用于分配动态长度的堆栈以提供给clone()?该网站只是疯狂的吗? ;)
The only context I've ever heard mmap used in is for mapping files into memory, and indeed reading the mmap man page it takes a file descriptor. How can this be used for allocating a stack of dynamic length to give to clone()? Is that site just crazy? ;)
在任何一种情况下,内核是否都不需要知道如何为新堆栈查找空闲的内存束,因为在用户启动新进程时,它总是必须做的事情吗?如果内核已经可以弄清堆栈指针,为什么还要首先指定堆栈指针呢?
In either case, doesn't the kernel need to know how to find a free bunch of memory for a new stack anyway, since that's something it has to do all the time as the user launches new processes? Why does a stack pointer even need to be specified in the first place if the kernel can already figure this out?
推荐答案
约瑟夫,回答您的最后一个问题:
Joseph, in answer to your last question:
当用户创建一个正常"的新进程时,这是由fork()完成的.在这种情况下,内核根本不必担心创建新堆栈,因为新过程是旧堆栈的完全复制,一直到堆栈.
When a user creates a "normal" new process, that's done by fork(). In this case, the kernel doesn't have to worry about creating a new stack at all, because the new process is a complete duplicate of the old one, right down to the stack.
如果用户使用exec()替换了当前正在运行的进程,则内核确实需要创建一个新的堆栈-但在这种情况下,这很容易,因为它是从空白开始的. exec()擦除进程的内存空间并重新初始化它,因此内核会说在exec()之后,堆栈始终位于此处".
If the user replaces the currently running process using exec(), then the kernel does need to create a new stack - but in this case that's easy, because it gets to start from a blank slate. exec() wipes out the memory space of the process and reinitialises it, so the kernel gets to say "after exec(), the stack always lives HERE".
但是,如果我们使用clone(),则可以说新进程将与旧进程(CLONE_VM)共享一个内存空间.在这种情况下,内核无法像在调用进程中那样离开堆栈(就像fork()一样),因为那样我们的两个进程就会踩到彼此的堆栈.内核也不能只是将其放在默认位置(就像exec()一样),因为该位置已经在此内存空间中占用了.唯一的解决方案是允许调用过程为其找到位置.
If, however, we use clone(), then we can say that the new process will share a memory space with the old process (CLONE_VM). In this situation, the kernel can't leave the stack as it was in the calling process (like fork() does), because then our two processes would be stomping on each other's stack. The kernel also can't just put it in a default location (like exec()) does, because that location is already taken in this memory space. The only solution is to allow the calling process to find a place for it, which is what it does.
这篇关于如何为Linux上的clone()系统调用映射堆栈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!