Вопросы, идеи по следующим шагам. 1) нужна ли ловушка на завершение? Так как задача оформляется в
виде функции, то вполне можно при создании фрейм стека дополнить
таким образом, чтобы при выходе из функции улетели на заранее
подготовленное место. Потенциально может помочь при отладке.
2) fork() - не как на взрослых машинах, суть в следующем: от уже существующего стека отступаем на какой-то размер, инициализируем кадр, и ставим возврат на то же место, откуда вызвали, но с другим возвращаемым значением. Тогда получится, что входной параметр будет говорить не о размере стека новой задачи, а о размере, оставленной для порождающей. Принципиальный момент, будет ли удобно этим пользоваться? Этот подход отменяет на вопрос в №1. Главный плюс - malloc() не нужен. Создание задач будет выглядеть примерно так:
if ( !fork() ) {
n_task_1();
print("Task 1 finished!\r\n");
}
if( !fork() ) {
n_task_2();
}
//......
3) сделал примитив через запрет прерываний по образу test-and-set.
- запомнить состояние прерываний
{
/* прерывания запрещены */
- прочитать ячейку
- если ноль, то записать '1'
}
- восстановить состояние прерываний.
- вернуть прочитанное значение.
Неудобно, что возвращается 0 в случае удачного захвата, ну да ладно - буду считать, что ответ на вопрос it_was_locked() ?
Можно сделать запись не '1', а произвольного значения, но это порождает много неоднозначностей.
4) Сейчас сохраняется только точка входа в задачу, нет доступа к описанию (task control block, tcb). Сделаю указатель на текущую, вроде как tcb_t *task_running
. Можно через опрос состояния, но смысла не вижу: исполняемая задача и так об этом "знает", а для ОС быстрее будет, чем список перетрясти. Но состояние в tcb обновлять надо, конечно.
5) Подглядываю в ваш исходник. Понял, что вы написали про прерывания. Да, нужно при системном блокирующем вызове делать эмуляцию вызова прерывания. Прозрачно не получится, но там буквально вызов подпрограммы на ассемблере с сохранением-восстановлением разрешений прерываний. Отработать (не-ОС функции), если оно действительно прилетело.
6) Множественные события. попытался изобразить. Захват ресурса (спинлока, мьютекса) не особо нужен, как мне кажется. Важнее просыпаться при освобождении ресурса. До чего додумался: с ресурсом связан указатель на список, в каждом элементе которого хранится а)указатель на EVENT "подписавшейся" задачи, б)маска для установки бита в EVENT (перменной ожидания) и в) указатель на следующий такой же от другой задачи уже со своей маской. Задача может следить за несколькими событиями и различать их за счёт разных масок.
Можно сделать несколько переменных ожидания списком, чтобы не было ограничения по битности хранимой переменной. Выглядит не сильно затратно в плане процессорного времени. Сложность в том, что освобождение ресурса должен выполнять вызов ОС, чтобы уведомить всех подписавшихся. Функции "ОС, я хочу подписаться на этот ресурс" и удаления подписки может быть не совсем примитивной вреализации.
Багофича: даже если ресурс кто-либо опять захватит, всё равно все подписанты получат уведомление, как вы и описывали: "событие случилось в прошлом".
mevent.png