Transparent distributed processing (прозрачная распределенная обработка).
По прочтении моей предыдущей статьи ты (надеюсь) получил некоторое представление об основных принципах функционирования КНХ-сети. В числе прочих упоминалось понятие блокировки, которому я не счел нужным дать определение, поскольку посчитал это избыточной информацией. Но специально для тех, кто не догадался сам, что это за блокировки такие, и зачем они вообще нужны, расскажу поподробнее :).
Иногда нужно запретить процессу выполнение каких-либо действий до наступления некоего события. Как ты понимаешь, в многозадачной среде может произойти ошибка, если, например, процесс A выдаст результаты вычислений еще до того, как процесс B предоставил ему данные для этих вычислений. Следовательно, необходимо заставить процесс A дождаться данных от B. Различают несколько видов блокировок в зависимости от стадии, в которой находится обмен сообщениями. Разумеется, процесс может быть и не блокирован, то есть в состоянии READY (есть еще несколько состояний - HELD, WAIT, DEAD, но их мы рассматривать не будем). Назовем процессы условно "рабочий" и "прораб", чтобы понятнее было :).
SEND-блокировка прораба: прораб кричит send() рабочему, нахально бездельничающему (READY) прямо под носом у начальства, но рабочий старательно делает вид, что не слышит :). Или просто до него медленно доходит...
REPLY-блокировка прораба: рабочий сказал receive(), мол сейчас все сделаю, только докурю...
RECEIVE-блокировка рабочего: рабочий попался сознательный, выдал receive(), хотя приказов еще никаких не получал. Выслужиться решил, вот и кричит: "готов к труду и обороне!", после чего терпеливо ждет сообщений в состоянии RECEIVE-блокировки. Получив приказ, рабочий ничего не говорит (думаю, не надо объяснять, что receive() уже был, а потому не имеет смысла выдавать его повторно), сразу принимается за работу, что радует прораба, которому даже не нужно переходить в состояние SEND-блокировки, так что он немедленно становится REPLY-блокированным и преспокойненько ждет результатов.
В любом случае, после выполнения задания рабочий говорит прорабу reply(), в смысле - принимай работу. Такой обмен сообщениями называется SEND-управляемым, то есть приказы отдает прораб, который решает, когда рабочему трудиться, а когда идти на обед. И это правильно, логично, и даже справедливо, но, как ни странно, существует REPLY-управляемый обмен сообщениями, когда всем заправляет рабочий, а не прораб. Просто рабочий прочитал КЗоТ и решил, что его нещадно эксплуатируют, лишая законных выходных и отпусков. Иногда он посылает сообщение прорабу "ну, так уж и быть, сегодня поработаю!". Прораб готовит задание и пересылает его в виде ответа на это сообщение. Соответственно, рабочий делает send(), содержащий результаты (такой конструкции, как ответ на ответ, в КНХ нет, иначе все окончательно запуталось бы).
Обычно прораб управляет несколькими рабочими, соответственно в КНХ вполне можно организовать прием сообщений от нескольких процессов-отправителей. Прием сообщений процессом-получателем осуществляется либо по очереди, в порядке поступления, либо в соответствии с приоритетами процессов-отправителей. Правда, мы договорились называть процесс-получатель "рабочим", а процесс-отправитель "прорабом", а потому ситуация выглядит парадоксально: один рабочий выполняет приказы нескольких прорабов. Впрочем, такое в жизни тоже случается :). К тому же "рабочий" и "прораб" - условные обозначения, при желании их можно зеркально отобразить... и тогда все станет на свои места.
Существует еще много нюансов передачи сообщений: запись и чтение части сообщения (если размер буфера меньше длины сообщения, то можно воспользоваться функциями Readmsg() и Writemsg(), вызывая их несколько раз, таким образом сообщение будет передано как бы "кусочками", нарезанными под размер свободного пространства в буфере), передача составных сообщений (немного отличный от предыдущего принцип: составное сообщение формируется в нескольких отдельных буферах, после чего передается без использования временного рабочего буфера, что обеспечивает бОльшую эффективность; имена соответствующих функций запомнить очень легко - Creceivemx(), Readmsgmx(), Receivemx(), Replymx(), Sendmx(), Writemsgmx(), т.е. они отличаются от соответствующих стандартных только приставкой mx).
Кроме того, интерес представляет так называемый прокси, что в данном случае означает метод связи, при котором процессы не блокируются. Используется в тех случаях, когда процесс-отправитель не нуждается в каком-либо взаимодействии с процессом-получателем, т.е. единственное предназначение proxy - посылка фиксированного сообщения процессу, создавшему proxy. Таким образом, процесс может передать сообщение, не блокируясь и не ожидая ответа, что удобно во многих случаях, в том числе в нередкой и немаловажной для ОС[РВ] ситуации, когда обработчик прерываний оповещает процесс о том, что некие данные доступны для обработки. Процесс, которому необходим такой способ связи (назовем его прокси-процессом для краткости), создает прокси-канал посредством функции qnx_proxy_attach(), после чего любой процесс или обработчик прерываний, которому известен идентификатор прокси-процесса, может послать ему прокси-сообщение с помощью функции trigger(). Чтобы не запутаться, назовем это сообщение триггером (интуитивно, да?). Так вот, чтобы не потерять триггеры, ядро выстраивает их в очередь и постепенно передает прокси-процессу, при необходимости "замораживая" их. В очереди может быть до 65535 отмороженных, т.е. тьфу, замороженных (или можно еще сказать - законсервированных) триггеров.
Совсем не лишняя мера предосторожности, учитывая, что при потере триггера по какой-либо форсмажорной причине прокси-процесс не сможет получить его повторно, ведь для этого необходимо как минимум проинформировать процесс, отославший триггер, что передача не произошла... а обратной связи как раз и нет! это же прокси! Обработчик прерываний вызывает прокси только в исключительных случаях - возникновение ошибок или, например, переполнение буфера в драйвере устройства, т.е. когда нужно проинформировать высокоуровневый процесс о чем-то очень важном и очень срочном... Не хватало еще ошибочно выполнить (точнее, НЕ выполнить) передачу сообщений об ошибке! Если ты читал "Паутину" Мэрси Шелли, то должен помнить, что там это называлось ОВО - Ошибка В Ошибке. Члены секты СЯО (Свидетели Явления Ошибки) считали ОВО признаком рождения великого кибер-мозга и ждали этого явления, как жрецы Майя - второго пришествия Пернатого Змея Кетцалькоатля... Или это были жрецы ацтеков? В любом случае, вряд ли это надо лично тебе :).
Прозрачность сетевого взаимодействия между процессами достигается с помощью так называемых виртуальных каналов. Работа с удаленным (в смысле remote, а не deleted :)) процессом ничем не отличается от использования локального процесса именно за счет того, что Сетевой администратор (все время при использовании этого термина возникает путаница, потому что непонятно, имею ли я в виду человека или программу... правильнее было бы наверно написать Сетевой Демон) автоматически передает сообщения (и еще сигналы, но это совсем другая история) этим путем, если нужно, конечно. Создавать виртуальный канал вручную обычно не требуется, хотя возможность такая есть, более того, при необходимости можно и обрубить канал насильственно... Процессы, работающие через виртуальный канал, получают виртуальные идентификаторы (VID), которые и являются уникальными в масштабе всей QNX-сети именами процессов. Разумеется, обеспечивается автоматическая трансляция VID'ов в PID'ы. Ты, наверное, обратил внимание на частое повторение слова "автоматически"? 🙂 Я же не виноват, что КНХ вообще и ее сетевая подсистема в частности организованы так грамотно ;).
Мой дорогой читател,ь может быть, спросит, в каких же случаях происходит автоматическое и насильственное прекращение связи по виртуальному каналу? Нет, ну я же сказал: "может быть" :). Так вот, если кто-то запнется о шнур питания и отрубит комп, участвовавший в передаче данных по виртуальному каналу, или тот же самый кривоногий "кто-то" выдернет сетевой кабель из хаба (он еще и криворукий к тому же ;)), а также в случае break'а удаленного процесса, с которым была установлена связь, данные передаваться не будут (как ни странно). Все эти ситуации фиксируются, после чего приложения высвобождают канал с целью корректного перераспределения занятых ими ресурсов, которые в противном случае могут оказаться постоянно занятыми. Взглючившие виндозные приложения часто оставляют свои ошметки в оперативной памяти, или, что еще хуже, продолжают работать, но такой остаточной работоспособности хватает обычно только на то, чтобы вынести какой-нибудь там МедиаПлейер, застопорить пару системных библиотек и в результате подвесить все, что можно и нельзя :(. Понятно, что КНХ это не винда (час от часу я выдаю все более глубокие мысли), и подобные вольности с ресурсами компа и нервами пользователя она себе (почти никогда) не позволяет.
Целостность виртуального канала проверяется Администратором процессов следующим образом:
Фиксируется время последней удачной попытки передачи данных. Если все таймауты давно кончились, а сетевой активности нет - значит велика вероятность наличия проблемы.
Администраторы процессов двух законнектвшихся компов периодически посылают друг другу тестовые пакеты. Если ответа нет, виртуальный канал помечается как сбойный. Предпринимается несколько попыток восстановления связи, в случае безуспешности которых канал отключается, процессам-виртуалам возвращается соответствующий код сбоя, после чего они переходят в состояние
READY. Кроме того, в целях повышения надежности и скорости, каждому виртуальному каналу выделяется область памяти для организации в ней буфера, в котором и хранятся передаваемые данные непосредственно в момент отправки на другой узел.
Разумеется, наибольшая ответственность за работоспособность сети возлагается на процесс Net (Администратор... ну, понятно чего). Ядро и Менеджер процессов помещают задания для Сетевого демона (как только их не приходится обзывать, чтобы избежать тавтологии... впрочем, смысла это не меняет) в специальную
неблокирующую очередь в памяти. Другими словами, сетевые операции (send(), reply(), qnx_proxy_attach(), передача SIGнала на другой узел) выстраиваются в некое подобие стека, ячейки которого содержат данные для этих операций.
Вот примерный алгоритм работы Администратора сети в стандартной ситуации Send-Reply:
1.Ядро копирует сообщение из адресного пространства процесса, вызвавшего send(), в буфер виртуального канала;
2.Ядро ставит заявку в очередь к Сетевому администратору, указывая в ней отправителя, удаленного получателя и указатели на данные в буфере виртуального канала. Если до этого очередь была пуста, то Менеджеру сети посылается прокси-сообщение (помнишь, тот самый триггер) о том, что появилась работа. В случае создания виртуального канала или передачи SIGнала составлением заявки занимается Администратор процессов, а в остальном все так же;
3.Сетевой администратор принимает заявку из очереди и передает ее, куда следует. Таким образом, он отвечает только за доставку данных, остальное его не касается. Такое высокоорганизованное распределение труда полностью себя оправдывает, но мы, кажется, забыли выяснить, что же происходит на узле-получаетеле. Итак...
4.Менеджер сети копирует поступившее по сети сообщение в буфер виртуального канала;
5.Он же оповещает ядро о завершении сеанса приема;
6.Ядро копирует данные из буфера виртуального канала в буфер процесса (надеюсь, ты помнишь, что процесс, ожидающий данных, обчно RECEIVE- или REPLY-блокирован). Если сообщение является управляющим SIGналом или командой создания виртуального канала, то оно потом обычным send'ом передается Администратору процессов (см.
последнее предложение пункта 2).
Если честно, я не рассказал и половины того, что могу и хочу поведать миру :). Планирование процессов в реальном времени, обеспечение жестких временных параметров при переключении задач и обработке прерываний, сигналы и их взаимосвязь с сообщениями, основанная на экстентах файловая система qnx и многое другое. К сожалению, я не имею возможности изучать КНХ всю жизнь - очень уж много написано других интересных ОСей, которым я собираюсь посвятить свои следующие статьи... Chorus и Jaluna, Mach и HURD, OS/2, Plan 9, различные клоны BeOS - все эти достойные образчики девелоперского труда будут героями моих романов :). Основной критерий, по которому я ориентируюсь при выборе тем - мнение потенциальных читателей, так что мыльте, высказывайте свою точку зрения на вопрос о том, какая именно ОС яляется самой интересной, самой лучшей, самой хорошей, и вообще самой-самой :). Вполне возможно, что одно из будущих моих произведений будет создано "по заявкам трудящихся" ;).
ЗЫ: Многие спрашивают меня, где достать дистрибутив этой замечательной операционки. На сайте
www.qnx.com халява кончилась, так что оттуда не скачать :(. Один человек выложил дистрибутив QNX 6.2.1 для всех желающих, но их оказалось так много, что лавочку пришлось прикрыть - плата за инет превысила все разумные пределы, а у него жена, дети, внуки... Так что 6.2.1 у меня самого нет, но есть 6.2.0 - один добрый человек прислал CD-R почтой. Кстати, таким путем я получил половину юзаемых мною ОСей, так что если кому надо - обращайтесь (возможен обмен бандеролями). А вот с QNX 4.25 вышло еще интереснее. Другой добрый человек кинул линк, но предупредил, что дистр оттуда скоро исчезнет, так что надо спешить. Зажав медяки в потной ладошке, я радостно поскакал, шлепая босиком по лужам, покупать инет. Тут необходимо пояснить, что в нашем городе 3 прова, оХвисы их находятся недалеко от моего дома, так что я пользуюсь разными: РЕНЕТ'ом для даунлоадинга по часовому тарифу (трафик они на основе абонентской платы предоставляют, что неудобно для человека, у которого деньги появляются редко и нерегулярно), ЛИ - для аськи и почты (качество связи у них просто ужасное, так что часы покупать бессмысленно), а РУС'ом вообще не пользуюсь (ну не нравятся они мне, и все тут). Так что я решил идти в РЕНЕТ, но по пути зашел в ЛИ, о чем сейчас очень жалею. Там мне предложили такую услугу: скачивание по выделенной линии (прямо в офисе, на гестовом компе), якобы это будет быстрее, дешевле и проще... Как последний дурак я поверил этой сказочке, а зря :(. За те деньги, которых хватило бы на 2 ночных часа (у РЕНЕТ'а за это время вполне реально скачать 19 мегов - полный дистр 4.25 со всеми аддонами), я скачал 7 (семь) мегов, т.е. голую ось без аддонов. Ладно, думаю, не очень-то и хотелось. Неизвестно, понадобятся мне эти аддоны вообще, хорошо хоть сама ось у меня есть. Как я был наивен! Оказалось, что они не могут сбросить эти файлы ни на дискеты, ни на CD или HDD, ни на мыл-бокс (да-да, дошло до того, что я предлагал им даже это). То у них шлейфа нет, то комп перезагружать/вскрывать нельзя, то разрезать файлы RAR'ом неохота. Короче, я пытался выцарапать эти жалкие 7 мегов почти месяц, после чего их сисадмин заявил мне буквально следующее: "Это в мои обязанности не входит, я занят, некогда мне тут с тобой разбираться, и вообще - наша фирма предоставляет услуги скачивания... Ты скачал? Вот и радуйся! Чего ты еще от меня хочешь? То, что ты получишь скачанное, мы не гарантируем". Другими словами, деньги с меня взяли за сомнительное удовольствие посидеть за их компом с Выньd0yz98. Так что если кому-нибудь бессмысленное любование интерфейсом виндозы доставляет эстетическое наслаждение - рекомендую фирму LAI
(http://firmlai.bal.ru), они такие услуги предоставляют (рубль в минуту).