Pull to refresh

Comments 58

Хм. Осталось сделать в модулях ядра Linux соответствующие «стандартные» ioctl-ы, и можно продвигать обратную совместимость с ОС Фантом. :)
Верно. Но есть более полезный (и более простой организационно) заход для этого упражнения. Напишу позже.
хочется предположить, что установка/чтение свойств — процесс редкий

Установка/чтение свойств — может быть и редкий процесс. Но ioctl — это же не только установка/чтение свойств. Это же универсальный интерфейс для выполнения драйвером обслуживающим файл произвольных действий с передачей произвольных данных.

можно сделать общую команду (напр mode), которая управляет параметрами любого драйвера, не зная о нём ничего

Устройства, а не драйвера?

static property_t proplist[] =
{
    { pt_int32, "leds", 0, &leds, 0, (void *)set_leds, 0, 0 },
};
...

static void set_leds(void)
...

А как set_leds узнает, которому из устройств обслуживаемых драйвером предназначена команда?
он же на fd меппится. что open позволяет открыть, то и предмет. захочет драйвер дать открыть не устройство, а себя вообще — будут проперти драйвера.
Это же универсальный интерфейс для выполнения драйвером обслуживающим файл произвольных действий с передачей произвольных данных.


Увы, да. Можно и это поддержать, сделав какой-нибудь ioread( fd, ioctl_id, void *, size_t ), но, кажется, перебор.
Кстати, разумный механизм — это через ioctl только переключать стейт, а ввод-вывод всё равно делать через read/write.

set_property( fd, "iomode", "palette" ); 
write( fd, &palette, sizeof(palette) );
UFO just landed and posted this here
Это тоже правда, но в этом смысле весь позикс — одна сплошная дыра. Впрочем, не давайте fd другому потоку, и всё. Ну или мьютекс возьмите — многопоточное программирование предполагает управление параллельным доступом через примитивы синхронизации, так или иначе.
UFO just landed and posted this here
Мне кажется, что современный тренд в том, чтобы через ioctl настраивать прямую связь юзерспейса с железом — IOMMU, аппаратные очереди в адресном пространстве процесса, а дальше они сами разберутся, без ядра.
Ну это наверное ближе к духу QNX, чем Linux.
Это ближе к духу OpenOnload, HSA, OpenCL и т.п., всё оно работает на линуксе.
Ну да, я как раз хотел сказать что такие штуки в основном используются для общения с GPU. Это в общем нарушает принципы UNIX, и делается в основном ради увеличения производительности в ущерб стабильности.
Это в общем нарушает принципы UNIX

Какие именно и каким образом?

делается в основном ради увеличения производительности в ущерб стабильности

Ради увеличения производительности — да, в ущерб стабильности — нет.
Какие именно и каким образом?

Унифицированный доступ к устройствам. Если взять например framebuffer device, то любой драйвер поддерживает стандартный API + какие-то свои расширения. А значит моя программа может открыть /dev/fb0, замапить его себе в память и не задумываясь больше ни о чем работать-работать-работать.
Если же мне нужны вычисления на GPU — мне надо недостаточно открыть /dev/dri/card0. Мне надо взять условный libopencl для моей конкретной видеокарты, потому что именно он знает как правильно замапить память видеокарты и как посылать ей комманды которые специфичны именно для неё.

Ради увеличения производительности — да, в ущерб стабильности — нет.

Ну лично мне неюутно от мысли что любое приложение в юзерспейсе может слать любые команды моей видеокарте. Ведь в данном случае ядро не может контролировать что делается с видеокартой.
Если же мне нужны вычисления на GPU — мне надо недостаточно открыть /dev/dri/card0. Мне надо взять условный libopencl для моей конкретной видеокарты, потому что именно он знает как правильно замапить память видеокарты и как посылать ей комманды которые специфичны именно для неё.

Но вы же не пытаетесь выводить во фреймбуфер текстовым редактором или командой sed? Условный libopencl — это такой же инструмент для вычислений на gpu. При желании из него можно сделать классическую программу-фильтр, принимающую на вход текст кернела и входные данные и выводящую результаты.

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

Частично может — с помощью правильно сконфигурированного IOMMU оно может защитить память не принадлежащую процессу от доступа со стороны видеокарты от имени и по поручению этого процесса. В остальном приложение взаимодействует, в основном, с фирмварью, которую можно считать специализированным «ядром» для видеокарты.
Но вы же не пытаетесь выводить во фреймбуфер текстовым редактором или командой sed?

