Как делают устройство посимвольного ввода-вывода или символьную специальную работу файлов?

Я не вижу потребности в веб-разработчике использовать Windows для разработки. Хотя Вы все еще захотите платформу Windows для тестирования. Какой btw Вы не включаете в Вас список инструментов. У Вас должна быть своего рода автоматизированная тестовая среда для нескольких различных платформ, но это может все быть сделано в VM.

Я не использовал бы IDE как Spket, но изучу один из основных и (обычно говорящий) очень программируемые редакторы: emacs, vi, или затмение.

Я также использовал бы Подвижный на стороне клиента для всего кода.

22
02.03.2018, 09:31
5 ответов

Они - на самом деле просто это - интерфейсы. Закодированный "главным" и "незначительным" числом они предоставляют рычаг ядру.

Они прибывают в две разновидности (хорошо, три, но именованные каналы вне объема этого объяснения на данный момент): Устройства посимвольного ввода-вывода и Блочные устройства.

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

Устройства посимвольного ввода-вывода являются вещами как звуковые карты или видеокарты или устройства ввода данных как клавиатура и мышь.

В каждом случае, когда ядро загружает корректный драйвер (или во время начальной загрузки, или с помощью программ как udev) это сканирует различные шины, чтобы видеть, присутствуют ли какие-либо устройства, обработанные тем драйвером на самом деле, в системе. Если так, это настраивает устройство, которое 'слушает' на соответствующем главном/незначительном числе.

(Например, Цифровой сигнальный процессор первой звуковой карты, найденной Вашей системой, получает главную/незначительную пару числа 14/3; второе добирается 14,35, и т.д.),

Это до udev для создания записи в /dev именованный dsp поскольку устройство посимвольного ввода-вывода отметило главные 14 незначительных 3.

(В значительно более старом или версиях минимального места Linux, /dev/ может не быть динамично загружен, но просто содержать все возможные файлы устройств статически.)

Затем когда программа пространства пользователя пытается получить доступ к файлу, это отмечено как 'символьный специальный файл' с соответствующим главным/незначительным числом (например, Ваш аудиоплеер, пытающийся отправить цифровое аудио в /dev/dsp ), ядро знает, что эти данные должны быть переданы через драйвер, к которому присоединено главное/незначительное число; по-видимому, упомянутый драйвер знает, что сделать с ним в свою очередь.

19
27.01.2020, 19:42
  • 1
    1. Таким образом, главные/незначительные числа походят на порты? –  bernie2436 03.05.2012, 18:38
  • 2
    2. Таким образом, когда доступ программ какой-либо файл, ядро читает эти специальные интерфейсы, чтобы учиться, должна ли программа получить прерывания от конкретного устройства? Исключая: если программа открывает файл слова, она читает устройство посимвольного ввода-вывода специальный файл, чтобы знать, что программа должна ответить на ввод с клавиатуры? –  bernie2436 03.05.2012, 18:45
  • 3
    1) Несколько. Это - аналогия бедного человека, но это сделает. –  Shadur 03.05.2012, 20:21
  • 4
    2) Вы пропускаете приблизительно три или четыре слоя абстракции там. Программа Вы открываетесь, текстовый файл ни со знает, ни заботится, каково устройство клавиатуры. Связь с используемым оборудованием происходит любой через эмулятор терминала (если Вы находитесь в консольном режиме), или через X слоев события (если Вы находитесь в графическом режиме), любой из которых будет слушать клавиатуру и другие диски и решает, что, во всяком случае, перейти к программе. Я суммирую довольно сложную многоуровневую систему здесь; Вы могли бы преуспеть для чтения в X-оконной системе в целом. –  Shadur 03.05.2012, 20:24
  • 5
    Обратите внимание также, что на некоторых разновидностях UN*X существуют символьные специальные файлы для устройств хранения; чтение или запись в специальный файл превращаются в чтение или запись к последовательности блоков на устройстве. (В последних версиях FreeBSD это - единственные специальные файлы для устройств хранения; нет никакого блока специальных файлов.) –   22.10.2014, 03:34
  • 6
    Обратите внимание также, что на некоторых разновидностях UN*X существуют символьные специальные файлы для устройств хранения; чтение или запись в специальный файл превращаются в чтение или запись к последовательности блоков на устройстве. (В последних версиях FreeBSD это - единственные специальные файлы для устройств хранения; нет никакого блока специальных файлов.) –   22.10.2014, 03:34

Каждый файл, устройство или иначе, поддерживает 6 основных операций в VFS:

  1. Открытый
  2. Закрыть
  3. Читать
  4. Записать
  5. Искать
  6. Сказать

Кроме того, файлы устройств поддерживают Управление ввода-вывода, которое позволяет другие разные операции, не покрытые первыми 6.

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

