gpt4 book ai didi

linux - 如何在 Linux 上为 clone() 系统调用映射堆栈?

转载 作者:IT王子 更新时间:2023-10-29 00:05:53 27 4
gpt4 key购买 nike

Linux 上的 clone() 系统调用带有一个指向堆栈的参数,供新创建的线程使用。这样做的明显方法是简单地 malloc 一些空间并传递它,但是你必须确保你已经 malloc 了与该线程将使用的一样多的堆栈空间(很难预测)。

我记得在使用 pthreads 时我不必这样做,所以我很好奇它做了什么。我遇到了this site这解释说,“Linux pthreads 实现使用的最佳解决方案是使用 mmap 分配内存,并使用标志指定内存区域,该区域在使用时分配。这样,内存就按原样分配给堆栈需要,如果系统无法分配额外的内存,就会发生分段冲突。”

我听说过使用 mmap 的唯一上下文是将文件映射到内存中,实际上阅读 mmap 手册页它需要一个文件描述符。这如何用于分配动态长度的堆栈以提供给 clone()?那个网站疯了吗? ;)

在任何一种情况下,内核不需要知道如何为新堆栈找到空闲内存,因为这是它在用户启动新进程时必须一直做的事情?如果内核已经知道了,为什么还需要首先指定堆栈指针?

最佳答案

堆栈的增长空间不是,也永远不会是无限的。与其他所有内容一样,它们存在于进程的虚拟地址空间中,并且它们可以增长的数量始终受限于到相邻映射内存区域的距离。

当人们谈论堆栈动态增长时,他们可能指的是以下两种情况之一:

  • 堆栈的页面可能是写时复制零页,在执行第一次写入之前不会创建私有(private)副本。
  • 堆栈区域的较低部分可能尚未保留(因此不计入进程的提交费用,即内核为进程保留的物理内存/交换量),直到保护页被命中,在这种情况下,内核会提交更多内容并移动保护页,或者如果没有剩余内存可提交则终止进程。

尝试依赖 MAP_GROWSDOWN 标志是不可靠且危险的,因为它无法保护您免受 mmap 创建一个与您的位置相邻的新映射堆栈,然后将被破坏。 (参见 http://lwn.net/Articles/294001/)对于主线程,内核自动保留堆栈大小 ulimit地址空间(不是内存)如下堆栈并防止 mmap 分配它。 (但要注意!一些损坏的供应商修补内核会禁用此行为,从而导致随机内存损坏!)对于其他线程,您只需必须 mmap 线程的整个地址空间范围创建它时可能需要堆栈。没有别的办法。您可以使它的大部分最初不可写/不可读,并在出现故障时更改它,但是您需要信号处理程序并且此解决方案在 POSIX 线程实现中是 Not Acceptable ,因为它会干扰应用程序的信号处理程序。 (请注意,作为扩展,内核可以提供特殊的 MAP_ 标志以在非法访问映射时传递不同的信号而不是 SIGSEGV ,然后线程实现可以捕捉到这个信号并对其进行操作。但是Linux目前没有这样的功能。)

最后,请注意 clone 系统调用不需要堆栈指针参数,因为它不需要它。系统调用必须从汇编代码执行,因为用户空间包装器需要更改“子”线程中的堆栈指针以指向所需堆栈,并避免向父堆栈写入任何内容。

实际上,clone 确实接受了一个堆栈指针参数,因为在返回到用户空间后等待更改“子”中的堆栈指针是不安全的。除非信号全部被阻塞,否则信号处理程序可能会立即在错误的堆栈上运行,并且在某些体系结构上,堆栈指针必须有效并始终指向一个安全区域以进行写入。

不仅无法从 C 修改堆栈指针,而且您也无法避免编译器在系统调用之后但在更改堆栈指针之前破坏父级堆栈的可能性。

关于linux - 如何在 Linux 上为 clone() 系统调用映射堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1083172/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com