Я могу как минимум попытаться. Например я похожим образом несколько раз проверял, работает ли фрейбуфер в моем устройстве или определял какой файл фрейбуффера какому экрану соотвествует. Я даже могу сделать скриншот с помощью команды cat.

Частично может — с помощью правильно сконфигурированного IOMMU оно может защитить память не принадлежащую процессу от доступа со стороны видеокарты от имени и по поручению этого процесса.

Да, IOMMU (там где оно есть) может защитить память других процессов. Но если приложение решит поиграться с клоками видеокарты, например? Или с управлением скоростью куллеров? Фирмварь видеокарты же не сможет определить от кого приходят команды.

Я просто веду к тому, что драйвера стали вылазить за пределы ядра. Пропал общий интерфейс. Сначала это произошло с принтерами и сканерами, из-за чего мы имеем огромный CUPS и несколько алтернативных паков «драйверов» к нему. Теперь то же самое происходит с GPU.

Кстати, вот ещё пример почему это плохо. В ядре есть CryptoAPI, который позволяет добавлять свои модули, например для аппаратного ускорения шифрования. Допустим, я хочу использовать OpenCL что бы ускорить AES. Если бы весь интерфейс к видеокарте жил в ядре — проблем бы небыло. Я пишу код для GPU, мой модуль аттачится к DRM, выставляет наружу интерфейс для CryptoAPI и все счастливы. Ядро (и все драйвера) может шифровать с аппаратным ускорением, юзерспейс может шифровать с аппаратным ускорением, все счастливы.
При текущем же дизайне мы максимум что можем сделать — это модуль для openssl. Все ядерные клиенты остаются в пролете.
Я даже могу сделать скриншот с помощью команды cat.

Точно так же вы можете запустить какой-нибудь стандартный 2х2=4 на gpu.

Но если приложение решит поиграться с клоками видеокарты, например?

Не решит, не даст ему никто.

Фирмварь видеокарты же не сможет определить от кого приходят команды.

Сможет. Она же участвует в создании пользовательских очередей. Там же весь дизайн нацелен на то, чтобы протащить нужный контекст до нужного места. Без этого ни один здравомыслящий архитектор не предложил бы такую технологию.

Кстати, вот ещё пример почему это плохо. В ядре есть CryptoAPI, который позволяет добавлять свои модули, например для аппаратного ускорения шифрования.

У линуксового CryptoAPI не файловый интерфейс. См. http://lwn.net/Articles/410763/, особенно комментарии про socat и т.п.

Ядро (и все драйвера) может шифровать с аппаратным ускорением, юзерспейс может шифровать с аппаратным ускорением, все счастливы.

И тут не всё гладко. Некоторым драйверам (PPTP например) требуется синхронный интерфейс, потому что они хотят заниматься криптографией из SoftIRQ. Не всякий криптопровайдер на это способен.

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

Не всё укладывается в общий файловый интерфейс, и не всё что удаётся уложить — красиво и эффективно.
Кажется, любой юниксосрач можно завершить этой мудрой мыслью:

Не всё укладывается в общий файловый интерфейс, и не всё что удаётся уложить — красиво и эффективно.


:)
в принципе, да — но, всё же, смысл существования ОС — в виртуализации железа. смысл opengl — обобщить и унифицировать интерфейсы и capabilities железа. обойти его — и ОС превращается в толстый и дорогой MS DOS.
Зачем, если технически это одно и то же: пробросить из/в юзерспейс какие-то буфера, их размеры и команду. А там уж — в зав-ти от вида команды — будь то rw или ioctl трактуем содержимое буфера.
Ну тогда надо будет делать пару ioread/iowrite что нифига не удобно, потому что есть немало вызовов где делается и чтение и запись. Например, педерать параметры команды и получить обратно какие-то результаты. Делать ioread и затем iowrite не выход, потому что появляется состояние и все связанные с ним проблемы. Поэтому опять приходим к нужности единого вызова ioctl. Короче, Томпсон, Ритчи и Ко были не дураки.
Или тот же самый DeviceIoControl:

BOOL WINAPI DeviceIoControl(
  _In_        HANDLE       hDevice,
  _In_        DWORD        dwIoControlCode,
  _In_opt_    LPVOID       lpInBuffer,
  _In_        DWORD        nInBufferSize,
  _Out_opt_   LPVOID       lpOutBuffer,
  _In_        DWORD        nOutBufferSize,
  _Out_opt_   LPDWORD      lpBytesReturned,
  _Inout_opt_ LPOVERLAPPED lpOverlapped
);


