Просмотр полной версии : context switcher in new OS?
Каким предполагается быть сабж? Типа вот такого?
context_switch:
di
push af-hl,af'-hl',ix,iy
;store sp
;select task
;load new sp
pop af-hl,af'-hl',ix,iy
ei
ret
А если таска решит 'отдаться' оси, ось пойдёт этим кодом другой таске время отдавать, а тут как раз прерывание придёт... Хорошо на амиге (или ещё где), где контроллер прерываний с рогами =), а на спеке? Прерывание пропускаться будет... сам с таким недавно столкнулся.
А если таск начал уже исполняться он сам ставит бит управления TASK_ON, чтобы прерывание его повторно не запускало (если я правильно понял о чем речь) и перескакивало дальше.
На 8051 это вот так выглядит:
JB TASK_ON, OFF
CALL TASK
OFF:
А если таск начал уже исполняться он сам ставит бит управления TASK_ON, чтобы прерывание его повторно не запускало (если я правильно понял о чем речь) и перескакивало дальше.
На 8051 это вот так выглядит:
JB TASK_ON, OFF
CALL TASK
OFF:
точнее, LCALL )
на 8051 и семафоры выглядят просто замечательно:
jbc lock, locked
;use...
setb lock
locked:
а насчет добровольного пропуска- при входе в процедуру запрещаем прерывания, ставим процессу флаг "заблокирован на текущий квант",сохраняем самостоятельно контекст и переходим на вызов процедуры диспетчера внутри обработчика прерываний (тот который в первом посте нарисован). в ветке "эксперимент" я выкидывал свои сорцы, где у меня получалось подобное сделать. причем там аж две функции пропуска кванта %)
а насчет добровольного пропуска- при входе в процедуру запрещаем прерывания, ставим процессу флаг "заблокирован на текущий квант",сохраняем самостоятельно контекст и переходим на вызов процедуры диспетчера внутри обработчика прерываний (тот который в первом посте нарисован). в ветке "эксперимент" я выкидывал свои сорцы, где у меня получалось подобное сделать. причем там аж две функции пропуска кванта %)
Дык ну и вот, в момент этого добровольного пропуска тебе приходит инт и ты его запросто пропускаешь. Вот о чём речь, а не о том, как это сделать.
Я модифицировал RTK так, чтобы он мог делать preemption. Делается замечательно, причем учитывает нахождение в ядре или в таске. Причем размер критических секций (где может теряться прерывание) всего около 40 тактов, их 4. Сегодня выложу версию 0.9.
Дык ну и вот, в момент этого добровольного пропуска тебе приходит инт и ты его запросто пропускаешь. Вот о чём речь, а не о том, как это сделать.
когда приходит инт, возможны две ситуации
-процесс вытеснится
-процесс останется тот же самый
если мы в процедуре пропуска кванта запрещаем прерывания, а в это время приходит сигнал, он игнорируется (я как понял, тебя это беспокоит). но мы следующим шагом идем в обработчик прерываний, который в итоге даст первую ситуацию. так что тут мы ничего не теряем.
исключение составляет очередь процессов реального времени, обязанных выполняться по очереди каждое прерывание. для них нужно вводить специальный флаг, который будет выставляться каждое прерывание обработчиком и сниматься диспетчером по окончанию обработки той очереди. но тут есть узкое место- в предложенной ситуации пропуск прерывания означает вероятный пропуск диспетчеризации очереди процессов реального времени. как вариант, можно использовать отложенные прерывания. например:
int_routine:
push af
ld a,(int_flag)
or int_comeon
ld (int_flag),a
and pended_interrupt
jr nz,skip_int
push bc
....
pop bc
skip_int:
pop af
ei
ret
;somewhere in system
yield
ld a,(int_flag) ;beneath DI
or pended_interrupt
ld (int_flag),a
...
когда приходит инт, возможны две ситуации
-процесс вытеснится
-процесс останется тот же самый
если мы в процедуре пропуска кванта запрещаем прерывания, а в это время приходит сигнал, он игнорируется (я как понял, тебя это беспокоит). но мы следующим шагом идем в обработчик прерываний, который в итоге даст первую ситуацию.
Зачем идти в обработчик прерывания, если мы только передиспетчеризацию вызвали? Тогда не скипаться инты будут, а наоборот, ложные вызываться =)
Меня волнует именно пропуск прерываний, а никак не то, что там с процессами будет. На прерываниях муза висит, и неприятно, когда она заикается.
так что тут мы ничего не теряем.
исключение составляет очередь процессов реального времени, обязанных выполняться по очереди каждое прерывание. для них нужно вводить специальный флаг, который будет выставляться каждое прерывание обработчиком и сниматься диспетчером по окончанию обработки той очереди. но тут есть узкое место- в предложенной ситуации пропуск прерывания означает вероятный пропуск диспетчеризации очереди процессов реального времени. как вариант, можно использовать отложенные прерывания. например:
int_routine:
push af
ld a,(int_flag)
or int_comeon
ld (int_flag),a
and pended_interrupt
jr nz,skip_int
push bc
....
pop bc
skip_int:
pop af
ei
ret
;somewhere in system
yield
ld a,(int_flag) ;beneath DI
or pended_interrupt
ld (int_flag),a
...
Вот, нагромождение на нагромождении. То память в очке 16кб, потом такое вот безобразие без контроллера прерываний. Кстати, простейший контроллер прерываний получается из половинки ТМ2, устанавливается по фронту вбланка, сбрасывается по /IORQ|/M1 =)
Зачем идти в обработчик прерывания, если мы только передиспетчеризацию вызвали? Тогда не скипаться инты будут, а наоборот, ложные вызываться =)
не вызвали. а перешли внутрь обработчика прерываний потому что там стоит вызов передиспетчеризации. а так как переход идет на вполне определенную точку, то можно вполне решить, откуда пришли- из обработчика или извне
Меня волнует именно пропуск прерываний, а никак не то, что там с процессами будет. На прерываниях муза висит, и неприятно, когда она заикается.
в предложенной схеме такого быть не должно. максимум что может быть- сдвиг "музы" по времени от начала инта. имхо не критично
Вот, нагромождение на нагромождении. То память в очке 16кб, потом такое вот безобразие без контроллера прерываний. Кстати, простейший контроллер прерываний получается из половинки ТМ2, устанавливается по фронту вбланка, сбрасывается по /IORQ|/M1 =)
ты считаешь что это нагромождение?! ты настоящих не видел %)
неужели ты никогда не использовал обработчик прерывания примерно следующего вида:
int:
push af
ld a,(is_music)
and a
jr z,nomusic
push ...
call 49157/49158
pop...
nomusic:
pop af
ei
ret
а насчет железной доработки- это уже крайний случай. потому как лезть с паяльником ради софта- никому не надо
в предложенной схеме такого быть не должно. максимум что может быть- сдвиг "музы" по времени от начала инта. имхо не критично
1 - если инт придёт в момент, когда ты в аккум загрузил inf_flag, будет попа.
2 - Вызов музы от балды со средней частотой 50гц тоже не катит =)
ты считаешь что это нагромождение?! ты настоящих не видел %)
неужели ты никогда не использовал обработчик прерывания примерно следующего вида:
int:
push af
ld a,(is_music)
and a
jr z,nomusic
push ...
call 49157/49158
pop...
nomusic:
pop af
ei
ret
Юзал и юзаю, но при этом муза всегда играет в фикс. момент времени относительно начала инта и не скипается.
А проблему я решил следующим образом: вместо call _release делаю halt:call _release. Инт, естественно, жрёт далеко не все такты.
а насчет железной доработки- это уже крайний случай. потому как лезть с паяльником ради софта- никому не надо
Тем не менее проблема пропуска прерываний имеет место быть.
1 - если инт придёт в момент, когда ты в аккум загрузил inf_flag, будет попа.
2 - Вызов музы от балды со средней частотой 50гц тоже не катит =)
1- согласен, именно этот момент и стоит обвязать di/ei или придумать какойнить атомарный способ установки
2- ты че представляешь обработчик прерываний для ОСи со специальной функцией типа "а тут мы будем играть музыку"? :)
все вещи, которые требуют жесткой периодичности, висят на процессах реального времени. они по очереди выполняются каждое прерывание. отличие от стандартного вызова в контексте прерывания- использование не системного стека, решение проблемы реентерабельности вызова прерывания. поэтому твои опасения необоснованы %)
Юзал и юзаю, но при этом муза всегда играет в фикс. момент времени относительно начала инта и не скипается.
А проблему я решил следующим образом: вместо call _release делаю halt:call _release. Инт, естественно, жрёт далеко не все такты.
halt в операционной системе- варварская пустая трата драгоценных тактов %)
Тем не менее проблема пропуска прерываний имеет место быть.
промоделируй ситуацию на предложенных мной исходах и убедись что это не так
halt в операционной системе- варварская пустая трата драгоценных тактов %)
Гы. Почему? RTK тоже умеет HALT ;) %))))
Гы. Почему? RTK тоже умеет HALT ;) %))))
ну и о чем это говорит? ;)
у меня тоже в макете был халт. один. в стартовой процедуре.
каждый халт в среднем теряет 36000 тактов. вот и считай что можно сделать полезного за это время. повторяю еще раз- синхронизация за счет процессов реального времени.
Итак, дабы 100% исключить пропуск прерывания, ни ОС, ни задачи не должны их выключать. (А если задачи и переключают, то это уже на свой страх и риск). Если в момент прихода :) работает задача - все в порядке, а вот если критическая секция ОСки - возникают серьезные проблемы.
К примеру, работает планировщик, переключает задачи...приходит прерывание с которым начинается новое прогнозирование и новое переключение...Жуть, вобщем.
Я это обходил следующим образом. В качестве критического семафора менял JP по адресу прерывания. Причем так, чтобы если int пришел до или после этого, ничего бы не случилось.
А альтернативный обработчик менял на стеке адрес возврата из критической процедуры и возвращал ей управление. По окончанию адрес возврата записывался в текущий PC текущей задачи и управление передавалось настоящему обработчику.
Изврата были полные помидоры. Но работало. А сейчас лежит на дискетах, которые я не могу на ПЦ считать :(. Но ничего, когда-нибудь я найду себе реал :(.
К примеру, работает планировщик, переключает задачи...приходит прерывание с которым начинается новое прогнозирование и новое переключение...Жуть, вобщем.
В RTK решено с помощью подобного семафора (только там - ячейка памяти). От запрета прерываний на ~40 тактов избавиться не удалось - переключается стек, если придет прерывание, будет ЖО... но шанс попадания прерывания в этот участок кода настолько мал, что его практически можно игнорировать.
каждый халт в среднем теряет 36000 тактов. вот и считай что можно сделать полезного за это время.
Эээээ. Речь шла о ситуации, когда все таски сделали RTK_TIDLE, и нет синхротасков. Тогда делать уже нечего.
К примеру, работает планировщик, переключает задачи...приходит прерывание с которым начинается новое прогнозирование и новое переключение...Жуть, вобщем.
планировщик висит на обработчике. фиксированно. и вызываться вне времени может только из процедуры пропуска кванта. тут да, есть проблема пропуска только в одном случае (кусок моего исхода, модифицированный):
;somewhere in system
yield
di
ld a,(int_flag) ;beneath DI
or pended_interrupt
ld (int_flag),a
ei
когда прерывание приходит в момент запрещенных прерываний. тут возможнен пропуск одного прерывания с вероятностью (4+13+7+13+4)/72000~5.7е-4 невелика вероятность, но она есть. другой вариант:
set pended_int,(ix/iy+int_flg_offset)
более удачен. как компромисс, вполне подходит. возможные проблемы- приход прерывания перед данной командой, пропуск кванта принудительно и, после возврата, еще один пропуск добровольно. вероятность данного события еще меньше %)
(пжалста используйте русский язык, не все ведь английский изучали)
должен восстановить счётчик команда, стек, и регистры общего назначения при переключении на новый поток.
При уходе со старого потока соответственно происходит сохранение его данных (стек, регистры, счётчик).
Т.о. суммарно тот переключатель контекста, который предложил Lvd полностью удовлетворяет указанным условиям...
Технические моменты с приходом прерывания решаются несколько иначе.
На самом деле, переключатель контекста находится где-то в полосе среднеприоритетных задач (самый высокий приоритет - обработчики прерываний, средний - менеджеры памяти/потоков, нижний - собственно сами потоки с их приоритетами от критического по времени до низкого = idle), поэтому если прерывание придёт на момент, когда работает перключатель контекста, то ничего страшного не произойдёт, просто отработает обработчик прерываний, затём опять будет работать перключатель контекста.
Все проблемы с переключением контекста связаны с тем, что авторы тредов нечётко представляют себе иерархию части ядра, обрабатывающей системные события.
Все проблемы с переключением контекста связаны с тем, что авторы тредов нечётко представляют себе иерархию части ядра, обрабатывающей системные события.
Все проблемы связаны с отсутствием нормального контроллера прерываний. Если подумать - то становится ясно, что прерывание может прийти в момент переключения контекста, т.е., момента запрета прерываний. А еще от невозможности "отложенного" переключения задачи (это "де факто" на любой платформе) - ибо она может добровольно и не отдать такты планировщику. А значит переключать контекст надо сразу по приходу прерывания. А если так - значит надо проверить, не переключаем ли мы контекст переключателя контекстов (deadlock). А значит нужен семафор. А атомарных операций у нас нет, надо запрещать прерывания. Короче, все к одному.
Все проблемы связаны с отсутствием нормального контроллера прерываний. Если подумать - то становится ясно, что прерывание может прийти в момент переключения контекста, т.е., момента запрета прерываний. А еще от невозможности "отложенного" переключения задачи (это "де факто" на любой платформе) - ибо она может добровольно и не отдать такты планировщику. А значит переключать контекст надо сразу по приходу прерывания. А если так - значит надо проверить, не переключаем ли мы контекст переключателя контекстов (deadlock). А значит нужен семафор. А атомарных операций у нас нет, надо запрещать прерывания. Короче, все к одному.
Мне кажется ты опять не до конца прочитал что я написал, или не допонял
Схема такая: имеется обработчик прерываний, имеется переключатель контекста.
Обработчик прерываний работает 50 раз в секунду, переключатель контекста когда угодно.
Переключатель контекста и обработчик прерываний есть две совершенно различные процедуры/подпрограммы.
Классический орбработчик прерываний начинается в DI: Push и т.д.
Диспетчер потоков (переключатель контекста) никогда не запрещает прерывания, он имеет средный приоритет, высокий приоритет имеет только обработчик прерываний.
Во время работы обработчика прерываний прерывание прийти не может (и не должно).
Во время работы диспетчера потоков прерывание может прийти и ничего болезного здесь нет.
Думаю всё ясно...
Так как многие любят на примерах, то поясню.
1. Обработчик прерываний
DI
LD (nn),SP ; сохраняем стек
LD SP,Stack_for_Inter_Route ; переключаем стек на свою область памяти
Push ; сохраняем используемые регистры
Push
.... ; здесь выполняется обработчик прерываний, в результате работы могут быть созданы предпосылки для перенастройки диспетчера потоков
Pop ; восстанавливаем регистры
Pop
Ld Sp,nn
Ei
Ret ; здесь так же может быть переход на какую нибудь дополнительную процедуру вместо просто возврата
2. Переключатель контекста
Он выглядит следующи образом:
Push ; сохраняем используемые регистры и всю память по контексту
Push
Push
....
Call Calc_Now_Run_Thread ; вычисляем какой процесс нам надо запустить, подготавливаем его данные
...
Pop ; восстанавливаем контекст
Pop
Pop
Ret
Примечание: в результате работы обработчика прерывания может быть изменены какие либо данные, касающиеся приоритета процессов и прочей важной для системы информации. Поэтому максимум один квант времени (если прерывание пришло на диспетчер потоков) система будет работать по старой рассчитанной уже схеме. В случае же, если прерывание пришло на тело процесса, то все данные будут уже приняты измененными диспетчером потоков.
Как видно из такой схемы никаких сложностей (кроме подавления желания "упростить") не возникает - прерывание отрабатывает по одной схеме, диспетчер потоков - по другой.
когда прерывание приходит в момент запрещенных прерываний. тут возможнен пропуск одного прерывания с вероятностью (4+13+7+13+4)/72000~5.7е-4 невелика вероятность, но она есть. другой вариант:
2all: Неверно. Точнее верно, если задача работает сама по себе секунд 10, потом вдруг решает ни с того ни с сего 'отдаться'. А если она завязана на прерывания и ждёт какого-то события оттуда, а потом что-то посчитает и снова баиньки до следующей эксгумации =), то вероятность пропуска в таком случае увеличивается.
Так как многие любят на примерах, то поясню.
[skip]
Угу, поясни. КТО у тебя вызывает свичер с контекстом какой-то свичиваемой им задачи в регистрах?
Чтобы переключить задачу, надо её прервать. Это можно сделать только прерыванием. Следовательно, именно в прерывании надо менять контекст.
Переключатель контекста и обработчик прерываний есть две совершенно различные процедуры/подпрограммы.
Не может такого быть. Переключать контекст надо именно в прерывании. У тебя все равно предполагается, что обработчик прерывания отдает управление переключателю контекста. А если нет - тогда просьба пояснить, когда и как он исполняется.
Еще попробуй посчитать потери на планирование потоков при таком подходе. Я перед тем, как написать RTK, посчитал. Классический метод при адекватном написании теряет до тысячи тактов на планирование потоков. Это роскошь уже недопустимая...
Угу, поясни. КТО у тебя вызывает свичер с контекстом какой-то свичиваемой им задачи в регистрах?
Чтобы переключить задачу, надо её прервать. Это можно сделать только прерыванием. Следовательно, именно в прерывании надо менять контекст.
Ведём спокойную дискуссию называется.... :(
Сигнал прихода прерывания ты можешь использовать как сигнал окончания псевдокванта времени (1/50 секунды), но вообще-то говоря ты его используешь именно как прерывание.
Если ты прервал работу программы - так всё равно все данные (регистры, флаги, стек) сохранены в стеке (или в памяти, это не так важно) и потом можно восстановить их для перехода (по необходимости, если такая есть) к переключателю контекста.
Если же уже запущен переключатель контекста, то просто возвращается выполнение и всё, мне не ясно про что ты вообще говоришь...
1. В случае, если вдруг оказалось что программа не поддерживает квантование своего времени - т.е. она не использует принципы и соглашения невытесняющей многозадачности, в результате после прихода прерывания этот факт будет отслежен (после того как отработает обработчик прерывания и передаст управление на диспетчер потоков). А принципы и соглашения следующие: если есть возможность выполнив какую то элементарную операцию отдать управление системе, то это надо делать; элементарная операция является таковой если она длится менее 5 мсек.
2. Программа следует указанным правилам и соглашениям, но просто она попала на границу псевдокванта. В таком случае всё равно происходит передача управления на диспетчер потоков и никаких последствий.
Предлагается два подхода:
1. "Упрощенческий". Обработчик прерываний и диспетчер потоков (читай: переключатель контекстов потоков) совмешены в одно единое целое. Тогда имеем все указанные проблемы и продолжаем дальше заниматься "упрощизмом".
2. Классический подход. Обработчик прерываний и диспетчер потоков разные программы, взаимодействующие по классическим правилам. В этом случае никаких проблем нет.
Не может такого быть. Переключать контекст надо именно в прерывании. У тебя все равно предполагается, что обработчик прерывания отдает управление переключателю контекста. А если нет - тогда просьба пояснить, когда и как он исполняется.
Еще попробуй посчитать потери на планирование потоков при таком подходе. Я перед тем, как написать RTK, посчитал. Классический метод при адекватном написании теряет до тысячи тактов на планирование потоков. Это роскошь уже недопустимая...
Дело в том, что ты сразу себе должен отдавать отчёт в невозможности применения стандартных методов вытесняющей многозадачности. Просто нет поддержки со стороны железа и всё. Поэтому уже на одном этом основании предполагается, что используется именно невытесняющая многозадачность. Правила невытеснящей многозадачности ты знаешь, сверху они в упрощённой форме озвучены, повторяться нет смысла.
А что нужна именно невытесняющая (кооперативная) многозадачность (по крайней мере сейчаз) мне кажется очевидным: стандартная раскладка, в которой сейчаз хочется увидеть многозадачность такова: имеется обработчик клавиатуры (кооперативен), имеется обработчик мышки (кооперативен), имеется плеер AY-музона (тоже кооперативен), имеется текстовый редактор (или какой либо другой редактор, тоже вообще то кооперативен), имеются 1,2, и т.д. потоков, которые выполняются в фоне (вычисления, компиляция, форматирование текста, анализ загруженных данных и т.д.; некооперативны).
Отстаётся единственный вопрос, как отслеживать "зажравшиеся" потоки/задачи/процессы (они обозначены как некооперативные), которые не придерживаются правил кооперации в системе. Вот для этого и необходим обработчик прерываний (и не только для этого на самом деле, но это уже не для спектрума). Обработчик прерываний будет давать информацию (а т.к. он имеет более высокий приоритет, то он и будет исполняться раньше) для диспетчера потоков о том, что какой-то поток нарушает требования. А дальше уже диспетчер потоков решает как поступать с "заблудшим" потоком.
элементарная операция является таковой если она длится менее 5 мсек
Чем мерять собираешься?
2. Классический подход. Обработчик прерываний и диспетчер потоков разные программы, взаимодействующие по классическим правилам. В этом случае никаких проблем нет.
Это с какого он 'классическим' стал? =)
Проблем нет, так как ты по сути предложил откладывать прерывания, когда их можно пропустить. Все красивые и сказанные с гордым выражением слова не изменяют сути =)
а что мешает пойти на компромисс?
делаем обработчик прерываний, внутри у него стоит диспетчер (упрощенная схема), но также имеется и некая система обработки состояния системы. в зависимости от флагов этот кусок кода может выступать и как диспетчер задач (разрешено вытеснение) и как обработчик прерываний (вытеснение не разрешено, но это чревато рассинхронизацией процессов реального времени).
а процедура пропуска кванта по сути дела представляет собой выполнение двух действий: перевод текущего процесса в состояние сна и вызов диспетчера. а так как у нас на диспетчер завязаны синхропотоки, то необходимо это дело слегка уложнить
но это чревато рассинхронизацией процессов реального времени
Абсолютно прав. При вытеснении задач в RTK (практика) происходит легкая рассинхронизация, причем ее степень зависит от продолжительности прерванного таска.
то необходимо это дело слегка уложнить
Да, очевидно придется сделать метод текущего определения таском своего времени. Я предполагаю завязать под это дело регистр IY (его нельзя будет использовать ВООБЩЕ, за исключением прямого назначения). Это увеличит и расходы тактов на планирование, и сложность диспетчера. И еще отнимает один регистр совсем... Так что вариант ли?
Абсолютно прав. При вытеснении задач в RTK (практика) происходит легкая рассинхронизация, причем ее степень зависит от продолжительности прерванного таска.
значит, нужно делать так, что процессы реального времени могут вытеснить текущий процесс, в какой бы он фазе ни находился. опять-таки, за исключением тех ситуаций, когда происходит запрет прерываний (или флаг отложенности прерываний), но это должно происходить _только_ во время процедуры пропуска кванта. т.о. процессы реального времени все равно будут вызваны в данный квант, правда с небольшим смещением от начала инта. не очень критично, потому как это смещение обычно не превысит +200-300 тактов от стандартного
Да, очевидно придется сделать метод текущего определения таском своего времени. Я предполагаю завязать под это дело регистр IY (его нельзя будет использовать ВООБЩЕ, за исключением прямого назначения). Это увеличит и расходы тактов на планирование, и сложность диспетчера. И еще отнимает один регистр совсем... Так что вариант ли?
не вариант. еще больше увеличивается уязвимость системы. прямо как бейсик получается- испортил iy или hl' и гудбай америка! %)
но это должно происходить _только_ во время процедуры пропуска кванта
Хм... Нелогично. Во время процедуры пропуска кванта ТЕКУЩИЙ процесс всегда вытесняется, если есть ожидающие кванта процессы. А вот если начинаем вытеснять процесс по приходу прерывания - встает трабла. Невозможно узнать, сколько тактов процесс отработал. Поэтому внутренний счетчик тактов "уходит", и происходит легкая рассинхронизация.
Хм... Нелогично. Во время процедуры пропуска кванта ТЕКУЩИЙ процесс всегда вытесняется, если есть ожидающие кванта процессы. А вот если начинаем вытеснять процесс по приходу прерывания - встает трабла. Невозможно узнать, сколько тактов процесс отработал. Поэтому внутренний счетчик тактов "уходит", и происходит легкая рассинхронизация.
не вижу ничего нелогичного. процесс имеет право запретить прерывания (сиречь возможное принудительное вытеснение) исключительно если сам собирается это сделать. типа "не трогайте меня, сам все отдам!" %)
Средняя длительность одного кванта около 5 мсек.
Чем мерять собираешься?
Она меряется статистическими методами - если она длится больше, то скорей всего она часто будет попадать на прерывание (т.е. прерывание пришло во времся работы потока). Для такого потока система будет применять штрафные санкции смещения потока вниз по приоритету.
Сообщение от GriV
2. Классический подход. Обработчик прерываний и диспетчер потоков разные программы, взаимодействующие по классическим правилам. В этом случае никаких проблем нет.
Это с какого он 'классическим' стал? =)
Проблем нет, так как ты по сути предложил откладывать прерывания, когда их можно пропустить. Все красивые и сказанные с гордым выражением слова не изменяют сути =)
Классическим он стал с тех пор как создатели ОСей подбили шишек в процессе разработки указанного предмета.
Нет я не откладываю прерывания, просто я на прерывания ложу несколько иные функции.
(задача в общем то стоит не в этом, но это не так важно), то тогда конечно же должна стоять задача жёсткой синхронизации.
У нас же (исходя из того что есть) стоит задача создания системы с кооперативным делением процессорного времени.
В таком случае (есть такое положение), что обеспечить самый высокий приоритет система может лишь для прерывания. Любой поток (даже обладающий самым высоким приоритетом) будет всегда обладать в общей схеме низким приоритетом. А значит весьма возможно возникновение рассинхронизации.
Классическим он стал с тех пор как создатели ОСей подбили шишек в процессе разработки указанного предмета.
Угу, стало быть амигаос не классическая, а модерновая. =)
Нет я не откладываю прерывания, просто я на прерывания ложу несколько иные функции.
Угу... А ещё ты кооперативную вместо вытесняющей делать хочешь, и даже мерять время работы процессов непойми чем =)
Corpsegrinder
20.04.2005, 13:33
А ты чем на спектруме собрался мерять время работы процессов?
У меня на ум приходит только разве что посчитать сколько уже от начала работы поршло прерываний. Ну можно ещё, поручить каждому порцессу честно призначаться сколько он тактов отъел. Можно условно периодичностью вызовов время посчитать, только это будет время не реальное, а условное в рамках колебательных характеристик текущего состояния ОСи.
в среднем система знает сколько тактов свободного времени остаётся на потоки приложений (т.е. после отработки прерываний, диспетчера задач).
Далее запускаются приложения, которые требуют выполнения в каждом такте (опрос клавиатуры и т.п.) [я считаю что это и есть процессы высшего приоритета - приоритета реального времени; потоки реального времени ВСЕГДА должны успевать отрабатываться раньше прерывания, т.е. оставлять процессорное время на другие потоки]. И только после этого начинают отрабатывать остальные процессы.
Согласен, точно никак померять длительность каждого потока не получится, но вот менеджер процессов может сделать косвенно.
Вот такой алгоритм:
При выполнении на текущем прерывании набора процессов может оказаться два варианта:
- Потоки отработали раньше, чем пришло прерывание, в таком случае можно говорить что требование кооперативной многозадачности выполнено - все задачи выполнились вовремя и никаких проблем нет, здесь вопрос длительности даже не стоит принципиально.
- Потоки не успели отработать
В таком случае ветвление:
А) Не успел отработать 1 поток - скорей всего он и является критичным (но вовсе не обязятельно он, это выясняется на протяжении нескольких прерываний), его приоритет слегка занижается, это скажется на первоочерёдности его вызова (переключения на него) при очередном вызове. Постепенно самый "дурной" поток уйдёт в фоновый режим.
Б) Не успели отработать несколько потоков - в таком случае происходит миксирование потоков до тех пор, пока количество отработанных за прерывание потоков не станет максимальным (т.е. чисто практическим методом вытесняем наиболее критические потоки, которые нарушают требования кооперативности). Т.е. рассматривая динамику, скажем, за 10 прерываний можно уже более менее чётко определить какой из потоков жрёт больше всего времени.
Вот пример
Потоки Время (тактов)
0 ______ 2500
1 ______ 5000
2 ______ 10000
3 ______ 15000
4 ______ 20000
5 ______ 25000
6 ______ 30000
Количество свободных тактов процессорного времени - 65000.
Первая схема запуска (на первом прерывании):
6, 5, 4, 3, 2, 1, 0 (расстановка от большего приоритета к меньшему)
В итоге успели выполниться 6, 5 и частично 4й поток.
Система делает микширование потоков (вторая схема запуска)
6, 5, 3, 2, 1, 0, 4
В итоге выполнились 6, 5 и частично 3й поток
Очередное микширование (3ья схема)
6, 5, 2, 1, 0, 4, 3
В итоге выполнились 6, 5, 2 и частично 1й поток (т.е. количество выполненных потоков увеличилось).
Теперь система делает микширование на поток 5 аналогичным образом она придёт к схеме:
6, 2, 1, 0, 4, 3, 5
Выполнились 6, 2, 1, 0 и частично 4й поток (опять увеличение)
Теперь очередь за 6м потоком:
2, 1, 0, 4, 3, 5, 6
В итоге выполнились 2, 1, 0, 4, 3 и частично 5й поток.
Т.о. 6й поток и 5й оказались в самом конце схемы (менее приоритетные), в то время как потоки 2, 1, 0, 4 и 3 получили больший приоритет, т.к. они укладываются в одно прерывание.
В общем то предложенная схема не лишена недостатков, однако показывает что не всё так плохо как кажется и косвенными методами можно вычислить нарушителей режима (которые кушают слишком много времени).
Тут есть ещё такое замечание.
Потоки реального времени тоже могут поддвергаться дисциплинарным санкциям, если вдруг они ещё работали когда пришло новое прерывание.
И ещё, на самом деле вычисление "дурацких" потоков, нарушающих режим будет приходить гораздо быстрей.
Это связано с тем, что только потоки реального времени выполняются каждое прерывание.
А остальные процессы (в зависимости от изначального и подкорректированного системой приоритета) будут выполняться чаще или реже, но всё же не каждое прерывание.
Т.е. скажем из приведённой схемы 6й поток - самый жёсткий для нашей системы - (для примера) может быть не выполнен системой на 5ое прерывание. И в это прерывание диспетчер потоков зафикисирует факт значительного увеличения количества выполненных потоков. Естественно после некоторых вычислений диспетчер определит что это именно 6й поток является нарушителем (кушает почти половину процессорного времени) и "одарит" этот поток самым низким приоритетом.
Правда возникают следующие сложности: такие длинные потоки будут делиться на несколько частей: начальная, промежуточные и последняя (т.е. он прерывается несколько раз) первая и промежуточные естестенно будут "кушать" всё процессорное время. А вот последняя часть может оказаться очень короткой, изза чего диспетчер потоков может принять ошибочное решение о увеличении приоритета такого потока, что впрочем на следующем же вызове будет отменено. Кроме указанной ошибки есть такая ошибка (это наверное заметил для себя каждый), не все процессы имеют фиксированное время исполнения.
А в общем такая схема устраивает на 90%...
А теперь предлагаю посчитать, сколько такой навернутый планировщик будет "кушать" сам. Не меньше 500-1000 тактов... Расточительно.
А теперь предлагаю посчитать, сколько такой навернутый планировщик будет "кушать" сам. Не меньше 500-1000 тактов... Расточительно.
посчитай сколько кушает обычная процедура обработки прерываний. с полным сохранением регистров (как обычно и делается). плюс чето там внутри работает типа музыки. а это все 3-5 тысяч тактов
А теперь предлагаю посчитать, сколько такой навернутый планировщик будет "кушать" сам. Не меньше 500-1000 тактов... Расточительно.
Согласен, но проект то открытый - не понравится так соберёшь своё ядро, которое будет проще и быстрей (зато может более глюкавое :D).
И потом, что можно на 500 тактов уместить - я не представляю, разве тока систему обработки прерывания с управлением неизменным списком потоков...
И потом, что можно на 500 тактов уместить - я не представляю, разве тока систему обработки прерывания с управлением неизменным списком потоков...
Последнее (с изменяемым списком потоков!) у меня умещено на 300-400 тактов. Так что вполне нормально.
Последнее (с изменяемым списком потоков!) у меня умещено на 300-400 тактов. Так что вполне нормально.
300-400 тактов? Даёшь ядро на асме аттачем, оно должно быть не очень большим, посмотрю что можно на такое уместить...
недавно чета мысля в голову стукнула как можно сделать поддержку семафоров без запрета прерываний достаточно быстрым методом.
главная задача- в один шаг изменить значение запирающей общей ячейки памяти на "занято", получив при этом предыдущее значение. на z80 для этих целей прекрасно подходит команда dec (hl) (dec(ix/iy), inc (hl/ix/iy))
вот примерный код семафора
spinlock db 1 ;1-free, other-busy
db 0 ;for owner
...
ld ix,spinlock
call lock
... ;do smth
call unlock
...
lock
dec (ix) ;A
jr z,isfree ;B
inc (ix)
call sleep
jr lock
isfree
ld a,(pid)
ld (ix+1),a
ret
unlock
ld (ix),1
ret
единственная опасность, которую мне удалось рассмотреть, это если 255 процессов последовательно прервут друг друга между точками А и В. прежде чем кинуться считать такую вероятность, посчитайте вероятность простого запуска такого количества процессов %)
http://3os.ru - довольно интересный проект. немного почитал, симпатишно, но одна мысля испортила все настроение. когда почитаете, поймете какая %)
300-400 тактов? Даёшь ядро на асме аттачем, оно должно быть не очень большим, посмотрю что можно на такое уместить...
Я же даже тему создавал в "ОСЯХ". RTK называется ;)
P.S. Хочу отметить низкие ресурсные требования данной штуковины. На внутреннее переключение тасков уходит 156-195 тактов. На вызов RTK_TSLICE (отдача времени другим таскам) - 131 такт, на отдачу времени до следующего прерывания - вызов RTK_TIDLE - 164 такта. Итого имеем всего лишь от 287 до 359 тактов на фактическое переключение таска. Если в этот момент происходит отработка критического (синхронизированного) таска - еще 174/138 тактов, но это одноразово. На прерывание уходит тоже всего ничего - 272-296 тактов.
Причем достаточно легко могу адаптировать эту штуковину под количество тасков > 8, без больших потерь во времени выполнения (порядка 40 тактов на 8 тасков).
недавно чета мысля в голову стукнула как можно сделать поддержку семафоров без запрета прерываний достаточно быстрым методом.
главная задача- в один шаг изменить значение запирающей общей ячейки памяти на "занято"
По-моему, можно гораздо проще, классическим способом. Проанализировал, вроде затыков быть не должно. Прошу всех проанализировать:
SEMAPH DB #80
LD HL,SEMAPH
SLA (HL)
JP NC,LOCKED
... do something ...
LD (HL),#80
JP ...
LOCKED ...
По-моему, можно гораздо проще, классическим способом. Проанализировал, вроде затыков быть не должно. Прошу всех проанализировать:
ну у меня тоже своего рода классический способ %) хотя у тебя изящней даже получилось %)
2Alex/AT> я знаю что ты делал тему про Real Time Kernel (или как там правильней расшифровывается), однако неясно где исходники сего продукта, потому и спросил.
И ещё, для спектрума система реального времени как таковая не очень нужна, а вот система с кооперативной многозадачностью было бы неплохо иметь...
Насчёт указанных алгоритмов, на самом деле такой подход "не канает" по следующим соображениям: если семафор простой (т.е. проверяется только 1 байт), то нет никаких проблем, такие алгоритмы будут работать, однако если семафоры усложнятся (наверняка кстати) то придётся чтото придумывать. А точнее не придумывать а брать готовое. Обычно за семафоры (работу с ними) отвечает система, так вот когда управление переходит на п/п работы с семафорами, то ни один прикладной поток не может прервать работу этой п/п (так называемая критическая секция) - кроме может быть прерывания (int). Т.о. будет решён вопрос со сложными семафорами.
однако неясно где исходники сего продукта
Лежат в теме ;)
И ещё, для спектрума система реального времени как таковая не очень нужна
Хм.. кооперативная многозадачность - это и получается СРВ в общем случае. Программы должны сами следить за слайсом.
однако если семафоры усложнятся (наверняка кстати)
Варианты усложнения? Большинство можно реализовать как набор 1-байтовых.
так вот когда управление переходит на п/п работы с семафорами, то ни один прикладной поток не может прервать работу этой п/п (так называемая критическая секция)
А в винде допустим внутри ОС эти функции все равно на атомарной команде реализованы. Так что большой разницы не вижу. Тем более так сделано только из-за возможной многопроцессорности. У нас ее не ожидается. Кроме того, с командой LOCK (на PC, у Z80 аналогов нет) классический вариант будет работать и в SMP...
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot