Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何创建中断堆栈?_C_Stack_Interrupt - Fatal编程技术网

C 如何创建中断堆栈?

C 如何创建中断堆栈?,c,stack,interrupt,C,Stack,Interrupt,我希望我的中断服务例程使用不同的堆栈(可能是它自己的),而不是使用调用线程的堆栈 thread_entry (){ do_something(); --> Interrupt occurs do_otherstuff(); } void interrupt_routine () { uint8_t read_byte; // I don't want this to be part of caller thread's stack

我希望我的中断服务例程使用不同的堆栈(可能是它自己的),而不是使用调用线程的堆栈

thread_entry (){
    do_something();
    --> Interrupt occurs
    do_otherstuff();    

}

void interrupt_routine ()
{
    uint8_t read_byte;     // I don't want this to be part of caller thread's stack
    read_byte= hw_read();
}

是否可能&如何实现这一点?

Linux的GNU C库有方法控制信号执行的堆栈。有关详细信息,请参阅

基本思想是为堆栈分配内存并调用函数

sigstack()
指定此堆栈可用于信号处理。然后使用

sigaction()
函数为特定信号注册处理程序并指定标志值

SA_ONSTACK
该处理程序在特殊堆栈上运行

下面是一个显示模式的代码片段,它是从示例中“借用”来的


操作系统和中断处理程序所需的堆栈是在初始化时设置的。这也是特定于体系结构的代码。对于ARM处理器,它有一个独特的R13,当处理器处于中断模式时使用。同样,该寄存器在启动时初始化。您希望通过这种设计解决什么问题。

这里是一个简单的x86内联汇编实现。您有一个包装器函数,可以更改堆栈并调用实际例程

const uint32_t interrupt_stack_size = 4096;
uint8_t interrupt_stack[interrupt_stack_size];

void interrupt_routine_wrap()
{
    static int thread_esp;
    // Stack grows towards lower addresses, so start at the bottom
    static int irq_esp = (int) interrupt_stack + interrupt_stack_size;

    // Store the old esp
    asm mov dword ptr thread_esp, esp;

    // Set the new esp
    asm mov esp, dword ptr irq_esp;

    // Execute the real interrupt routine
    interrupt_routine(); 

    // Restore old esp
    asm mov esp, dword ptr thread_esp;
}
我在这里完全忽略了段寄存器(
ss
),但是不同的内存模型可能需要将其与
sp
一起存储

您可以通过使用
setjmp
/
longjmp
读取/写入所有寄存器来摆脱内联程序集。这是一种更便于携带的方法


还要注意,我没有在这里保留任何寄存器,内联汇编可能会混淆编译器。也许值得在包装器例程周围添加一个
pusha
/
popa
对。如果您将函数指定为
interrupt
,编译器可能会为您执行此操作。检查生成的二进制文件以确定。

这是什么编程语言?实际代码是C语言。我在这里放了一种伪代码。很抱歉。让变量
静态
(取决于您有多少ram)怎么样?@vlp类似于
静态
变量的概念,您可以拥有所有ISRs变量的全局并集,因此它们共享相同的全局内存。@mtijanic Nice idea…还记得在使用前初始化这些变量(在适当的情况下).谢谢,这似乎是一个可行的解决方案。
const uint32_t interrupt_stack_size = 4096;
uint8_t interrupt_stack[interrupt_stack_size];

void interrupt_routine_wrap()
{
    static int thread_esp;
    // Stack grows towards lower addresses, so start at the bottom
    static int irq_esp = (int) interrupt_stack + interrupt_stack_size;

    // Store the old esp
    asm mov dword ptr thread_esp, esp;

    // Set the new esp
    asm mov esp, dword ptr irq_esp;

    // Execute the real interrupt routine
    interrupt_routine(); 

    // Restore old esp
    asm mov esp, dword ptr thread_esp;
}