Вопрос или проблема
Функция cfsetospeed в musl и glibc просто устанавливает скорость для поля c_cflag структуры termios, хотя и после некоторых проверок битов и операций с использованием CBAUD.
Вот реализация musl
int cfsetospeed(struct termios *tio, speed_t speed)
{
if (speed & ~CBAUD) {
errno = EINVAL;
return -1;
}
tio->c_cflag &= ~CBAUD;
tio->c_cflag |= speed;
return 0;
}
Почему это не может сделать ядро? Или вызывающая сторона, если на то пошло?
Является ли CBAUD специфичным для платформы? “Зависит от реализации”?
Какое-то специальное значение, о котором знают только поставщики libc?
Поиск CBAUD дал ответ.
Довольно интересно.
Похоже, CBAUD — это всего лишь одна из множества возможностей, используемых при установке поля c_cflag
Никогда не инициализируйте поле c_cflag (или любое другое поле) напрямую; вы всегда должны использовать побитовые операторы AND, OR и NOT, чтобы устанавливать или очищать биты в полях. Разные версии операционных систем (и даже патчи) могут и используют биты по-разному…
Функции cfsetospeed(3) и cfsetispeed(3) предоставляются для установки
скорости передачи в структуре termios независимо от интерфейса операционной
системы.
Полный текст и таблица констант для поля c_cflag находятся здесь
https://wiki.control.fel.cvut.cz/pos/cv5/doc/serial.html
Ответ или решение
Функция cfsetospeed
, присутствующая в библиотеках C, таких как glibc и musl, отвечает за установку скорости передачи данных в структуре termios
. Несмотря на её наличие в библиотеках стандартной библиотеки C, а не в кодовой базе ядра Linux, это решение продиктовано несколькими важными факторами, связанными с архитектурой операционной системы, гибкостью и портируемостью.
Почему cfsetospeed
находится в glibc и не обрабатывается в ядре
-
Абстракция аппаратных деталей: Ядро операционной системы отвечает за управление аппаратными ресурсами и выполнение низкоуровневых операций. Однако конкретные реализации настройки параметров, таких как скорости передачи данных, могут существенно различаться в зависимости от конкретного аппаратного обеспечения и его возможностей. Функция
cfsetospeed
выступает в роли абстракции, позволяющей разработчикам инкапсулировать логику установки скорости без необходимости углубляться в детали работы с различными аппаратными решениями. -
Гибкость и стандартность: Использование стандартной библиотеки для таких операций упрощает создание переносимых приложений, работающих на различных операционных системах и архитектурах. Это позволяет разработчикам полагаться на однородный интерфейс для доступа к функциональности, вместо того чтобы писать уникальный код для каждой целевой платформы.
-
Проверка корректности данных: В приведенном выражении кода реализуется проверка входного значения
speed
с использованием макросаCBAUD
, который ограничивает возможные значения, которые может принимать скорость передачи. Это позволяет предотвратить ошибки, связанные с установкой неверных значений, что значительно улучшает стабильность программного обеспечения.
Почему это не выполняется вызывающей стороной
-
Сложность управления флагами: Установка битов в члене структуры
c_cflag
требует применения битовых операций для корректного наложения флагов. Если бы этот процесс выполнялся вызывающей стороной, это увеличивало бы вероятность ошибок и несоответствий между различными реализациями и версиями ОС. -
Методология работы с конфигурациями: Задача управления флагами и конфигурационными параметрами, такими как скорость передачи данных, требует хорошо определенной и согласованной стратегии. Разлучение этой логики от вызывающего кода позволяет обеспечить единообразие и делает код более читаемым и поддерживаемым.
Платформенная специфичность CBAUD
Макрос CBAUD
действительно является платформенно специфичным, так как различные аппаратные решения могут по-разному интерпретировать и использовать биты в c_cflag
. Разработчикам рекомендуется не инициализировать c_cflag
напрямую, а использовать специальные функции, такие как cfsetospeed
, которые знают о местных нюансах и индивидуальных особенностях платформы.
Заключение
Функция cfsetospeed
в glibc и musl иллюстрирует важность отделения логики программного обеспечения от аппаратных деталей, улучшая таким образом переносимость и упрощая разработку приложений. Это также подчеркивает необходимость в стандартизации интерфейсов для работы с системными уровнями, благодаря чему разработчики могут сосредоточиться на функциональности своих приложений, не отвлекаясь на детали взаимодействия с аппаратным обеспечением. Таким образом, хранение этой логики в библиотеке C вместо ядра или в вызывающем коде является не только разумным, но и необходимым шагом для обеспечения стабильности и универсальности при разработке программного обеспечения.