echo 'foo' > /dev/some/char
sed ... < /dev/some/char
10
27.01.2020, 19:42
[116018] Символьные устройства могут быть созданы модулями ядра (или самим ядром). При создании устройства создатель предоставляет указатели на функции, которые реализуют обработку стандартных вызовов, таких как open, read и т.д. Затем ядро Linux связывает эти функции с символьным устройством, поэтому, например, когда пользовательское приложение вызывает функцию read() в файле символьного устройства, это приводит к syscall'у, а затем ядро направляет этот вызов на функцию чтения, указанную при создании драйвера. Пошаговое руководство по созданию символьного устройства [116377] здесь [116378], вы можете создать пример проекта и пройти через него с помощью отладчика, чтобы понять, как создается объект устройства и когда вызываются обработчики[116019].
1
27.01.2020, 19:42

«Символ за раз» является неправильным термином (как и идея о том, что символьные устройства обязательно не поддерживают поиск и определение). На самом деле, "блочные" (т.е. строго ориентированные на запись, такие как ленточный накопитель*) устройства должны быть символьными устройствами. Такова же идея, что символьное устройство обязательно должно быть недоступным для поиска - драйверы символьных устройств определяют полную структуру file_operations, которая может свободно определять llseek или нет в зависимости от того, поддерживает ли устройство операцию. Символьные устройства, которые большинство людей считают примерами, — это null, urandom, устройства TTY, звуковая карта, мышь и т. д., которые невозможно найти из-за специфики этих устройств, но /dev/vcs, /dev/fb0 и /dev/kmem также являются символьными устройствами, и все они доступны для поиска.

Как я уже упоминал, драйвер символьного устройства определяет структуру file_operations, которая имеет указатели функций для всех операций, которые кто-то может захотеть вызвать с файлом — поиск, чтение, запись, ioctl и т. д. — и каждая из них вызывается один раз, когда соответствующий системный вызов выполняется при открытом файле устройства. И поэтому чтение и запись могут делать со своими аргументами все, что захотят — они могут отказаться принимать запись, которая слишком велика, или писать только то, что подходит; он может прочитать только данные, соответствующие одной записи, а не все запрошенное количество байтов.

Итак, что такое блочное устройство? По сути, блочные устройства представляют собой дисковые накопители. Ни одно другое устройство (кроме виртуальных дисков, таких как ramdisk и loopback) не является блочным устройством.Они интегрированы в систему запросов ввода/вывода, уровень файловой системы, систему буферов/кэшей и систему виртуальной памяти таким образом, что символьные устройства не интегрированы, даже когда вы обращаетесь, например. /dev/sda из пользовательского процесса. Даже «необработанные устройства», упомянутые на этой странице в качестве исключения , являются символьными устройствами.

*Некоторые системы UNIX реализовали так называемый «режим с фиксированными блоками», который позволяет ядру группировать и разделять запросы ввода-вывода, чтобы соответствовать сконфигурированным границам блоков более или менее таким же образом, как это делается для дисковых накопителей. как блочное устройство. Символьное устройство необходимо для «режима переменного блока», который сохраняет границы блока из пользовательской программы, поскольку одиночный вызов write(2) записывает один блок, а одиночный вызов read(2) возвращает один блок. Поскольку переключение режимов теперь реализовано как ioctl, а не как отдельный файл устройства, используется символьное устройство. Ленточные накопители с переменной записью в основном не поддерживают поиск, поскольку поиск включает подсчет количества записей, а не количества байтов, а собственная операция поиска реализована как ioctl.

5
27.01.2020, 19:42

Минимальная работоспособность file_operationsпример

Когда вы видите минимальный пример, все становится очевидным.

Ключевые идеи:

  • file_operationsсодержит обратные вызовы для каждого системного вызова, связанного с файлом
  • mknod <path> c <major> <minor>создает символьное устройство, которое использует этиfile_operations
  • для символьных устройств, которые динамически распределяют номера устройств (норма во избежание конфликтов ), найдите номер с помощьюcat /proc/devices

character_device.koмодуль ядра:

#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <uapi/linux/stat.h> /* S_IRUSR */

#define NAME "lkmc_character_device"

MODULE_LICENSE("GPL");

static int major;

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    size_t ret;
    char kbuf[] = {'a', 'b', 'c', 'd'};

    ret = 0;
    if (*off == 0) {
        if (copy_to_user(buf, kbuf, sizeof(kbuf))) {
            ret = -EFAULT;
        } else {
            ret = sizeof(kbuf);
            *off = 1;
        }
    }
    return ret;
}

static const struct file_operations fops = {
   .owner = THIS_MODULE,
   .read = read,
};

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

static void myexit(void)
{
    unregister_chrdev(major, NAME);
}

module_init(myinit)
module_exit(myexit)

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

insmod /character_device.ko
dev="lkmc_character_device"
major="$(grep "$dev" /proc/devices | cut -d ' ' -f 1)"
mknod "/dev/$dev" c "$major" 0
cat /dev/lkmc_character_device
# => abcd
rm /dev/lkmc_character_device
rmmod character_device

GitHub QEMU + Buildroot восходящей ветки с шаблонным кодом, чтобы запустить его:

Более сложные примеры:

7
27.01.2020, 19:42

Теги

Похожие вопросы