Ну да, это прямой аналог ioctl из мира Windows. Трудно придумать более универсальный и гибкий способ общаться с ядром.
Не перебор. Это критически важный функционал. Любой драйвер, цепляющийся к сети и регулирующий прохождение трафика, предполагает, что в него во время настройки будет загружена куча правил. И эти правила не имеют имён. В лучшем случае они имеют генерируемые на лету числовые идентификаторы, в худшем — каждое правило идентифицируется лишь собственным содержанием.
UFO just landed and posted this here
Это правда.

Но посмотрите на жизнь с другой стороны.

Языка Си больше нет.

Вся современная разработка — переносимые языки с динамическим рантаймом, и никаких дефайнов там нет. Они всё равно мепятся в ioctl через ж. автогеном, и всё равно в рантайме.
UFO just landed and posted this here
Надеюсь, Вы знаете, на кой хрен Вы до сих пор с С++. Я вижу только две причины: исторические наслоения и те 10% кода, которые правда надо оптимизировать.
UFO just landed and posted this here
Решение требует задачи. Нет смысла выбирать ЯП абстрактно.

Однако, как 20 лет назад был универсальный ответ «не знаешь, на чём писать — пиши на Си (++)», так сегодня дефолтным ЯП является Ява, если ты юниксоид и С#, если ты хочешь жить и умереть в виндах. Инфраструктура поддержки этих двух ЯП несравнима ни с чем (включая си).

Если тебе нужно скриптик или страничку — похрен. Хоть на коболе.
UFO just landed and posted this here
Вы о себе или об индустрии? Строка кода на С++ в 4-5 раз дороже строки на Яве.
UFO just landed and posted this here
Можно пример-два? Не срача ради. ПМСМ, чем дальше, тем меньше разницы.
UFO just landed and posted this here
Ага, как раз про ауто думал сегодня, читая вот эту статью:
https://habrahabr.ru/company/luxoft/blog/278313/
UFO just landed and posted this here
Она написана на GPU, который занимается графикой, и на динамическом языке, на котором пишут AI. Си там — тонкая прослойка между ними, которая написана на Си только в силу стереотипности мышления разрабов. Технически в этом давно нет смысла.

Скучно это. Я в 90-х наблюдал истерику разработчиков на ассемблере, которым говорили, что асм умер и всё пишут на си. Потом истерику сишников с переходом на яву. Сегодня истерика явистов с переходом на ФП языки.

(И да, если вы ещё истерите по поводу фразы «си умер в пользу явы», вы проспали поколение — уже пора рассказывать, что ява — это легаси.)
Сегодня истерика явистов с переходом на ФП языки.

Хде истерика-то? На самом деле, явистам пофиг, часть ФП языков приходит в JVM экосистему, то есть является ещё одним инструментов явистов, которым это интересно, а большая часть существующих проектов никогда с явы не слезет, а значит тем явистам, которым не интересно на ближайшие лет 10-15 работы на явы не сильно убавиться. Да, и большинство явистов признает недостатки явы (просто она довольно удобна для некоторых задач энтерпрайза), так что каких-то истерик не ждите. Ну и потихонку ФП идет в java, я говорю о ряде библиотек, которые позволяют вносить ФП конструкции в джаву.
Всё верно. Но иногда люди эмоциональны. :)
Черт, а я уже столько лет пишу на несуществующем языке.
Надо завтра черкануть в мэйлинг лист линуксового ядра, чтобы тоже прекращали использовать несуществующий язык и переходили на РНР.
Я всего лет 7 назад помогал в исправлении ошибки в коде на языке Кобол. Кобол. Знаете такой? Джермейн, IBM360, середина прошлого века, слышали? Работает! Используют!

Так и Си.

Некоторым не везёт. Некоторые балдеют. Я вот пишу на Си уже тридцать лет, нехреново умею это делать и определённое удовольствие от этого испытываю.

Но не нужно путать неизбежность (хрен куда Линукс с Си спрыгнет, это ясно), собственные сексуальные предпочтения (писать на си — разновидность онанизма) и ЦЕЛЕСООБРАЗНОСТЬ.

Писать на Си в 99% случаев — НЕЦЕЛЕСООБРАЗНО. Потому что 3.14здец как дорого и 3.14здец как ненадёжно. Это я говорю вам как человек, который этим языком занимается 30 (тридцать) лет и как создатель нескольких крупнейших софтверных систем в России, типа Я.Маркета и инфраструктуры портала Яндекса, Юлмарта и ещё с сотни проектов помельче.

