Продолжение истории с зависшей батареей, рассказываю что бывает если постоянно заимствовать пусть и открытый, но все же чужой код.

Понимаю, что для большинства читателей актуальна только красивая девушка на фоне, но тем не менее.
Понимаю, что для большинства читателей актуальна только красивая девушка на фоне, но тем не менее.

Помните как рассказывал об одном досадном баге в ядре Linux, выедавшем мне мозг несколько лет?

Внезапно этот же баг проявился в совершенно другой операционной системе, по идее не имеющей к линуксу никакого отношения — FreeBSD.

С чего автор слегка офигел, поскольку интернет испокон веков был полон срачами интеллектуальными дискуссиями на тему «Linux vs FreeBSD» — их радикальных отличий в идеях и концепциях, позиционировании на рынке и половой ориентации создателей.

Для тех кто не ходит по ссылкам, напомню суть бага:

Ноутбук засыпает, ноутбук просыпается и батарея «зависает» — перестает отдавать свой статус и уровень заряда.

Ноутбук старый, ноутбук редкий, из тех сказочных времен, когда подсистема ACPI еще считалась чем-то новым и не до конца проработанным.

Поэтому производители компьютерного оборудования позволяли себе вольности по части поддержки ACPI в своих девайсах. И разумеется мой ноутбук (Asus F3Ke) оказался одним из таких.

Не буду повторять всю историю поиска решения, занявшего несколько лет — она описана в оригинальной статье и достаточно интересна сама по себе.

В этот раз расскажу про другое:

каким сказочным образом баг в драйвере (!) одной открытой ОС перекочевал в другую открытую ОС.

Напомню (на всякий случай), что термин «драйвер» — из мира Windows и для Linux/BSD не совсем корректен, поскольку прямого аналога драйверов оборудования в этих ОС нет.

Но как назвать это более корректно идей не нашлось, увы. Официально эта сказочная штука о которой пойдет речь называется:

ACPICA kernel-resident subsystem

И живет внутри ядра, без возможности выгрузки.

Симбиоз

Конечно это не тайное масонское знание и не «секрет полишинеля», что разработчики открытых систем постоянно обмениваются идеями и копируют друг у друга какие-то наработки. Это разумно, поскольку в некоторых случаях действительно нет ни практического смысла ни ресурсов изобретать собственный велосипед.

У проекта FreeBSD долгая история заимствований из Linux, для примера именно таким путем (прямого заимствования) в FreeBSD появился DBus, появился Bluez (поддержка Bluetooth) и много чего еще.

Процесс зашел настолько далеко, что появился и активно развивается отдельный слой эмуляции Linux на уровне ядра, позволяющий запускать практически любые Linux-приложения без пересборки под FreeBSD.

Но к заимствованию из Linux исходного кода целых подсистем, еще и в ядро — прямо скажем: жизнь не готовила.

Еще я не был готов к нынешним реалиям в плане стандартов и их поддержки — история с ACPICA оказалась несколько глубже и интереснее, чем простое заимствование.

Мы пришли с миром

В исходном коде FreeBSD есть каталоги contrib, в которых находится код, разрабатываемый вне проекта FreeBSD. Сразу уточню, что речь не про пакеты или порты а про саму базовую ОС.

Каталогов contrib несколько, первый находится прямо в корне и содержит внешний исходный код утилит и библиотек, используемых в базовой системе:

Второй contrib находится в каталоге sys и содержит заимствованный код, используемый непосредственно в ядре FreeBSD:

Именно тут находится виновник торжества, в каталоге:

/usr/src/sys/contrib/dev/acpica

Место правки — файл components/events/evregion.c, как видите сохранен даже оригинальный комментарий.

Сама правка, ее причины и суть детально описаны в первой части:

/*
     * These address spaces do not need a call to _REG, since the ACPI
     * specification defines them as: "must always be accessible". Since
     * they never change state (never become unavailable), no need to ever
     * call _REG on them. Also, a DataTable is not a "real" address space,
     * so do not call _REG. September 2018.
*/
if (
        //(SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) ||
        (SpaceId == ACPI_ADR_SPACE_SYSTEM_IO) ||
        (SpaceId == ACPI_ADR_SPACE_DATA_TABLE))
 {
        return_VOID;
 }

Единственное заметное отличие — использование другой нотации в именовании переменных.

После правки ядро необходимо пересобрать и установить:

make buildkernel KERNCONF=ALEXS
make installkernel

Напоминаю, что правка находится в подсистеме ACPICA, которая не отделяема и не выгружаема — т. е. является монолитной частью ядра FreeBSD.

ACPICA

Мне стало интересно, что же это за неведомое чудо, написанное на чистом Си и вот так запросто кочующее из одной операционной системы в другую.

Недолгое гугление вывело на сайт проекта и репозиторий на Github:

The ACPI Component Architecture (ACPICA) project provides an open-source operating system-independent implementation of the Advanced Configuration and Power Interface specification (ACPI).

Думаю по адресу сайта нетрудно догадаться, что отвечает за ACPICA компания Intel, которая славится своей любовью к лоббированию и закрытым прошивкам.

А теперь самое интересное, так выглядит оригинальный код с проблемным местом, которое я исправлял:

Как видите никаких отличий нет и даже сам комментарий с пояснением, как оказалось, был перенесен в ядро Linux именно отсюда и без изменений.

А затем этот же код от Intel был внесен и в кодовую базу FreeBSD.

Причем кода в этом удивительном проекте от Intel довольно много.

Выводы

Лично для меня вся эта история с ACPICA оказалась полным сюрпризом, получается что есть некая часть ядра с достаточно объемной кодовой базой, разрабатываемая извне как проекта FreeBSD так и Linux.

Разрабатываемая огромной корпорацией и автономно. А в конечные проекты FreeBSD и ядра Linux (и полагаю еще в ряд открытых ОС) этот код попадает в полу‑автоматическом режиме и без существенных правок.

Во такой он — прекрасный новый мир.

Оригинал как обычно в нашем блоге, копия на Дзене.