您是否熟悉流程检查点重新启动?特别是CRIU?在我看来,它可能为您提供了一个简单的选择。
我想获得一个正在运行的Linux进程的核心转储,而不会中断该进程[并且]以某种方式获得其他原始线程的相关数据。
忘记不要中断该过程。如果考虑一下,核心转储 必须
在转储期间中断该进程;因此,您的真正目标必须是最大程度地减少这种中断的时间。您最初的使用想法
fork()确实会中断该过程,只是在很短的时间内就会中断。
- 包含所有线程堆栈的内存在分支过程中是否仍然可用并可以访问?
否。
fork()唯一保留执行实际调用的线程,其余线程的堆栈丢失。
假设CRIU不适合,这是我要使用的过程:
- 有一个父进程,该进程会在子进程停止时生成子进程的核心转储。(请注意,可能会生成多个连续的停止事件;只有第一个停止事件才发生,直到下一个继续事件为止。)
您可以使用来检测停止/继续事件
waitpid(child,,WUNTRACED|WCONTINUED)。
- 可选:用于
sched_setaffinity()
将进程限制为单个CPU,并且sched_setscheduler()
(也许sched_setparam()
)将进程优先级降低为IDLE
。
您可以从父进程执行此操作,该父进程仅在有效组和允许组中都具有该
CAP_SYS_NICE功能(
setcap 'cap_sys_nice=pe'parent-binary如果您像大多数当前Linux发行版一样启用了文件系统功能,则可以将其提供给父二进制文件使用)。
目的是在一个线程确定要快照/转储的时间到所有线程停止之间的时间最小化其他线程的进度。我尚未测试过更改生效要花多长时间-
当然,更改最早最早会在当前时间片的结尾发生。因此,此步骤可能应该事先完成。
就个人而言,我不会打扰。在我的四核计算机上,
SIGSTOP仅下面的语句在线程之间会产生与互斥量或信号量相似的延迟,因此我认为没有必要为更好的同步而努力。
- 当子进程中的某个线程决定要对其自身进行快照时,它将向
SIGSTOP
自身发送一个(通过kill(getpid(), SIGSTOP)
)。这将停止进程中的所有线程。
父进程将收到有关子进程已停止的通知。它将首先检查
/proc/PID/task/以获取子进程的每个线程的TID(以及
/proc/PID/task/TID/其他信息的伪文件),然后使用附加到每个TID
ptrace(PTRACE_ATTACH, TID)。显然,
ptrace(PTRACE_GETREGS, TID,...)将获得每个线程的寄存器状态,这些状态可以与
/proc/PID/task/TID/smaps和一起使用
/proc/PID/task/TID/mem以获取每个线程的堆栈跟踪以及您感兴趣的任何其他信息。(例如,您可以创建一个与调试器兼容的内核每个线程的文件。)
当父进程完成转储操作时,它将让子进程继续。我相信您需要发送一个单独的
SIGCONT信号来让整个子进程继续运行,而不是仅仅依靠
ptrace(PTRACE_CONT,TID),但是我还没有检查这一点。请对此进行验证。
我确实相信上述内容将使进程停止中的线程之间的挂钟时间产生最小的延迟。在Xubuntu上的AMD Athlon II X4
640和3.8.0-29-Generic内核上进行的快速测试表明,紧紧的循环会增加其他线程中的volatile变量,只会使计数器增加几千,这取决于线程数(太多了)我做了一些更具体的测试后发现噪音)。
将进程限制为单个CPU,甚至限制为IDLE优先级,将大大减少该延迟。
CAP_SYS_NICE功能使父级不仅可以降低子级进程的优先级,还可以将优先级提高到原始级别。文件系统功能意味着父进程甚至不必设置setuid,
CAP_SYS_NICE就足够了。(我认为在父程序中进行一些良好的检查之后,将其安装在大学计算机中就足够安全了,在大学计算机中,学生非常积极地寻找有趣的方式来利用已安装的程序。)
可以创建提供增强功能的内核补丁(或模块),该补丁
kill(getpid(),SIGSTOP)还尝试从运行中的CPU中启动其他线程,从而尝试使线程停止之间的延迟更小。就个人而言,我不会打扰。即使没有CPU
/优先级操纵,我也可以获得足够的同步(线程停止之间的足够小的延迟)。
您是否需要一些示例代码来说明我的上述想法?



