Глава 5. Фреймворк SYSINIT | FreeBSD Documentation Portal
Description: Фреймворк SYSINIT
Keywords: SYSINIT,framework,Terminology

# Глава 5. Фреймворк SYSINIT

Этот перевод может быть устаревшим. Для того, чтобы помочь с переводом, пожалуйста, обратитесь к Сервер переводов FreeBSD.

SYSINIT — это фреймворк для общего механизма сортировки и диспетчеризации вызовов. В настоящее время FreeBSD использует его для динамической инициализации ядра. SYSINIT позволяет изменять порядок, добавлять, удалять и заменять подсистемы ядра FreeBSD во время линковки ядра при загрузке ядра или его модулей, без необходимости редактировать статически упорядоченные маршруты инициализации и перекомпилировать ядро. Эта система также позволяет модулям ядра (в настоящее время называемым KLD) компилироваться, линковаться и инициализироваться отдельно во время загрузки, а также загружаться позже, когда система уже работает. Это достигается с помощью «компоновщика ядра» (kernel linker) и «наборов компоновщика» (linker sets).

## 5.1. Терминология

Набор компоновщика (Linker Set)

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

## 5.2. Работа механизма SYSINIT

SYSINIT полагается на способность компоновщика объединять статические данные, объявленные в нескольких местах исходного кода программы, в единый непрерывный блок данных. Этот метод компоновщика называется "набором компоновщика" (linker set). SYSINIT использует два набора компоновщика для поддержки двух наборов данных, содержащих порядок вызова, функцию и указатель на данные, передаваемые этой функции для каждого члена этих наборов данных.

SYSINIT использует два приоритета для упорядочивания функций при выполнении. Первый приоритет — это идентификатор подсистемы, задающий общий порядок вызова функций SYSINIT. Предварительно объявленные идентификаторы находятся в <sys/kernel.h> в перечислении `sysinit_sub_id`. Второй используемый приоритет — это порядок элементов внутри подсистемы. Предварительно объявленные порядки элементов подсистемы находятся в <sys/kernel.h> в перечислении `sysinit_elem_order`.

В настоящее время существует два варианта использования `SYSINIT`: вызов функций при загрузке системы и загрузке модулей ядра, а также вызов функций при завершении работы системы и выгрузке модулей ядра. Подсистемы ядра часто используют `SYSINIT` при старте системы для инициализации структур данных. Например, подсистема планирования процессов использует `SYSINIT` для инициализации структуры данных очереди выполнения. Драйверы устройств должны избегать прямого использования `SYSINIT()`. Вместо этого драйверы реальных устройств, входящих в структуру шины, должны использовать `DRIVER_MODULE()`, который предоставляет функцию для обнаружения устройства и, если оно присутствует, его инициализации. Этот макрос выполняет несколько действий, специфичных для устройств, а затем вызывает `SYSINIT()` самостоятельно. Для псевдоустройств, которые не входят в структуру шины, следует использовать `DEV_MODULE()`.

## 5.3. Использование SYSINIT

### 5.3.1. Интерфейс

#### 5.3.1.1. Заголовки

    <sys/kernel.h>

#### 5.3.1.2. Макросы

    SYSINIT(uniquifier, subsystem, order, func, ident)
    SYSUNINIT(uniquifier, subsystem, order, func, ident)

### 5.3.2. Запуск

Макрос `SYSINIT()` создаёт необходимые данные SYSINIT в наборе данных инициализации системы, чтобы SYSINIT мог отсортировать и выполнить функцию при запуске системы и загрузке модуля. `SYSINIT()` принимает уникальный идентификатор, который SYSINIT использует для идентификации конкретных данных вызова функции, порядок подсистемы, порядок элемента подсистемы, функцию для вызова и данные для передачи в функцию. Все функции должны принимать аргумент в виде константного указателя.

Пример 1. Пример `SYSINIT()`

    #include <sys/kernel.h>

    void foo_null(void *unused)
    {
            foo_doo();
    }
    SYSINIT(foo, SI_SUB_FOO, SI_ORDER_FOO, foo_null, NULL);

    struct foo foo_voodoo = {
            FOO_VOODOO;
    }

    void foo_arg(void *vdata)
    {
            struct foo *foo = (struct foo *)vdata;
            foo_data(foo);
    }
    SYSINIT(bar, SI_SUB_FOO, SI_ORDER_FOO, foo_arg, &foo_voodoo);

Обратите внимание, что `SI_SUB_FOO` и `SI_ORDER_FOO` должны быть в перечислениях `sysinit_sub_id` и `sysinit_elem_order`, как упоминалось выше. Можно использовать существующие значения или добавить свои в эти перечисления. Также можно использовать математические операции для точной настройки порядка выполнения SYSINIT. В этом примере показан SYSINIT, который должен выполняться непосредственно перед SYSINIT, обрабатывающими настройку параметров ядра.

Пример 2. Пример настройки порядка `SYSINIT()`

    static void
    mptable_register(void *dummy __unused)
    {

    	apic_register_enumerator(&mptable_enumerator);
    }

    SYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST,
        mptable_register, NULL);

### 5.3.3. Выключение системы

Макрос `SYSUNINIT()` ведёт себя аналогично макросу `SYSINIT()`, за исключением того, что добавляет данные SYSINIT в набор данных завершения работы SYSINIT.

Пример 3. Пример `SYSUNINIT()`

    #include <sys/kernel.h>

    void foo_cleanup(void *unused)
    {
            foo_kill();
    }
    SYSUNINIT(foobar, SI_SUB_FOO, SI_ORDER_FOO, foo_cleanup, NULL);

    struct foo_stack foo_stack = {
            FOO_STACK_VOODOO;
    }

    void foo_flush(void *vdata)
    {
    }
    SYSUNINIT(barfoo, SI_SUB_FOO, SI_ORDER_FOO, foo_flush, &foo_stack);

Изменено: 17 мая 2026 г. by Vladlen Popolitov

Назад
Главная
Далее