ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
19 апреля
1057443 Топик полностью
Dingo (02.12.2020 18:37, просмотров: 472) ответил fk0 на Основной примитив -- ожидание множественных событий. У многих нет и это проблема. Но по крайней мере у многих есть event flags из TRON. У кого нет (есть и такие) -- невозможно же программировать, всё упирается в очередь и работает только по очереди... Второй больной момент -- реализация условной переменной (conditional variable). Нужна возможность побудки одновременно всего множества процессов её ожидающих. Последнее -- что-то вроде futex в линуксе и зачатки видны в моём
Вопросы, идеи по следующим шагам. 

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