ROS Newsletter91
Содержание
Выпуск новостей ReactOS №91
Переписывание диспетчера сеанса ReactOS
Диспетчер сеанса (SMSS) отвечает за инициализацию большей части окружения операционной системы, а также за запуск служб и процессов, необходимых для отображения экрана входа пользователя в систему. В частности, он создает системные переменные окружения, наследуемые другими процессами, загружает подсистему Win32, создаёт страничные файлы для виртуальной памяти, и, наконец, запускает процесс winlogon.exe. Реализация этого компонента, которая ранее использовалась в ReactOS, была крайне упрощенной в части её взаимодействия с компонентами подсистемы, что приводило к тому, что эти компоненты не правильно предоставляли реализации интерфейсов, которые должен был использовать SMSS. Алекс Ионеску (Alex Ionescu) решил исправить эту ситуацию и поочерёдно заменял компоненты SMSS на создаваемые заново.
Первоначально SMSS2 мог всего лишь инициализировать окружение, однако с каждым коммитом Алекса стал принимать на себя всё большее и большее количество обязанностей существующего SMSS, включая создание страничных файлов (pagefiles) и переменных окружения. Алекс одновременно работал над SMSS и компонентами подсистемы Win32 в win32k.sys, а также подсистемой клиент/сервер времени выполнения (CSRSRV), для исправления ошибок в их взаимодействии с SMSS, что в конечном итоге привело к появлению в транке полностью завершённой реализации CSRSRV.
При работе над CSRSRV пришлось также поработать над потоковой моделью, используемой для обработки запросов. Ранее CSRSRV создавал новый поток для каждого запроса, который он получал. Кроме того, в старом коде содержались ошибки, приводившие к массовым утечкам ETHREAD, структур данных, которые и представляют собой потоки. Поскольку экземпляры ETHREAD выделялись из невыгружаемого пула, а CSRSRV порождал несколько тысяч потоков, в каждом из которых происходила утечка приблизительно 300 байт, в конечном итоге система довольно быcтро съедала крайне дефицитные ресурсы, и это не считая других, более мелких утечек, имевшихся в старом CSRSRV. Успешное устранение этой проблемы принесло значительное уменьшение одновременных потоков в CSRSRV и позволило избавиться от довольно большой утечки памяти.
Утечки и неэффективная работа с памятью
Как упоминалось ранее, работа Алекса над SMSS и CSRSRV позволила значительно сократить количество памяти, используемой ReactOS, главным образом благодаря устранению утечек и более эффективному использованию ресурсов. Алекс, однако, был не единственным, кто пытался устранить утечки и повреждения памяти. Жерому Гардо (Jérôme Gardou) удалось найти и исправить ошибку, известную как ошибка 'mshtml' (хотя к самому компоненту mshtml она и не имела никакого отношения).
В ReactOS в настоящее время имеется два диспетчера памяти: первоначальный диспетчер, а также новый диспетчер ARM3 (сокращение от Another Rewrite of the Memory Manager Module), работы над которым были начаты командой портирования на архитектуру ARM. Хотя в ARM3 и содержится значительная часть функциональности, необходимой для замены диспетчера памяти, он еще не может полностью заменить старый диспетчер памяти, поэтому оба они работают параллельно. Проблемы начинаются тогда, когда старый диспетчер и ARM3 начинают работать по-разному.
Далее приводится очень короткое объяснение принципов функционирования виртуальной памяти и структур данных подкачки (те, кто уже знаком с терминологией виртуальной памяти, могут перейти к следующему параграфу). Виртуальная память представляет собой способ для абстрагирования операционной системы от прямого доступа к физической памяти и предоставления программам непрерывного адресного пространства. Для преобразования виртуальных и физических адресов используются таблицы страниц, и для преобразования каждой из страниц в таблице имеется соответствующая запись. Сами по себе таблицы страниц организованы в каталоги страниц, и каждый элемент каталога страниц (PDE) указывает на адреса таблиц страниц и содержит биты информации об их состоянии. Всё это в сумме представляет собой основные структуры данных, которые диспетчер памяти использует для своего функционирования. Ошибки в обработке любой из них, как правило, приводят к множеству ошибок, начиная с небольших повреждений данных и заканчивая критическими сбоями системы.
Каждый из диспетчеров памяти поддерживает свой собственный набор каталогов страниц и занимается их выделением и освобождением. В ARM3 имеется счётчик ссылок для подсчёта количества присутствовавших в каталоге страниц элементов, что позволяет облегчить принятие решения о возможности удаления конкретного PDE. Старый диспетчер памяти этого не делал и просто отбрасывал PDE всякий раз, когда происходило завершение работы процесса или процессор производил переключение контекста.
В настоящее время ARM3 поддерживает лишь выделение памяти ядра, функционируя совместно со старым диспетчером памяти. Однако это совместное функционирование может привести к очень плохим вещам из-за того, что записи, обрабатываемые старым диспетчером памяти и ARM3, никогда не синхронизировались. Это приводило к потере старым диспетчером памяти слежения за страницами, находящимися в директориях страниц, что в конечном итоге могло привести к повторному их использованию для других целей либо самим старым диспетчером памяти, либо диспетчером ARM3, приводя к повреждениям PDE и полной потере слежения за преобразованием виртуальных и физических адресов между собой.
Жером произвёл соответствующие изменения в коде, результатом которых стало возложение на ARM3 обязанностей по обработке всех содержащих PDE страниц, что позволило использовать механизм подсчёта в ARM3 для слежения за тем, используется ли каждый конкретный каталог страниц. Отчёты тестеров дают понять, что ошибка 'mshtml' была устранена, однако выявились другин проблемы, которые, похоже, были скрыты от глаз тестеров долгим царствованием ошибки 'mshtml'. Работа Жерома и других разработчиков над диспетчером памяти вдохновила Алекса на просмотр своих старых патчей, и он наткнулся на один патч, отправленный им команде ARM на рассмотрение. Просмотрев его, Алекс понял, что этот патч, похоже, мог бы исправить ошибку 'mshtml' ещё несколько месяцев назад и сэкономить время, потраченное на поиск и устранение этой проблемы.
Как и работа Жерома, этот патч был связан с PDE и с правильной очисткой, что позволило бы убедиться в отсутствии утечек в записях, а также устранением некоторых других проблем. Алекс создал обновленный патч с учётом текущего состояния диспетчера памяти и добавил его в кодовую базу, однако Жерому пришлось провести дополнительную доработку кода для исправления освобождения страниц PDE, указывающих на общую память.
Кроме кода обработки PDE, патч команды ARM также касался проблемы удаления данных, которые больше не требуется после инициализации программы. В частности, функции в драйверах могут быть промаркированы макросом INIT_FUNCTION, который сообщает загрузчику о необходимости помещения его в специальный раздел двоичного образа. После того, как загрузчик загрузит образ в память и инициализация драйвера или программы будет завершена, диспетчер памяти может освободить блок памяти, куда ранее были загружены секции. Разумеется это применимо только к функциям, которые необходимы лишь во время инициализации, и в последующем больше не потребуются, но даже это приводит к заметной экономии используемой системой памяти. И последним замечательным нововведением, которое было внесено в систему патчем команды ARM, стало хотя и довольно простое, но тем не менее эффективное изменение, связанное с удалением данных, необходимых для загрузки операционной системы, но абсолютно бесполезных после начала функционирования ядра.
Вполне очевидный вопрос, который многие хотели бы задать: Когда же ARM3 сможет заменить старый диспетчер памяти? Краткий рассказ о нём чуть выше по тексту показал более жёсткий учёт ресурсов системы диспетчером ARM3, а также его превосходство над старым диспетчером памяти. К сожалению, ARM3 пока не подключен к компонентам памяти пользовательского режима, и, скорее всего, потребуется некоторое время, прежде чем эта работа будет завершена, поэтому в краткосрочной перспективе у ReactOS нет иного выбора, кроме как иметь в своём составе два диспетчера памяти.
Объекты Window Station и Desktop
Объекты window station являются неотъемлемой частью целой модели обеспечения безопасности в Windows, и их удручающее состояние в ReactOS означает, что система практически не способна обеспечить безопасную работу. Яннис Адамопулос (Giannis Adamopoulos) усердно старается исправить эту ситуацию, и в ходе своей работы столкнулся с обширным кругом различных проблем. Одной из самых крупных ошибок, препятствующих его корректной реализации, была проблема неправильно спроектированной обработки ввода с клавиатуры и мыши. Рафал Харабиен (Rafał Harabień) исправил эту проблему, после чего Яннис смог удалить несколько хаков.
Многие из этих хаков были связаны со структурой данных THREADINFO, которая, как понятно из её названия, используется подсистемой win32k для описания потоков. Самая вопиющая ошибка была связана с обработкой объектов Рабочий стол (desktop), хотя это и происходило не по вине самой структуры THREADINFO. У объекта desktop имеется своя собственная ассоциированная с ним память кучи, и все потоки, принадлежащие этому рабочему столу, размещают свои данные в этой куче. При вызове функции CreateDesktop для уже существующего объекта desktop, ему передаётся новая куча. Проблема, однако, состояла в том, что все потоки по-прежнему хранят свои данные в старой куче и начинают путаться при внезапном изменении кучи, принадлежащей их объекту desktop.
Разработчики системы Windows часто используют различные средства управления доступом и маски для указания типа выполняемых операций при необходимости создания или открытия объектов и система проверяет эти маски, чтобы убедиться, что вызывающий объект на самом деле имеет разрешение на выполнение требуемой операции. Для объектов, которыми управляет win32k (таких, например, как desktop и window station) такие проверки не производятся. Причина этого напоминает что-то вроде петли отрицательной обратной связи. Во-первых, ReactOS никогда не указывает правильные маски доступа, которые собирается проверять.
Если говорить более конкретно, то это приведёт к тому, что код проверки правильности маски не примет передаваемую ему маску, поскольку не была задана правильная маска. Теоретически, это приведёт к провалу попыток проверки разрешений и безопасности. Во-вторых, ReactOS не устанавливает правильные разрешения для владельца объектов desktop, поэтому в теории ни один компонент системы не сможет сделать что-либо с объектом desktop. И в-третьих, чтобы в ReactOS не возникало проблем с предыдущими двумя проблемами, проверки контроля доступа были отключены почти во всех компонентах системы. Яннис занимался решением первой проблемы, а сейчас работает над второй. После того как обе этих проблемы будут решены, он сможет включить контроль доступа в соответствующих местах кодовой базы, и, надеемся, слово "безопасность" наконец-то будет для ReactOS не пустым звуком.
USB
Как уже было отмечено в совместном с Haiku заявлении, проект ReactOS недавно добился значительного прогресса в разработке стека USB. Во время и после гонки за включение в кодовую базу проекта ветви, в которой происходила разработка поддержки USB, Кэмерон совместно с Йоханнесом Андервальдом (Johannes Anderwald) активно работали над отладкой и исправлением ошибок в USB-стеке для приведения его в более пригодное к использованию состояние. На текущий момент их достижения включают в себя монтирование USB-носителей и значительно улучшенную поддержку устройств ввода для интерфейса USB.
Кэмерон наконец смог избавиться от драйвера USB для NT4, который долгое время использовался в ReactOS как хак для обеспечения крайне ограниченной поддержки интерфейса USB. В этом драйвере весь стек USB объединён воедино, включая драйверы для устройств хранения данных, клавиатур, мышей и даже для различных типов контроллеров, таких, как EHCI, OHCI, и UHCI. Краткую статью, посвящённую рассказу о типах USB-контроллеров, можно прочитать в предыдущем выпуске новостей. Этот драйвер представлял собой один огромный хак, и работа, начатая Михаэлем Мартином (Michael Martin) и продолженная Кэмероном и Йоханнесом позволила отказаться от его дальнейшего использования. Попытки исправления проблем с загрузкой с USB устройств, с которыми столкнулись пользователи, привели разработчиков в HAL, который передавал неправильную нумерацию шин драйверу PCI, из-за чего драйверу не удавалось обнаружить никаких устройств используя эти номера.
Так как драйвер PCI ничего не находил, соответственно он даже не пытался загрузить драйвер USB. Сбросы состояния EHCI и OHCI также были усеяны хаками, при этом OHCI был занят постоянным ожиданием получения бита сброса, а отнюдь не ожиданием прерывания. В обработчике прерывания сброса EHCI находился код, которого там не должно было быть. Помимо этого, EHCI не мог очистить биты изменения состояния, что приводило невозможности использования новых устройств после того, как в порт было установлено, а затем удалено низкоскоростное устройство. И, наконец, проблема с USB-клавиатурами во время первого этапа загрузки заключалась в отсутствии соответствующих данных в реестре. Так как раньше ни один из компонентов не использовал этой информации, то соответственно не было необходимости в исправлении этой проблемы, однако для правильной регистрации интерфейса, необходимой для обеспечения работоспособности USB-устройств, работающих на раннем этапе загрузки системы, эта информация крайне необходима.
В целом, поддержка USB существенно улучшилась, но стек ещё остаётся чрезвычайно хрупким и незавершенным. Нужно сделать ещё много работы, и Кэмерону и Йоханнесу ещё предстоит справиться с большим количеством ошибок, неправильным поведением некоторых контроллеров и двусмысленностями в документации и спецификациях. Предстоит пройти ещё довольно долгий путь, прежде чем ReactOS наконец получит полную и стабильную поддержку интерфейса USB, но радует то, что начало этому уже положено.
Newsletters | |
---|---|
30-39 | #30 • #31 • #32 • #33 • #34 • #35 • #36 • #37 • #38 • #39 |
40-49 | #40 • #41 • #42 • #43 • #44 • #45 • #46 • #47 • #48 • #49 |
50-59 | #50 • #51 • #52 • #53 • #54 • #55 • #56 • #57 • #58 • #59 |
60-69 | #60 • #61 • #62 • #63 • #64 • #65 • #66 • #67 • #68 • #69 |
70-79 | #70 • #71 • #72 • #73 • #74 • #75 • #76 • #77 • #78 • #79 |
80-89 | #80 • #81 • #82 • #83 • #84 • #85 • #86 • #87 • #88 • #89 |
90-99 | #90 • #91 • #92 • #93 • #94 • #95 • #96 • #97 • #98 • #99 |