ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Воскресенье
24 ноября
1056406
Dingo (29.11.2020 11:52, просмотров: 31416)
Появился зуд, хочу попробовать написать что-нибудь вытесняющее, дабы лучше понять как работают OS. В связи с чем вопросы к донам и дуэньям. 

Желание сделать планировщик или ОС, самый простой вариант, но именно что с вытесняющей многозадачностью. Минимальное необходимое - это возможность принудительно остановить одну задачу и передать управление другой. Да, я понимаю, что ОС никогда не ограничивается этим: следом пойдут средства взаимодействия (мьютексы, сообщения, приоритеты задач, ...), но это это неизбежный минимум.

1) прерывания. Проще всего переключать задачу из прерывания, поменяв адрес возврата в указателе стека. Только неоднозначно, как лучше делать. На примере AVR GCC есть атрибут naked, когда забота о сохранении/восстановлении состояния при входе/выходе из прерывания перекладывается с компилятора на программиста. Тогда появляется возможность использовать отдельный стек для прерывания, в которым будет работать планировщик, чтобы уменьшить необходимую глубину стека задач. Примерно как здесь https://habr.com/ru/post/267573/

Для переключения потребуется менять адрес возврата. Если сохранение стека не делать врукопашную, есть ли способы подменить точку возврата штатными средствами Си? setjmp/longjmp здесь не подходят, как мне кажется. Как бы вы делали: полностью взяли бы на себя работу со стеком или же переложили по возможности на компилятор?

1.1) ARM в отличие от AVR при входе в прерывания сразу сохраняет часть регистров, если я правильно прочитал. И умеет выстраивать прерывания в цепочку: если во время работы одного прерывания приходит запрос на другое (с этим же приоритетом?), то выполняется переход сразу на второй обработчик, без возврата в основную программу. Есть ли аналог naked для других компиляторов? Для других платформ (кроме AVR)?

1.2) Проблема с вложенностью прерываний - во время работы планировщика может произойти прерывание с более высоким приоритетом. Спрашиваю из-за своей мнительности: можно ли считать работу планировщика целостной, если такое случилось? В приведённой ссылке как раз подобная ситуация и была одним из источников проблем.

2) Старт задачи. Как выполнить? То есть при нормальном выполнении как запустить вторую задачу? Если делать что-то вроде

int main( void ) {
    start_task( task1, ...);
    start_task( task2, ...);
    start_task( task3, ...);

  while(1) {
      sheduler();
  }

}

то для задачи непременно должно быть начальное состояние "готова к запуску, но не выполняется"?

При старте вызывается функция и состояние задачи меняется на другое. Более никогда к начальному не возвращается. Далее планировщик согласно какой-либо логике чередует задачи.

Пока видится некая табличка, которая содержит начальные адреса задач и поле состояния "готова к запуску, но не выполняется". И место для сохранения контекста. Делать табличку как массив или как связанный список?

Может порекомендуете чтиво для подобного подхода? MINIX3 явно перебор. Про кооперативки не поможет в этих тонкостях. Во FreeRTOS я заблудился в исходниках - разветвлённое дерево и много всяких конфигурируемых вещей и всяческих #ifdef .