I am using <ucontext.h>
to swap between different tasks in my "task manager" program. The tasks (functions) are in a linked list and a timer is sending signals in regular intervals to a signal handler which swaps the current context to the next task in the list.
The problem is that I need an infinite loop in order to keep the program running, because otherwise it terminates before the timer has a chance to send the next signal. The way I am dealing with this is slapping an infinite cycle at the end of each task (function) so the timer has time to send a signal. I don't think this is a good way to keep the program running, so I want to know if there is a way to create some sort of "global" loop which keeps going irrespective of the current context I am currently in. Putting it in the "main" function did not work, because I leave the main context in order to enter the other ones.
#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, ¤t->context);
}
void signal_handler() {
struct elem *temp = current;
current = current->next;
pop();
push(temp->context);
swapcontext(&temp->context, ¤t->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");
}