本文介绍了可以在Linux的用户空间中实现本机代码的抢占式多任务处理吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有可能在Linux上的用户空间的单个进程中实现本机代码的抢占式多任务处理. (也就是说,从外部暂停一些正在运行的本机代码,保存上下文,在不同的上下文中交换,然后恢复执行,所有这些操作都是由用户空间精心安排的,但使用可能会进入内核的调用.)我当时认为可以通过使用信号来完成此操作. SIGALRM*context()系列的处理程序,但事实证明整个*context()系列都是异步信号不安全,因此不能保证该方法有效.我确实找到了实现此想法的 gist ,显然,它确实在Linux上确实有效,至少有时,即使使用POSIX,也不需要工作.要点将其作为信号处理程序安装在SIGALRM上,该信号处理程序将进行多次*context()调用:

I'm wondering if it's possible to implement preemptive multitasking of native code within a single process in user space on Linux. (That is, externally pause some running native code, save the context, swap in a different context, and resume execution, all orchestrated by user space but using calls that may enter the kernel.) I was thinking this could be done using a signal handler for SIGALRM, and the *context() family but it turns out that the entire *context() family is async-signal-unsafe so that approach isn't guaranteed to work. I did find a gist that implements this idea so apparently it does happen to work on Linux, at least sometimes, even though by POSIX it's not required to work. The gist installs this as a signal handler on SIGALRM, which makes several *context() calls:

void
timer_interrupt(int j, siginfo_t *si, void *old_context)
{
    /* Create new scheduler context */
    getcontext(&signal_context);
    signal_context.uc_stack.ss_sp = signal_stack;
    signal_context.uc_stack.ss_size = STACKSIZE;
    signal_context.uc_stack.ss_flags = 0;
    sigemptyset(&signal_context.uc_sigmask);
    makecontext(&signal_context, scheduler, 1);

    /* save running thread, jump to scheduler */
    swapcontext(cur_context,&signal_context);
}

Linux是否提供任何保证使此方法正确的保证?有没有办法使这个正确?有完全不同的方法可以正确地做到这一点吗?

Does Linux offer any guarantee that makes this approach correct? Is there a way to make this correct? Is there a totally different way to do this correctly?

(通过在用户空间中实现",我并不是说我们永远不会进入内核.我的意思是与内核实现的抢先式多任务处理形成对比.)

(By "implement in user space" I don't mean that we never enter the kernel. I mean to contrast with the preemptive multitasking implemented by the kernel.)

推荐答案

您不能可靠地更改信号处理程序中的上下文. (如果您是通过某个信号处理程序执行此操作的,则它通常会在实践中正常运行,但并非总是如此,因此它是未定义的行为).

You cannot reliably change contexts inside signal handlers. (if you did that from some signal handler, it would usually work in practice, but not always, hence it is undefined behavior).

您可以设置一些volatile sig_atomic_t标志(有关 sig_atomic_t )在信号处理程序中(请参见 signal(7)信号安全(7) sigreturn(2) ...)并检查该标志定期(例如,至少每几毫秒一次),例如在大多数调用之前,或者在您的事件循环(如果有的话,等等),因此它成为合作用户土地调度.

You could set some volatile sig_atomic_t flag (read about sig_atomic_t) in a signal handler (see signal(7), signal-safety(7), sigreturn(2) ...) and check that flag regularly (e.g. at least once every few milliseconds) in your code, for example before most calls, or inside your event loop if you have one, etc... So it becomes cooperative user-land scheduling.

如果您可以更改代码,例如当您设计一些发出C代码的编译器时(常见做法),或者如果您破解了C编译器以发出代码这样的测试.然后,您将更改代码生成器,有时会在生成的代码中发出这样的测试.

It is easier to do if you can change the code, e.g. when you design some compiler which emits C code (a common practice), or if you hack your C compiler to emit such tests. Then you'll change your code generator to sometimes emit such a test in the generated code.

您可能要禁止阻止系统调用,并用替换它们非阻塞变体或包装.另请参见投票(2),等.

You may want to forbid blocking system calls and replace them with non-blocking variants or wrappers. See also poll(2), fcntl(2) with F_SETFL and O_NONBLOCK, etc...

您可能希望代码生成器避免大型调用栈,例如就像GCC的-fsplit-stack 仪器选项一样(了解拆分堆栈(在GCC中).

You may want the code generator to avoid large call stacks, e.g. like GCC's -fsplit-stack instrumentation option does (read about splitstacks in GCC).

如果生成(或编写一些)汇编程序,则可以使用这种技巧. AFAIK Go编译器的goroutine使用类似的东西.研究您的 ABI ,例如来自此处.

And if you generate (or write some) assembler, you can use such tricks. AFAIK the Go compiler uses something similar for its goroutines. Study your ABI, e.g. from here.

但是,最好使用内核启动的抢占式调度(并且在Linux上,进程或内核任务之间仍会发生这种抢占式调度,请参见克隆(2)).

However, kernel initiated preemptive scheduling is preferable (and on Linux will still happen between processes or kernel tasks, see clone(2)).

PS.如果您喜欢使用类似技巧的垃圾收集技术,请查看 MPS MTA上的钱(例如进入鸡计划).

PS. If garbage collection techniques using similar tricks interest you, look into MPS and Cheney on the MTA (e.g. into Chicken Scheme).

这篇关于可以在Linux的用户空间中实现本机代码的抢占式多任务处理吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 05:34