Что-то намешалось "Списки хотят выделения/освобождения памяти" - откуда такие новости? Списки позволяют динамически связывать элементы списка (в этом случае структура метаданных задачи с указателем на функцию задачи, также в этой структуре должен быть указатель на структуру следующей задачи - тогда это элемент списка). Почитайте таки Вирта "Алгоритмы и структуры данных". Не стесняйтесь:).
По enum - что-то типа такого:
enum {
TASKNAME0,
TASKNAME1,
TASKNUMBER,
};
typedef void (*task_fun_ptr)(void *);
void FooTaskName0(void * Arg);
void FooTaskName1(void * Arg);
typedef stuct task_t{
//stuct task_t * next;
task_fun_ptr foo;
unsigned int rules;
}task_t;
task_t TaskName0 = {.foo = &FooTaskName0};
task_t TaskName1 = {.foo = &FooTaskName1};
task_t task_collection[TASKNUMBER]={ &TaskName0 , &TaskName1};
. . .
{
int idx = 0;
task_collection[idx].foo();
. . .
task_collection[TASKNAME1].foo();
}
Поставить в очередь.
Писал добавить в список, в тот же. Насчет приоритета и кооперативности - это, IMHO, влажные мечты, извините, не связанные с реальностью. Но если очень надо, то в структуру метаданных задачи можно добавить и поле приоритета, ну и написать, что с ним делать. Заодно вспомнить об инверсии приоритетов и благополучно забросить эту идею:)
Что касается event-driven, то оно начинается со входа-выхода из режима Idle. Тут опять рекомендую обратиться к Miro Samek. Причем нужно читать и https://embedders.org/blog/teap0t/miro-samek-ispolzovanie-rezhimov-malogo-energopotrebleniya-v-prostykh-programmnykh-arkhi , и его книгу, причем желательно начать с первой редакции, увидеть, какие ожидаются проблемы при мелкожручести и вытеснении, а потом вторую редакцию, где это вроде как причесали до рецептов. Кстати, у него на state-machine.com и кооперативка есть, и вытесняющие. Поглядите - вдруг "они копались в вашей голове". Там всё крутится именно вокруг Run-To-Complete и event-driven