在 pthreads 线程的堆栈中预先发生故障的最佳方法是什么?
我正在为嵌入式 Linux 系统中运行的实时程序编写代码。由于我们不会因页面错误而意外停止,这一点至关重要,因此我希望在堆栈中预先发生错误,以便保证我们使用的区域被 mlockall()
调用覆盖。
对于主线程来说这很简单;只需执行几个大的 alloca()
并确保每隔几页写入一次。这是可行的,因为在程序启动时,堆栈限制远大于我们需要的数量;我们最终准确地分配了预先故障的数量。
但是,对于 pthread 堆栈,它们也会使用 MAP_GROWSDOWN 进行分配吗?如果是这样,考虑到以下因素,预先对它们进行故障排除的最佳方法是什么:
- 我们不知道 libc 启动消耗了多少(已知)堆栈大小
- 我们不想为堆栈分配比所需更多的
内存我知道我可以使用 pthread_attr_setstack 传入手动分配的堆栈,但这会使线程后的清理工作变得复杂,因此如果可能的话,我宁愿避免这种情况。
因此,执行此预故障的最佳方法是什么?如果有一种简单的方法来找出堆栈的下限(就在保护页上方)就足够了;此时我可以简单地写入从那里到当前堆栈指针的每个页面。
请注意,可移植性不是一个问题;我们很高兴能有一个仅在 x86-32 和 Linux 下工作的解决方案。
I am writing code for a real-time program running in an embedded Linux system. As it is critical that we don't stall unpredictably on page faults, I would like to prefault in the stack so that the region that we use is guaranteed to be covered by a mlockall()
call.
For the main thread this is simple enough; simply do a few big alloca()
s and make sure to do a write every few pages. This works because at program startup, the stack limit is much larger than the amount we need; we end up allocating exactly how much we prefault in.
However, for pthread stacks, will they be allocated using MAP_GROWSDOWN
as well? If so, what's the best way to prefault them in, considering that:
- We don't know how much of the (known) stack size is consumed by libc startup
- We don't want to allocate more memory to the stack than is necessary
I'm aware that I can use pthread_attr_setstack
to pass in a manually-allocated stack, but this complicates cleaning up after the thread, and so I'd prefer to avoid this if possible.
As such, what's the best way to perform this prefaulting? It would be sufficient if there was an easy way to find out the lower bound of the stack (just above the guard page); at this point I could simply write to every page from there to the current stack pointer.
Note that portability is not a concern; we'd be happy to have a solution that works only under x86-32 and Linux.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您使用
pthread_attr_setstacksize
,您仍然可以自动分配已知大小。glibc nptl 在堆栈之间留下保护页,因此您还可以设置一个 SEGV 处理程序并简单地乱写,直到发生故障,然后 longjmp 退出循环。那就太丑了!
编辑:一种真正不可移植的方法是打开 /proc/self/maps 来查找您的堆栈!
If you use
pthread_attr_setstacksize
you can still have automatic allocation with a known size.glibc nptl leaves guard pages between the stacks, so you could also set a
SEGV
handler and simply scribble until you fault and thenlongjmp
out of the loop. That'd be ugly!Edit: A really nonportable way would be to open
/proc/self/maps
to find your stacks!是的。如果在pthread_create之前调用了mlockall(MCL_CURRENT | MCL_FUTURE),则启动线程时会发生线程堆栈页错误。之后,线程中访问堆栈时就不会再出现页面错误。
因此人们总是为新创建的线程设置合适的线程大小,以避免为将来的线程锁定太多内存。
看看:
https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
如果将线程堆栈大小更改为 7MB,您将看到:
初始计数:页面错误,主要:0(允许 >=0),次要:190(允许 >=0)
mlockall() 生成:页面错误,主要:0(允许 >=0),次要:393(允许 >=0)
malloc() 和 touch 生成:页面错误,主要:0(允许 >=0),次要:25633(允许 >=0)
第二个 malloc() 并使用生成的: Pagefaults, Major:0 (Allowed 0), Minor:0 (Allowed 0)
查看 ps -leyf 的输出,看到 RSS 现在约为 100 [MB]
按退出
我是一个 RT 线程,其堆栈在使用过程中不会生成页面错误,stacksize=7340032
由创建线程引起:页面错误,主要:0(允许>=0),次要:1797(允许>=0)
使用线程堆栈导致:页面错误,Major:0 (Allowed 0), Minor:0 (Allowed 0)
创建线程时发生 1797 个页面错误,大约 7MB。
-巴里
yes. if you have called mlockall(MCL_CURRENT | MCL_FUTURE) before pthread_create, page fault for thread stack will happen when starting the thread. and after that, there will be no page fault again while accessing stack in the thread.
so people always set the suitable thread size for the new created thread to avoid lock too much memory for the future coming threads.
take a look at:
https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
if you change the thread stack size to 7MB, you will see:
Initial count : Pagefaults, Major:0 (Allowed >=0), Minor:190 (Allowed >=0)
mlockall() generated : Pagefaults, Major:0 (Allowed >=0), Minor:393 (Allowed >=0)
malloc() and touch generated : Pagefaults, Major:0 (Allowed >=0), Minor:25633 (Allowed >=0)
2nd malloc() and use generated: Pagefaults, Major:0 (Allowed 0), Minor:0 (Allowed 0)
Look at the output of ps -leyf, and see that the RSS is now about 100 [MB]
Press to exit
I am an RT-thread with a stack that does not generate page-faults during use, stacksize=7340032
Caused by creating thread : Pagefaults, Major:0 (Allowed >=0), Minor:1797 (Allowed >=0)
Caused by using thread stack : Pagefaults, Major:0 (Allowed 0), Minor:0 (Allowed 0)
1797 page faults happen while creating thread, it is about 7MB.
-barry