有没有一种方法可以创建一个全局无限循环,而不考虑当前的ucontext(Linux C)?

k10s72fa  于 2023-05-28  发布在  Linux
关注(0)|答案(1)|浏览(133)

我正在使用<ucontext.h>在我的“任务管理器”程序中的不同任务之间进行交换。任务(功能)在一个链表中,定时器定期向信号处理程序发送信号,信号处理程序将当前上下文交换到列表中的下一个任务。
问题是我需要一个无限循环来保持程序运行,因为否则它会在计时器有机会发送下一个信号之前终止。我处理这个问题的方法是在每个任务(函数)结束时打一个无限循环,这样计时器就有时间发送信号。我不认为这是保持程序运行的好方法,所以我想知道是否有一种方法可以创建某种“全局”循环,无论我当前所处的上下文如何,它都可以继续运行。把它放在“main”函数中并不起作用,因为我离开主上下文是为了进入其他上下文。

#include <malloc.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <ucontext.h>
#include <unistd.h>

#define FIBER_STACK 1024 * 64

ucontext_t uctx_func1, uctx_func2, uctx_func3, uctx_main;

struct elem {
    ucontext_t context;
    struct elem *prev;
    struct elem *next;
};

struct elem *start = NULL;
struct elem *current = NULL;

void signal_handler();
void push(ucontext_t context);  // end
void pop();  // start
void fiber1();  // these are my tasks
void fiber2();  // these are my tasks
void fiber3();  // these are my tasks
void create_task(void (*start_routine)(), ucontext_t context);
void setHandler(struct sigaction sa);
void setTimer(struct itimerval timer);

void main() {
    struct sigaction sa;
    struct itimerval timer;

    create_task(fiber1, uctx_func1);
    create_task(fiber2, uctx_func2);
    create_task(fiber3, uctx_func3);

    setHandler(sa);
    setTimer(timer);

    current = start;

    swapcontext(&uctx_main, &current->context);
}

void signal_handler() {
    struct elem *temp = current;

    current = current->next;

    pop();

    push(temp->context);

    swapcontext(&temp->context, &current->context);
}

void create_task(void (*start_routine)(), ucontext_t context) {
    getcontext(&context);

    context.uc_link = NULL;
    context.uc_stack.ss_sp = malloc(FIBER_STACK);
    context.uc_stack.ss_size = FIBER_STACK;
    context.uc_stack.ss_flags = 0;

    makecontext(&context, start_routine, 0);

    push(context);
}

void fiber1() {
    printf("++++++++++\n");

    while (true) {
    }  // these are the infinite loops I want to get rid of
}

void fiber2() {
    printf("----------\n");

    while (true) {
    }  // these are the infinite loops I want to get rid of
}

void fiber3() {
    printf("**********\n");

    while (true) {
    }  // these are the infinite loops I want to get rid of
}

void push(ucontext_t context) {
    struct elem *p = start, *q;

    if (start) {
        q = (struct elem *)malloc(sizeof(struct elem));

        q->context = context;
        q->next = NULL;

        while (p->next)
            p = p->next;

        p->next = q;

        q->prev = p;

    }

    else {
        start = (struct elem *)malloc(sizeof(struct elem));

        start->context = context;

        start->prev = NULL;

        start->next = p;
    }

    // printf ("Element Added.\n");
}

void pop() {
    if (start) {
        start = start->next;

        // printf ("Element Deleted.\n");
    }

    else
        printf("Queue is empty.\n");
}

void setHandler(struct sigaction sa) {
    sa.sa_handler = signal_handler;
    sa.sa_flags = 0;

    sigemptyset(&sa.sa_mask);

    if (sigaction(SIGALRM, &sa, NULL) == -1)
        perror("sigaction");
}

void setTimer(struct itimerval timer) {
    timer.it_interval.tv_sec = 0;
    timer.it_value.tv_sec = 0;
    timer.it_interval.tv_usec = 10000;
    timer.it_value.tv_usec = 10000;

    if (setitimer(ITIMER_REAL, &timer, NULL) == -1)
        perror("setitimer");
}
icnyk63a

icnyk63a1#

创建一个wrapper函数:

void task(void (*actual_task)())
{
    // Call the actual task function
    actual_task();
    // Do the housekeeping
    while(1);
}

然后按如下方式更改create_task

void create_task(void (*start_routine)(), ucontext_t context) {
    // ......
    makecontext(&context, task, 1, start_routine);
    // ......
}
  • 但我会建议用一个信号来触发“非计划”上下文切换而不是等待计时器来取代循环。
    **编辑:**正如注解中所指出的,makecontext的可变参数不能是函数指针,必须是int。为了解决这个问题,可以创建一个“任务”的全局数组-即函数指针,并将数组索引作为参数传递。因此,修改答案,它看起来像:
void (*task_func[])() = {
    fiber1,
    fiber2,
    fiber3
};
//.....

void task(int task_index)
{
    // Call the actual task function
    (task_func[task_index])();
    // Do the housekeeping
    while(1);
}
//......
void create_task(int task_index, ucontext_t context)
{
    // ......
    makecontext(&context, task, 1, task_index);
    // ......
}

相关问题