И как человек, написавший ОС почти в одно рыло.

Так вот — почти ПОЛОВИНА кода ОС посвящена заморочкам, которые из Си делают что-то жизнеспособное.

Всякие референс каунты (ручной ad hoc garbage collection), очереди, списки, эмуляции виртуальных методов, мемберофы, проверки и затычки.

Другое дело, что в некоторых проектах деваться тупо некуда — gcc поддержан на таком количестве платформ, что его ещё долго не получится забыть. Ну и есть реально тесные платформы типа avr, при паре килобайт памяти не разгуляешься.

Но это всё — уже история. Как Кобол. Лямбды уверенно вытесняют указатели на функцию.
Всякие референс каунты (ручной ad hoc garbage collection)
По-вашему, ОС с ядром на языке со сборкой мусора будет в чём-то лучше конкурентов? Оберон вон как-то не взлетел.
Это не очень эффективно, но хочется предположить, что установка/чтение свойств — процесс редкий, и потому упираться в его скорость смысла немного, да и само переключение контекста при вызове стоит немало.

В принципе, если properties метод — просто обертки над ioctl кодами, то это не проблема — в случае необходимости можно реализовать вызов напрямую.
Никаких дефайнов с номерами, только имена.

Никаких имен. Только GUID, только хардкор.

Применение строковых имен чревато их конфликтами, перепутыванием прописных и строчных букв, потерей пробелов, знаков препинания и т.д. Кроме того, обработка C-строк менее эффективна, чем обработка данных фиксированной длины, таких как GUID.
Никаких бинарных данных, только строки

Ну и это ни к чему. Появляется парсинг строк, диагностика синтаксических и прочих ошибок, уязвимости парсера. Эта современная мода на текстовое представление всего и вся — она годится только для малых объемов данных и в тех случаях, где производительность некритична. Даже XML-файл прочитать на несколько десятков мегабайт может не каждая библиотека.
Ну я бы не сказал, что ioctl прям вот всегда процесс редкий. Если какой-нибудь сервер принимает кучу коротких входящих соединений, то там соотношение Ioctl и fread вполне может быть близко к 1/1.
Properties получаются альтернативой sysfs (где тоже строковые ключи и значения), а не ioctl.
реализую похожую модель, но в приложении к другому объекту.
с другой стороны, возможно, правильная схема именно fs:

/dev/tty0
/dev/tty0.speed
/dev/tty0.stop_bits

Ага, ага. Понятно во что оно мигрирует:
— Сделать «невидимые» атрибуты, например начинающиеся с _ или $ в стиле MS
— Сделать систему безопасности, каждый атрибут должен иметь список на чтение-запись-просмотр
— Сделать иерархическую систему атрибутов, объединив похожие атрибуты в каталоги атрибутов по типу Registry
— Невидимость атрибутов можно реализовать через систему безопасности атрибутов и каталоги атрибутов конечно же
— Сделать «метаатрибуты», в которых будут хранится свойства атрибутов, в частности их тип, по образцу SNMP OID

P.S. В принципе тут уже упомянули sysfs. Надо только добавить, что заниматься этим должен обязательно systemd.

[sarcasm mode off]
ls /proc

это, в общем, тот же путь, да.
/proc — помойка, в той части, которая к PID не привязана. Раскидывание свойств по устройствам — это sysfs.
Любой нейминг без централизованного управления приходит в состояние помойки. Вопрос времени. :)
В целом — согласен. Есть разница в том, что sysfs — это ,, проекция'' реальных структур ядра в файловую систему. Т.е. основа в виде каталогов всегда будет осмысленной. А в /proc каждый кидал что и как хотел.
Да, это помогает. Должно, по крайней мере. Семантика диктует структуру.

AVDictionary из FFmpeg вспомнились и сразу проблемы (которые, в принципе, все выше перечислены):


  • опечатки, как в именах, так и в значениях
  • конфликт имён и типов значений
  • отсутствие проверки со стороны компилятора и
  • как следствие — валится в рантайме в самый неподходящий момент

Кстати, интерфейс словаря можно и тут добавить — что бы за вызов сразу пачку параметров изменить/получить. В FFmpeg после вызова в словаре остаются записи, которые примениться не смогли.

проблема только с именами, и то — частичная. рантайм вернёт ошибку. Всё остальное есть у ioctl в полный рост. никто и никак не проверит бинарный номер и формат структуры. а так же выравнивание полей.
Sign up to leave a comment.

Articles