KasperskyOS Community Edition 1.1

Содержание

[Topic api][Topic libkos]

Общие сведения о библиотеке libkos

Ядро KasperskyOS имеет ряд служб для управления дескрипторами, потоками, памятью, процессами, IPC-каналами, ресурсами ввода-вывода и т.д. Для доступа к службам используется библиотека libkos.

Библиотека libkos

Библиотека libkos состоит из двух частей:

  • Первая часть предоставляет собой C-интерфейс для доступа к службам ядра KasperskyOS. Она доступна через заголовочные файлы, находящиеся в директории coresrv.
  • Вторая часть библиотеки libkos предоставляет абстракции примитивов синхронизации, объектов и очередей. Она также содержит функции-обертки для более простой аллокации памяти и работы с потоками. Заголовочные файлы второй части libkos находятся в директории kos.

Библиотека libkos значительно упрощает использование служб ядра. Функции библиотеки libkos обеспечивают корректную упаковку IPC-сообщения и выполнение системных вызовов. Взаимодействие других библиотек (включая libc) с ядром происходит через библиотеку libkos.

Для использования службы ядра KasperskyOS нужно подключить соответствующий этой службе заголовочный файл библиотеки libkos. Например, для доступа к методам менеджера ввода-вывода (IO Manager) нужно подключить файл io_api.h:

#include <coresrv/io/io_api.h>

Файлы, используемые библиотекой libkos

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

  • Файлы на языке IDL (idl-описания). Содержат описания интерфейсов служб. Используются IPC-транспортом для корректной упаковки сообщений.
  • Заголовочные файлы ядра. Эти файлы включаются библиотекой libkos.

Пример

Менеджер ввода-вывода (IO Manager) представлен для пользователя следующими файлами:

  • coresrv/io/io_api.h – заголовочный файл библиотеки libkos;
  • services/io/IO.idl – idl-описание менеджера ввода-вывода;
  • io/io_dma.h, io/io_irq.h – заголовочные файлы ядра.
В начало
[Topic libkos_intro][Topic api_memory]

Состояния памяти

Каждая страница виртуальной памяти может быть свободна (free), зарезервирована (reserved) или передана (committed).

Переход из свободного состояния в зарезервированное называется резервированием (аллокацией). Предварительное резервирование памяти (без передачи физических страниц) позволяет приложению заранее разметить свое адресное пространство. Обратный переход из зарезервированного в свободное состояние называется освобождением памяти.

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

Переходы между состояниями страницы памяти

В начало
[Topic api_memory_states]

KnVmAllocate()

Функция объявлена в файле coresrv/vmm/vmm_api.h.

void *KnVmAllocate(void *addr, rtl_size_t size, int flags);

Функция резервирует диапазон физических страниц, задаваемый параметрами addr и size. Если указан флаг VMM_FLAG_COMMIT, функция резервирует и передает страницы за один вызов.

Параметры:

  • addr – странично-выровненный базовый физический адрес; если задать addr равным 0, система сама выберет свободный участок физической памяти;
  • size – размер участка памяти в байтах (должен быть кратен размеру страницы);
  • flags – флаги аллокации.

Функция возвращает базовый виртуальный адрес зарезервированного участка. Если зарезервировать участок памяти невозможно, функция возвращает RTL_NULL.

Флаги аллокации

В параметре flags можно использовать следующие флаги (vmm/flags.h):

  • VMM_FLAG_RESERVE – обязательный флаг;
  • VMM_FLAG_COMMIT – позволяет за один вызов KnVmAllocate() резервировать и передать страницы памяти в "ленивом" режиме;
  • VMM_FLAG_LOCKED – используется совместно с VMM_FLAG_COMMIT; позволяет сразу передать физические страницы памяти вместо "ленивой" передачи;
  • VMM_FLAG_WRITE_BACK, VMM_FLAG_WRITE_THROUGH, VMM_FLAG_WRITE_COMBINE, VMM_FLAG_CACHE_DISABLE и VMM_FLAG_CACHE_MASK – управляют кэшированием страниц памяти;
  • VMM_FLAG_READ, VMM_FLAG_WRITE, VMM_FLAG_EXECUTE и VMM_FLAG_RWX_MASK – атрибуты защиты памяти;
  • VMM_FLAG_LOW_GUARD и VMM_FLAG_HIGH_GUARD – добавление защитной страницы перед и после выделенной памяти соответственно;
  • VMM_FLAG_GROW_DOWN – определение направления доступа к памяти (от старших адресов к младшим).

Допустимые комбинации атрибутов защиты памяти:

  • VMM_FLAG_READ – разрешено чтение содержимого страницы;
  • VMM_FLAG_READ | VMM_FLAG_WRITE – разрешено чтение и изменение содержимого страницы;
  • VMM_FLAG_READ | VMM_FLAG_EXECUTE – разрешено чтение и выполнение содержимого страницы;
  • VMM_FLAG_RWX_MASK или VMM_FLAG_READ | VMM_FLAG_WRITE | VMM_FLAG_EXECUTE – полный доступ к содержимому страницы (эти записи эквивалентны).

Пример

coredump->base = KnVmAllocate(RTL_NULL, vmaSize,

VMM_FLAG_READ | VMM_FLAG_RESERVE |

VMM_FLAG_WRITE | VMM_FLAG_COMMIT |

VMM_FLAG_LOCKED);

При необходимости можно изменить заданные атрибуты защиты участка памяти с помощью функции KnVmProtect().

В начало
[Topic kn_vm_allocate]

KnVmCommit()

Функция объявлена в файле coresrv/vmm/vmm_api.h.

Retcode KnVmCommit(void *addr, rtl_size_t size, int flags);

Функция передает диапазон физических страниц, задаваемый параметрами addr и size.

Все передаваемые страницы должны быть предварительно зарезервированы.

Параметры:

  • addr – странично-выровненный базовый виртуальный адрес участка памяти;
  • size – размер участка памяти в байтах (должен быть кратен размеру страницы);
  • flags – параметр не используется (укажите флаг VMM_FLAG_LOCKED в значении параметра для обеспечения совместимости).

В случае успешной передачи страниц функция возвращает rcOk.

В начало
[Topic kn_vm_commit]

KnVmDecommit()

Функция объявлена в файле coresrv/vmm/vmm_api.h.

Retcode KnVmDecommit(void *addr, rtl_size_t size);

Функция освобождает диапазон страниц (переводит их в зарезервированное состояние).

Параметры:

  • addr – странично-выровненный базовый виртуальный адрес участка памяти;
  • size – размер участка памяти в байтах (должен быть кратен размеру страницы).

В случае успешного освобождения страниц функция возвращает rcOk.

В начало
[Topic kn_vm_decommit]

KnVmProtect()

Функция объявлена в файле coresrv/vmm/vmm_api.h.

Retcode KnVmProtect(void *addr, rtl_size_t size, int newFlags);

Функция изменяет атрибуты защиты зарезервированных или переданных страниц памяти.

Параметры:

  • addr – странично-выровненный базовый виртуальный адрес участка памяти;
  • size – размер участка памяти в байтах (должен быть кратен размеру страницы);
  • newFlags – новые атрибуты защиты.

В случае успешного изменения атрибутов защиты функция возвращает rcOk.

Допустимые комбинации атрибутов защиты памяти:

  • VMM_FLAG_READ – разрешено чтение содержимого страницы;
  • VMM_FLAG_READ | VMM_FLAG_WRITE – разрешено чтение и изменение содержимого страницы;
  • VMM_FLAG_READ | VMM_FLAG_EXECUTE – разрешено чтение и выполнение содержимого страницы;
  • VMM_FLAG_RWX_MASK или VMM_FLAG_READ | VMM_FLAG_WRITE | VMM_FLAG_EXECUTE – полный доступ к содержимому страницы (эти записи эквивалентны).
В начало
[Topic kn_vm_protect]

KnVmUnmap()

Функция объявлена в файле coresrv/vmm/vmm_api.h.

Retcode KnVmUnmap(void *addr, rtl_size_t size);

Функция освобождает участок памяти.

Параметры:

  • addr – странично-выровненный адрес участка памяти;
  • size – размер участка памяти.

В случае успешного освобождения страниц функция возвращает rcOk.

В начало
[Topic kn_vm_unmap]

Аллокация памяти

В этом разделе

KosMemAlloc()

KosMemAllocEx()

KosMemFree()

KosMemGetSize()

KosMemZalloc()

В начало
[Topic api_memory_alloc]

KosMemAlloc()

Функция объявлена в файле kos/alloc.h.

void *KosMemAlloc(rtl_size_t size);

Функция выделяет (резервирует и передает) участок памяти размером size байт.

Функция возвращает указатель на выделенный участок или RTL_NULL, если память не удалось выделить.

Память, выделенная с помощью функции KosMemAlloc(), имеет следующие флаги аллокации: VMM_FLAG_READ | VMM_FLAG_WRITE, VMM_FLAG_RESERVE, VMM_FLAG_COMMIT, VMM_FLAG_LOCKED. Чтобы выделить память с другими флагами аллокации, используйте функцию KnVmAllocate().

В начало
[Topic kos_mem_alloc]

KosMemAllocEx()

Функция объявлена в файле kos/alloc.h.

void *KosMemAllocEx(rtl_size_t size, rtl_size_t align, int zeroed);

Функция аналогична KosMemAlloc(), но при этом имеет дополнительные параметры:

  • align – выравнивание участка памяти в байтах (степень двойки);
  • zeroed – нужно ли заполнить участок памяти нулями (1 – заполнить, 0 – не заполнять).
В начало
[Topic kos_mem_alloc_ex]

KosMemFree()

Функция объявлена в файле kos/alloc.h.

void KosMemFree(void *ptr);

Функция освобождает участок памяти, выделенный с помощью функции KosMemAlloc(), KosMemZalloc() или KosMemAllocEx().

  • ptr – указатель на освобождаемый участок памяти.
В начало
[Topic kos_mem_free]

KosMemGetSize()

Функция объявлена в файле kos/alloc.h.

rtl_size_t KosMemGetSize(void *ptr);

Функция возвращает размер (в байтах) участка памяти, выделенного с помощью функции KosMemAlloc(), KosMemZalloc() или KosMemAllocEx().

  • ptr – указатель на участок памяти.
В начало
[Topic kos_mem_get_size]

KosMemZalloc()

Функция объявлена в файле kos/alloc.h.

void *KosMemZalloc(rtl_size_t size);

Функция аналогична KosMemAlloc(), но при этом заполняет выделяемый участок памяти нулями.

В начало
[Topic kos_mem_zalloc][Topic libkos_threads]

KosThreadCallback()

Прототип callback-функции объявлен в файле kos/thread.h.

typedef void KosThreadCallback(KosThreadCallbackReason reason);

/* Аргумент callback-функции */

typedef enum KosThreadCallbackReason {

KosThreadCallbackReasonCreate,

KosThreadCallbackReasonDestroy,

} KosThreadCallbackReason;

При создании нового потока все зарегистрированные callback-функции будут вызваны с аргументом KosThreadCallbackReasonCreate, при завершении – с аргументом KosThreadCallbackReasonDestroy.

В начало
[Topic kos_thread_callback]

KosThreadCallbackRegister()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadCallbackRegister(KosThreadCallback *callback);

Функция регистрирует пользовательскую callback-функцию. При создании и завершении потока будут вызваны все зарегистрированные callback-функции.

В начало
[Topic kos_thread_callback_register]

KosThreadCallbackUnregister()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadCallbackUnregister(KosThreadCallback *callback);

Функция дерегистрирует (удаляет из списка вызываемых) пользовательскую callback-функцию.

В начало
[Topic kos_thread_callback_unregister]

KosThreadCreate()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadCreate(Tid *tid,

rtl_uint32_t priority,

rtl_uint32_t stackSize,

ThreadRoutine routine,

void *context,

int suspended);

Функция создает новый поток.

Входные параметры:

  • priority – приоритет, должен быть в интервале от 0 до 31; доступны следующие константы приоритета: ThreadPriorityLowest (0), ThreadPriorityNormal (15) и ThreadPriorityHighest (31);
  • stackSize – размер стека;
  • routine – функция, которая будет выполняться в потоке;
  • context – аргумент, который будет передан в функцию routine;
  • suspended – позволяет создать поток в приостановленном состоянии (1 – создать приостановленный, 0 – не приостановленный).

Выходные параметры:

  • tid – идентификатор созданного потока.

Пример

int main(int argc, char **argv)

{

Tid tidB;

Tid tidC;

Retcode rcB;

Retcode rcC;

static ThreadContext threadContext[] = {

{.ddi = "B", .deviceName = "/pci/bus0/dev2/fun0/DDI_B"},

{.ddi = "C", .deviceName = "/pci/bus0/dev2/fun0/DDI_C"},

};

rcB = KosThreadCreate(&tidB, ThreadPriorityNormal,

ThreadStackSizeDefault,

FbHotplugThread,

&threadContext[0], 0);

if (rcB != rcOk)

ERR("Failed to start thread %s", threadContext[0].ddi);

rcC = KosThreadCreate(&tidC, ThreadPriorityNormal,

ThreadStackSizeDefault,

FbHotplugThread,

&threadContext[1], 0);

if (rcC != rcOk)

ERR("Failed to start thread %s", threadContext[1].ddi);

/* Ожидание завершения потоков */

...

}

В начало
[Topic kos_thread_create]

KosThreadCurrentId()

Функция объявлена в файле kos/thread.h.

Tid KosThreadCurrentId(void);

Функция запрашивает TID вызывающего потока.

В случае успеха функция возвращает идентификатор потока (TID).

В начало
[Topic kos_thread_current_id]

KosThreadExit()

Функция объявлена в файле kos/thread.h.

void KosThreadExit(rtl_int32_t exitCode);

Функция принудительно завершает текущий поток с кодом выхода exitCode.

В начало
[Topic kos_thread_exit]

KosThreadGetStack()

Функция объявлена в файле kos/thread.h.

void *KosThreadGetStack(Tid tid, rtl_uint32_t *size);

Функция получает стек потока с идентификатором tid.

Выходной параметр size содержит размер стека.

В случае успеха функция возвращает указатель на начало стека.

В начало
[Topic kos_thread_get_stack]

KosThreadOnce()

Функция объявлена в файле kos/thread.h.

typedef int KosThreadOnceState;

Retcode KosThreadOnce(KosThreadOnceState *onceControl,

void (* initRoutine) (void));

Функция позволяет вызвать заданную процедуру initRoutine в точности один раз, даже при вызове из нескольких потоков.

Параметр onceControl предназначен для контроля однократного вызова процедуры.

При успешном вызове процедуры, а также если она уже была вызвана ранее, функция KosThreadOnce() возвращает rcOk.

В начало
[Topic kos_thread_once]

KosThreadResume()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadResume(Tid tid);

Функция возобновляет поток с идентификатором tid, созданный в приостановленном состоянии.

В случае успеха функция возвращает rcOk.

В начало
[Topic kos_thread_resume]

KosThreadSleep()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadSleep(rtl_uint32_t mdelay);

Функция приостанавливает выполнение текущего потока на mdelay миллисекунд.

В случае успеха функция возвращает rcOk.

В начало
[Topic kos_thread_sleep]

KosThreadSuspend()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadSuspend(Tid tid);

Функция необратимо останавливает текущий поток, не завершая его.

Параметр tid должен быть равен идентификатору текущего потока (ограничение текущей имплементации).

В случае успеха функция возвращает rcOk.

В начало
[Topic kos_thread_suspend]

KosThreadTerminate()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadTerminate(Tid tid, rtl_int32_t exitCode);

Функция завершает поток вызывающего процесса. Параметр tid задает идентификатор потока.

Если tid указывает на текущий поток, то параметр exitCode задает код выхода потока.

В случае успеха функция возвращает rcOk.

В начало
[Topic kos_thread_terminate]

KosThreadTlsGet()

Функция объявлена в файле kos/thread.h.

void *KosThreadTlsGet(void);

Функция возвращает указатель на локальное хранилище потока (TLS) или RTL_NULL, если TLS отсутствует.

В начало
[Topic kos_thread_tls_get]

KosThreadTlsSet()

Функция объявлена в файле kos/thread.h.

Retcode KosThreadTlsSet(void *tls);

Функция задает адрес локального хранилища потока (TLS).

Входной аргумент tls содержит адрес TLS.

В начало
[Topic kos_thread_tls_set]

KosThreadWait()

Функция объявлена в файле kos/thread.h.

int KosThreadWait(rtl_uint32_t tid, rtl_uint32_t timeout);

Функция приостанавливает выполнение текущего потока до момента завершения потока с идентификатором tid или до истечения timeout миллисекунд.

Вызов KosThreadWait() с нулевым значением timeout аналогичен вызову KosThreadYield().

В случае успеха функция возвращает rcOk, в случае таймаута rcTimeout.

В начало
[Topic kos_thread_wait]

KosThreadYield()

Функция объявлена в файле kos/thread.h.

void KosThreadYield(void);

Функция передает выполнение вызвавшего ее потока следующему потоку.

Вызов KosThreadYield() аналогичен вызову KosThreadSleep() с нулевым значением mdelay.

В начало
[Topic kos_thread_yield][Topic api_handles]

KnHandleClose()

Функция объявлена в файле coresrv/handle/handle_api.h.

Retcode KnHandleClose(Handle handle);

Функция удаляет дескриптор handle.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

Удаление дескриптора не делает недействительными его предков и потомков (в отличие от отзыва дескриптора, который делает недействительными его потомков – см. KnHandleRevoke() и KnHandleRevokeSubtree()). Удаление дескриптора также не нарушает целостность дерева наследования дескрипторов. Место удаленного дескриптора занимает его предок – он становится непосредственным предком потомков удаленного дескриптора.

В начало
[Topic kn_handle_close]

KnHandleCreateBadge()

Функция объявлена в файле coresrv/handle/handle_api.h.

Retcode KnHandleCreateBadge(Notice notice, rtl_uintptr_t eventId,

void *context, Handle *handle);

Функция создает объект контекста передачи ресурса для контекста передачи ресурса context и настраивает приемник уведомлений notice на прием уведомлений об этом объекте. Приемник уведомлений настраивается на прием уведомлений о событиях, которые соответствуют флагам маски событий EVENT_OBJECT_DESTROYED и EVENT_BADGE_CLOSED.

Входной параметр eventId задает идентификатор записи вида "ресурс – маска событий" в приемнике уведомлений.

Выходной параметр handle содержит дескриптор объекта контекста передачи ресурса.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic kn_handle_create_badge]

KnHandleCreateUserObject()

Функция объявлена в файле coresrv/handle/handle_api.h.

Retcode KnHandleCreateUserObject(rtl_uint32_t type, rtl_uint32_t rights,

void *context, Handle *handle);

Функция создает дескриптор handle типа type с маской прав rights.

Параметр type может принимать значения от HANDLE_TYPE_USER_FIRST до HANDLE_TYPE_USER_LAST.

Макросы HANDLE_TYPE_USER_FIRST и HANDLE_TYPE_USER_LAST определены в заголовочном файле handle/handletype.h.

Параметр context задает контекст пользовательского ресурса. В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

Пример

Retcode ServerPortInit(ServerPort *serverPort)

{

Retcode rc = rcInvalidArgument;

Notice serverEventNotice;

rc = KnHandleCreateUserObject(HANDLE_TYPE_USER_FIRST, OCAP_HANDLE_SET_EVENT | OCAP_HANDLE_GET_EVENT,

serverPort, &serverPort->handle);

if (rc == rcOk) {

KosRefObject(serverPort);

rc = KnNoticeSubscribeToObject(serverEventNotice,

serverPort->handle,

EVENT_OBJECT_DESTROYED,

(rtl_uintptr_t) serverPort);

if (rc != rcOk) {

KosPutObject(serverPort);

KnHandleClose(serverPort->handle);

serverPort->handle = INVALID_HANDLE;

}

}

return rc;

}

В начало
[Topic kn_handle_create_user_object]

KnHandleRevoke()

Функция объявлена в файле coresrv/handle/handle_api.h.

Retcode KnHandleRevoke(Handle handle);

Функция удаляет дескриптор handle и отзывает всех его потомков.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

Отзыв дескрипторов не удаляет их, но через отозванные дескрипторы невозможно обращаться к ресурсам. Любая функция, которая принимает дескриптор, завершается с ошибкой rcHandleRevoked, если эта функция вызывается с отозванным дескриптором.

В начало
[Topic kn_handle_revoke]

KnHandleRevokeSubtree()

Функция объявлена в файле coresrv/handle/handle_api.h.

Retcode KnHandleRevokeSubtree(Handle handle, Handle badge);

Функция отзывает дескрипторы, которые образуют поддерево наследования дескриптора handle.

Корневым узлом поддерева наследования является дескриптор, который порожден передачей дескриптора handle в ассоциации с объектом контекста передачи ресурса badge.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

Отзыв дескрипторов не удаляет их, но через отозванные дескрипторы невозможно обращаться к ресурсам. Любая функция, которая принимает дескриптор, завершается с ошибкой rcHandleRevoked, если эта функция вызывается с отозванным дескриптором.

В начало
[Topic kn_handle_revoke_subtree]

nk_get_badge_op()

Функция объявлена в файле nk/types.h.

static inline

nk_err_t nk_get_badge_op(const nk_handle_desc_t *desc,

nk_rights_t operation,

nk_badge_t *badge);

Функция извлекает указатель на контекст передачи ресурса badge из транспортного контейнера дескриптора desc, если в маске прав, которая помещена в транспортном контейнере дескриптора desc, установлены флаги operation.

В случае успеха функция возвращает NK_EOK, иначе возвращает код ошибки.

В начало
[Topic nk_get_badge_op]

nk_is_handle_dereferenced()

Функция объявлена в файле nk/types.h.

static inline

nk_bool_t nk_is_handle_dereferenced(const nk_handle_desc_t *desc);

Функция возвращает отличное от нуля значение, если дескриптор в транспортном контейнере дескриптора desc получен в результате операции разыменования дескриптора.

Функция возвращает нуль, если дескриптор в транспортном контейнере дескриптора desc получен в результате операции передачи дескриптора.

В начало
[Topic nk_is_handle_dereferenced]

Управление дескрипторами

Для управления дескрипторами используются функции менеджера дескрипторов (Handle Manager) и подсистемы уведомлений (Notification Subsystem).

Менеджер дескрипторов представлен для пользователя следующими файлами:

  • coresrv/handle/handle_api.h – заголовочный файл библиотеки libkos;
  • services/handle/Handle.idl – описание IPC-интерфейса менеджера дескрипторов на языке IDL.

Подсистема уведомлений представлена для пользователя следующими файлами:

  • coresrv/handle/notice_api.h – заголовочный файл библиотеки libkos;
  • services/handle/Notice.idl – описание IPC-интерфейса подсистемы уведомлений на языке IDL.

В этом разделе

Маска прав дескриптора

Создание дескрипторов

Передача дескрипторов

Разыменование дескрипторов

Отзыв дескрипторов

Уведомление о состоянии ресурсов

Удаление дескрипторов

Пример использования OCap

В начало
[Topic handles_manage]

Маска прав дескриптора

Маска прав дескриптора имеет размер 32 бита и состоит из общей и специальной части. Общая часть описывает права, неспецифичные для любых ресурсов (флаги этих прав определены в заголовочном файле services/ocap.h). Например, в общей части находится флаг OCAP_HANDLE_TRANSFER, который определяет право на передачу дескриптора. Специальная часть описывает права, специфичные для пользовательского или системного ресурса. Флаги прав специальной части для системных ресурсов определены в заголовочном файле services/ocap.h. Структура специальной части для пользовательских ресурсов определяется поставщиком ресурсов с использованием макроса OCAP_HANDLE_SPEC(), который определен в заголовочном файле services/ocap.h. Поставщику ресурсов необходимо экспортировать публичные заголовочные файлы с описанием структуры специальной части.

При создании дескриптора системного ресурса маска прав задается ядром KasperskyOS, которое применяет маски прав из заголовочного файла services/ocap.h. Применяются маски прав с именами вида OCAP_*_FULL (например, OCAP_IOPORT_FULL, OCAP_TASK_FULL, OCAP_FILE_FULL) и вида OCAP_IPC_* (например, OCAP_IPC_SERVER, OCAP_IPC_LISTENER, OCAP_IPC_CLIENT).

При создании дескриптора пользовательского ресурса маска прав задается пользователем.

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

В начало
[Topic libkos_handles_rights]

Создание дескрипторов

Дескрипторы пользовательских ресурсов создаются поставщиками ресурсов. Для создания дескрипторов пользовательских ресурсов используется функция KnHandleCreateUserObject(), которая объявлена в заголовочном файле coresrv/handle/handle_api.h.

handle_api.h (фрагмент)

/**

* Функция создает дескриптор handle типа type с маской прав rights.

* Параметр type может принимать значения от HANDLE_TYPE_USER_FIRST до

* HANDLE_TYPE_USER_LAST. Макросы HANDLE_TYPE_USER_FIRST и HANDLE_TYPE_USER_LAST

* определены в заголовочном файле handletype.h. Параметр context задает контекст

* пользовательского ресурса.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnHandleCreateUserObject(rtl_uint32_t type, rtl_uint32_t rights,

void *context, Handle *handle);

Контекст пользовательского ресурса – данные, позволяющие поставщику ресурса идентифицировать ресурс и его состояние, когда запрашивается доступ к ресурсу другими программами. В общем случае это набор разнотипных данных (структура). Например, для файла контекст может включать имя, путь, положение курсора. Контекст пользовательского ресурса используется в качестве контекста передачи ресурса или совместно с несколькими контекстами передачи ресурса.

Параметр type функции KnHandleCreateUserObject() зарезервирован для возможного использования в будущем и не влияет на ее поведение, но должен принимать значение из интервала, указанного в комментарии к функции.

О маске прав дескриптора см. "Маска прав дескриптора".

В начало
[Topic handles_create]

Передача дескрипторов

Общие сведения

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

Один дескриптор может быть передан многократно одной или нескольким программам. Каждая передача порождает нового потомка переданного дескриптора на стороне принимающей программы. Программа может передавать дескрипторы, которые она получила от других программ или ядра KasperskyOS (при создании дескрипторов системных ресурсов). Поэтому у дескриптора может быть несколько поколений потомков. Иерархия порождения дескрипторов для каждого ресурса хранится в ядре KasperskyOS в виде дерева наследования дескрипторов.

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

Условия для передачи дескрипторов

Чтобы программы могли передавать дескрипторы между собой, должны выполняться следующие условия:

  1. Между программами создан IPC-канал.
  2. Политика безопасности решения (security.psl) разрешает взаимодействие программ.
  3. Реализованы интерфейсные методы для передачи дескрипторов.
  4. Программа-клиент получила идентификатор службы (RIID) программы-сервера с методами для передачи дескрипторов.

Интерфейсные методы для передачи дескрипторов объявляются в IDL-описании с входными (in) и/или выходными (out) параметрами типа Handle. Методы с входными параметрами типа Handle предназначены для передачи дескрипторов от программы-клиента программе-серверу. Методы с выходными параметрами типа Handle предназначены для передачи дескрипторов от программы-сервера программе-клиенту. Для одного метода может быть объявлено не более семи входных и семи выходных параметров типа Handle.

Пример IDL-описания, где объявлены интерфейсные методы для передачи дескрипторов:

package IpcTransfer

interface {

PublishResource1(in Handle handle, out UInt32 result);

PublishResource7(in Handle handle1, in Handle handle2,

in Handle handle3, in Handle handle4,

in Handle handle5, in Handle handle6,

in Handle handle7, out UInt32 result);

OpenResource(in UInt32 ID, out Handle handle);

}

Для каждого параметра типа Handle компилятор NK генерирует в структурах запросов *_req и/или ответов *_res поле типа nk_handle_desc_t (далее также транспортный контейнер дескриптора). Этот тип объявлен в заголовочном файле nk/types.h и представляет собой структуру, состоящую из трех полей: поля дескриптора handle, поля маски прав дескриптора rights и поля контекста передачи ресурса badge.

Контекст передачи ресурса

Контекст передачи ресурса – данные, позволяющие программе-серверу идентифицировать ресурс и его состояние, когда запрашивается доступ к ресурсу через потомков переданного дескриптора. В общем случае это набор разнотипных данных (структура). Например, для файла контекст передачи может включать имя, путь, положение курсора. Программа-сервер получает указатель на контекст передачи ресурса при разыменовании дескриптора.

Программа-сервер независимо от того, является ли она поставщиком ресурса или нет, может ассоциировать каждую передачу дескриптора с отдельным контекстом передачи ресурса. Этот контекст передачи ресурса связывается только с теми потомками дескриптора (поддеревом наследования дескриптора), которые порождены в результате конкретной его передачи. Это позволяет определять состояние ресурса по отношению к отдельной передаче дескриптора этого ресурса. Например, в случае множественного доступа к одному файлу контекст передачи файла позволяет определить, какому именно открытию этого файла соответствует полученный запрос.

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

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

Если программа-клиент использует несколько разнотипных ресурсов программы-сервера, контексты передачи ресурсов (или контексты пользовательских ресурсов, если они используются в качестве контекстов передачи ресурсов) должны быть типизированными объектами KosObject. Это нужно, чтобы программа-сервер могла проверить, что программа-клиент при использовании ресурса передала в интерфейсный метод дескриптор того ресурса, который соответствует этому методу. Такая проверка требуется, поскольку программа-клиент может ошибочно передать в интерфейсный метод дескриптор ресурса, который не соответствует этому методу. Например, программа-клиент получила дескриптор файла и передала его в интерфейсный метод для работы с томами.

Чтобы ассоциировать передачу дескриптора с контекстом передачи ресурса, программа-сервер помещает в поле badge структуры nk_handle_desc_t дескриптор объекта контекста передачи ресурса. Объект контекста передачи ресурса – объект, в котором хранится указатель на контекст передачи ресурса. Объект контекста передачи ресурса создается функцией KnHandleCreateBadge(), которая объявлена в заголовочном файле coresrv/handle/handle_api.h. Работа этой функции связана с подсистемой уведомлений о состоянии ресурсов, так как программе-серверу нужно знать, когда объект контекста передачи ресурса будет закрыт и прекратит свое существование. Эти сведения требуются программе-серверу, чтобы освободить или использовать повторно память, которая отведена для хранения контекста передачи ресурса.

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

Один объект контекста передачи ресурса может быть ассоциирован только с одной передачей дескриптора.

handle_api.h (фрагмент)

/**

* Функция создает объект контекста передачи ресурса для

* контекста передачи ресурса context и настраивает

* приемник уведомлений notice на прием уведомлений об

* этом объекте. Приемник уведомлений настраивается на

* прием уведомлений о событиях, которые соответствуют

* флагам маски событий OBJECT_DESTROYED и EVENT_BADGE_CLOSED.

* Входной параметр eventId задает идентификатор записи

* вида "ресурс – маска событий" в приемнике уведомлений.

* Выходной параметр handle содержит дескриптор объекта

* контекста передачи ресурса.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnHandleCreateBadge(Notice notice, rtl_uintptr_t eventId,

void *context, Handle *handle);

Упаковка данных в транспортный контейнер дескриптора

Для упаковки дескриптора, маски прав дескриптора и дескриптора объекта контекста передачи ресурса в транспортный контейнер дескриптора используется макрос nk_handle_desc(), который определен в заголовочном файле nk/types.h. Этот макрос принимает переменное число аргументов.

Если не передавать макросу ни одного аргумента, то в поле дескриптора handle структуры nk_handle_desc_t будет записано значение NK_INVALID_HANDLE.

Если передать макросу один аргумент, то этот аргумент интерпретируется как дескриптор.

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

Если передать макросу три аргумента, то первый аргумент интерпретируется как дескриптор, второй аргумент интерпретируется как маска прав дескриптора, третий аргумент интерпретируется как дескриптор объекта контекста передачи ресурса.

Извлечение данных из транспортного контейнера дескриптора

Для извлечения дескриптора, маски прав дескриптора и указателя на контекст передачи ресурса из транспортного контейнера дескриптора используются соответственно функции nk_get_handle(), nk_get_rights() и nk_get_badge_op() (или nk_get_badge()), которые определены в заголовочном файле nk/types.h. Функции nk_get_badge_op() и nk_get_badge() используются только при разыменовании дескрипторов.

Сценарии передачи дескрипторов

Сценарий передачи дескрипторов от программы-клиента программе-серверу включает следующие шаги:

  1. Передающая программа-клиент упаковывает дескрипторы и маски прав дескрипторов в поля структуры запросов *_req типа nk_handle_desc_t.
  2. Передающая программа-клиент вызывает интерфейсный метод для передачи дескрипторов программе-серверу. Этот метод выполняет системный вызов Call().
  3. Принимающая программа-сервер получает запрос, выполняя системный вызов Recv().
  4. Диспетчер на стороне принимающей программы-сервера вызывает метод, который соответствует запросу. Этот метод извлекает дескрипторы и маски прав дескрипторов из полей структуры запросов *_req типа nk_handle_desc_t.

Сценарий передачи дескрипторов от программы-сервера программе-клиенту включает следующие шаги:

  1. Принимающая программа-клиент вызывает интерфейсный метод для получения дескрипторов от программы-сервера. Этот метод выполняет системный вызов Call().
  2. Передающая программа-сервер получает запрос, выполняя системный вызов Recv().
  3. Диспетчер на стороне передающей программы-сервера вызывает метод, который соответствует запросу. Этот метод упаковывает дескрипторы, маски прав дескрипторов и дескрипторы объектов контекстов передачи ресурсов в поля структуры ответов *_res типа nk_handle_desc_t.
  4. Передающая программа-сервер отвечает на запрос, выполняя системный вызов Reply().
  5. На стороне принимающей программы-клиента интерфейсный метод возвращает управление. После этого принимающая программа-клиент извлекает дескрипторы и маски прав дескрипторов из полей структуры ответов *_res типа nk_handle_desc_t.

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

В начало
[Topic libkos_handles_transfer]

Разыменование дескрипторов

Разыменование дескриптора – это операция, при которой программа-клиент отправляет программе-серверу дескриптор, а программа-сервер получает указатель на контекст передачи ресурса, маску прав отправленного дескриптора и предка отправленного программой-клиентом дескриптора, которым программа-сервер уже владеет. Разыменование выполняется, когда программа-клиент, вызывая методы работы с ресурсом (например, чтения, записи, закрытия доступа), передает программе-серверу дескриптор, который был получен от этой программы-сервера при открытии доступа к ресурсу.

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

  1. Программа-клиент упаковывает дескриптор в поле структуры запросов *_req типа nk_handle_desc_t.
  2. Программа-клиент вызывает интерфейсный метод для отправки дескриптора программе-серверу с целью выполнения действий с ресурсом. Этот метод выполняет системный вызов Call().
  3. Программа-сервер принимает запрос, выполняя системный вызов Recv().
  4. Диспетчер на стороне программы-сервера вызывает метод, который соответствует запросу. Этот метод проверяет, что выполнена именно операция разыменования, а не передача дескриптора. Затем вызванный метод опционально проверяет, что права доступа разыменованного дескриптора (который отправлен программой-клиентом) разрешают запрашиваемые действия с ресурсом, и извлекает указатель на контекст передачи ресурса из поля структуры запросов *_req типа nk_handle_desc_t.

Для выполнения проверок программа-сервер использует функции nk_is_handle_dereferenced() и nk_get_badge_op(), которые объявлены в заголовочном файле nk/types.h.

types.h (фрагмент)

/**

* Функция возвращает отличное от нуля значение, если

* дескриптор в транспортном контейнере дескриптора

* desc получен в результате операции разыменования

* дескриптора. Функция возвращает нуль, если дескриптор

* в транспортном контейнере дескриптора desc получен

* в результате операции передачи дескриптора.

*/

static inline

nk_bool_t nk_is_handle_dereferenced(const nk_handle_desc_t *desc)

/**

* Функция извлекает указатель на контекст передачи ресурса

* badge из транспортного контейнера дескриптора desc,

* если в маске прав, которая помещена в транспортном

* контейнере дескриптора desc, установлены флаги operation.

* В случае успеха функция возвращает NK_EOK, иначе возвращает код ошибки.

*/

static inline

nk_err_t nk_get_badge_op(const nk_handle_desc_t *desc,

nk_rights_t operation,

nk_badge_t *badge)

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

В начало
[Topic libkos_handles_dereference]

Отзыв дескрипторов

Программа может отзывать потомков дескриптора, которым она владеет. Отзыв дескрипторов осуществляется согласно дереву наследования дескрипторов.

Отзыв дескрипторов не удаляет их, но через отозванные дескрипторы невозможно обращаться к ресурсам. Любая функция, которая принимает дескриптор, завершается с ошибкой rcHandleRevoked, если эта функция вызывается с отозванным дескриптором.

Отзыв выполняется функциями KnHandleRevoke() и KnHandleRevokeSubtree(), которые объявлены в заголовочном файле coresrv/handle/handle_api.h. Функция KnHandleRevokeSubtree() использует объект контекста передачи ресурса, который создается при передаче дескрипторов.

handle_api.h (фрагмент)

/**

* Функция удаляет дескриптор handle и отзывает всех его потомков.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnHandleRevoke(Handle handle);

/**

* Функция отзывает дескрипторы, которые образуют поддерево

* наследования дескриптора handle. Корневым узлом поддерева

* наследования является дескриптор, который порожден передачей

* дескриптора handle в ассоциации с объектом контекста

* передачи ресурса badge.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnHandleRevokeSubtree(Handle handle, Handle badge);

В начало
[Topic libkos_handles_revoke]

Уведомление о состоянии ресурсов

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

Функции подсистемы уведомлений объявлены в заголовочном файле coresrv/handle/notice_api.h. Подсистема уведомлений предусматривает использование масок событий.

Маска событий – значение, биты которого интерпретируются как события, которые должны отслеживаться или уже произошли. Маска событий имеет размер 32 бита и состоит из общей и специальной части. Общая часть описывает события, неспецифичные для любых ресурсов (флаги этих событий определены в заголовочном файле handle/event_descr.h). Например, в общей части находится флаг EVENT_OBJECT_DESTROYED, который определяет событие "прекращение существования ресурса". Специальная часть описывает события, специфичные для пользовательского ресурса. Структура специальной части определяется поставщиком ресурса с использованием макроса OBJECT_EVENT_SPEC(), который определен в заголовочном файле handle/event_descr.h. Поставщику ресурса необходимо экспортировать публичные заголовочные файлы с описанием структуры специальной части.

Сценарий получения уведомлений о событиях, которые происходят с ресурсом, включает следующие шаги:

  1. Функцией KnNoticeCreate() создается приемник уведомлений (объект, в котором накапливаются уведомления).
  2. В приемник уведомлений функцией KnNoticeSubscribeToObject() добавляются записи вида "ресурс – маска событий", чтобы настроить его на прием уведомлений о событиях, которые происходят с интересующими ресурсами. Набор отслеживаемых событий задается для каждого ресурса маской событий.
  3. Чтобы извлекать уведомления из приемника уведомлений, вызывается функция KnNoticeGetEvent().

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

notice_api.h (фрагмент)

/**

* Функция создает приемник уведомлений notice.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnNoticeCreate(Notice *notice);

/**

* Функция добавляет запись вида "ресурс – маска событий"

* в приемник уведомлений notice, чтобы он принимал уведомления о

* событиях, которые происходят с ресурсом object и соответствуют

* маске событий evMask. Входной параметр evId задает идентификатор

* записи, который назначается пользователем и используется, чтобы

* идентифицировать запись в полученных уведомлениях.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnNoticeSubscribeToObject(Notice notice,

Handle object,

rtl_uint32_t evMask,

rtl_uintptr_t evId);

/**

* Функция извлекает уведомления из приемника уведомлений notice,

* ожидая наступления событий в течение msec миллисекунд.

* Входной параметр countMax задает максимальное число

* уведомлений, которое может быть извлечено. Выходной параметр

* events содержит набор извлеченных уведомлений типа EventDesc.

* Выходной параметр count содержит число уведомлений, которые

* были извлечены.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnNoticeGetEvent(Notice notice,

rtl_uint64_t msec,

rtl_size_t countMax,

EventDesc *events,

rtl_size_t *count);

/* Структура уведомления */

typedef struct {

/* Идентификатор записи "ресурс – маска событий"

* в приемнике уведомлений */

rtl_uintptr_t eventId;

/* Маска событий, которые произошли. */

rtl_uint32_t eventMask;

} EventDesc;

/**

* Функция сигнализирует, что события из маски событий

* evMask произошли с пользовательским ресурсом object.

* Нельзя устанавливать флаги общей части маски событий,

* так как о событиях из общей части маски событий может

* сигнализировать только ядро KasperskyOS.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnNoticeSetObjectEvent(Handle object, rtl_uint32_t evMask);

В начало
[Topic libkos_handles_notification]

Удаление дескрипторов

Программа может удалять дескрипторы, которыми она владеет. Удаление дескриптора не делает недействительными его предков и потомков (в отличие от отзыва дескриптора, который делает недействительными его потомков). То есть через предков и потомков удаленного дескриптора обеспечивается доступ к ресурсу, который они идентифицируют. Также удаление дескриптора не нарушает целостность дерева наследования дескрипторов, которое относится к ресурсу, идентифицируемому этим дескриптором. Место удаленного дескриптора занимает его предок. То есть предок удаленного дескриптора становится непосредственным предком потомков удаленного дескриптора.

Удаление дескрипторов выполняется функцией KnHandleClose(), которая объявлена в заголовочном файле coresrv/handle/handle_api.h.

handle_api.h (фрагмент)

/**

* Функция удаляет дескриптор handle.

* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

*/

Retcode KnHandleClose(Handle handle);

В начало
[Topic libkos_handles_delete]

Пример использования OCap

В этой статье приведен сценарий использования OCap, в котором программа-сервер предоставляет следующие методы доступа к своим ресурсам:

  • OpenResource() – открытие доступа к ресурсу;
  • UseResource() – использование ресурса;
  • CloseResource() – закрытие доступа к ресурсу.

Программа-клиент использует эти методы.

IDL-описание интерфейсных методов:

package SimpleOCap

interface {

OpenResource(in UInt32 ID, out Handle handle);

UseResource(in Handle handle, in UInt8 param, out UInt8 result);

CloseResource(in Handle handle);

}

Сценарий включает следующие шаги:

  1. Поставщик ресурса создает контекст пользовательского ресурса и вызывает функцию KnHandleCreateUserObject() для создания дескриптора ресурса. Поставщик ресурса сохраняет дескриптор ресурса в контексте пользовательского ресурса.
  2. Клиент вызывает метод открытия доступа к ресурсу OpenResource().
    1. Поставщик ресурса создает контекст передачи ресурса и вызывает функцию KnHandleCreateBadge() для создания объекта контекста передачи ресурса и настройки приемника уведомлений на прием уведомлений о закрытии и прекращении существования объекта контекста передачи ресурса. Поставщик ресурса сохраняет дескриптор объекта контекста передачи ресурса и указатель на контекст пользовательского ресурса в контексте передачи ресурса.
    2. Поставщик ресурса, используя макрос nk_handle_desc(), упаковывает дескриптор ресурса, маску прав дескриптора и указатель на объект контекста передачи ресурса в транспортный контейнер дескриптора.
    3. Выполняется передача дескриптора от поставщика ресурса клиенту, в результате которой клиент получает потомка дескриптора, которым владеет поставщик ресурса.
    4. Вызов метода OpenResource() завершается успешно. Клиент извлекает дескриптор и маску прав дескриптора из транспортного контейнера дескриптора функциями nk_get_handle() и nk_get_rights() соответственно. Маска прав дескриптора не требуется клиенту для обращения к ресурсу и передается, чтобы клиент мог узнать свои права доступа к ресурсу.
  3. Клиент вызывает метод использования ресурса UseResource().
    1. Дескриптор, который получен от поставщика ресурса на шаге 2, используется в качестве аргумента метода UseResource(). Перед вызовом этого метода клиент упаковывает дескриптор в транспортный контейнер дескриптора макросом nk_handle_desc().
    2. Выполняется разыменование дескриптора, в результате которого поставщик ресурса получает указатель на контекст передачи ресурса.
    3. Поставщик ресурса, используя функцию nk_is_handle_dereferenced(), проверяет, что выполнена операция разыменования, а не передача дескриптора.
    4. Поставщик ресурса проверяет, что права доступа разыменованного дескриптора (который отправлен клиентом) разрешают запрашиваемую операцию над ресурсом, и извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора. Для этого поставщик ресурса использует функцию nk_get_badge_op(), которая извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора, если в полученной маске прав установлены флаги, соответствующие запрашиваемой операции.
    5. Поставщик ресурса, используя контекст передачи ресурса и контекст пользовательского ресурса, выполняет запрашиваемую клиентом операцию над ресурсом. Затем поставщик ресурса отправляет клиенту результат выполнения этой операции.
    6. Вызов метода UseResource() завершается успешно. Клиент получает результат выполнения операции над ресурсом.
  4. Клиент вызывает метод закрытия доступа к ресурсу CloseResource().
    1. Дескриптор, который получен от поставщика ресурса на шаге 2, используется в качестве аргумента метода CloseResource(). Перед вызовом этого метода клиент упаковывает дескриптор в транспортный контейнер дескриптора макросом nk_handle_desc(). После вызова метода CloseResource() клиент удаляет дескриптор функцией KnHandleClose().
    2. Выполняется разыменование дескриптора, в результате которого поставщик ресурса получает указатель на контекст передачи ресурса.
    3. Поставщик ресурса, используя функцию nk_is_handle_dereferenced(), проверяет, что выполнена операция разыменования, а не передача дескриптора.
    4. Поставщик ресурса, используя функцию nk_get_badge(), извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора.
    5. Поставщик ресурса отзывает дескриптор, которым владеет клиент, функцией KnHandleRevokeSubtree(). В качестве аргументов этой функции используются дескриптор ресурса, которым владеет поставщик ресурса, и дескриптор объекта контекста передачи ресурса. Поставщик ресурса получает доступ к этим дескрипторам через указатель на контекст передачи ресурса. (Технически не требуется отзывать дескриптор, которым владеет клиент, так как клиент его уже удалил. Но поставщик ресурса не может быть уверен в том, что клиент удалил дескриптор, поэтому выполняется отзыв).
    6. Вызов метода CloseResource() завершается успешно.
  5. Поставщик ресурса освобождает память, которая была выделена под контекст передачи ресурса и контекст пользовательского ресурса.
    1. Поставщик ресурса вызовом функции KnNoticeGetEvent() получает уведомление, что объект контекста передачи ресурса закрыт, и удаляет дескриптор объекта контекста передачи ресурса функцией KnHandleClose().
    2. Поставщик ресурса вызовом функции KnNoticeGetEvent() получает уведомление, что объект контекста передачи ресурса прекратил свое существование, и освобождает память, которая была выделена под контекст передачи ресурса.
    3. Поставщик ресурса удаляет дескриптор ресурса функцией KnHandleClose() и освобождает память, которая была выделена под контекст пользовательского ресурса.
В начало
[Topic libkos_handles_simple_scenario][Topic libkos_notice]

Маска событий

Маска событий – значение, биты которого интерпретируются как события, которые должны отслеживаться или уже произошли. Маска событий имеет размер 32 бита и состоит из общей и специальной части. Общая часть описывает события, неспецифичные для любых ресурсов (флаги этих событий определены в заголовочном файле handle/event_descr.h). Например, в общей части находится флаг EVENT_OBJECT_DESTROYED, который определяет событие "прекращение существования ресурса". Специальная часть описывает события, специфичные для пользовательского ресурса. Структура специальной части определяется поставщиком ресурса с использованием макроса OBJECT_EVENT_SPEC(), который определен в заголовочном файле handle/event_descr.h. Поставщику ресурса необходимо экспортировать публичные заголовочные файлы с описанием структуры специальной части.

В начало
[Topic event_mask]

EventDesc

Структура, описывающая уведомление, объявлена в файле coresrv/handle/notice_api.h.

typedef struct {

rtl_uintptr_t eventId;

rtl_uint32_t eventMask;

} EventDesc;

eventId – идентификатор записи "ресурс – маска событий" в приемнике уведомлений.

eventMaskмаска событий, которые произошли.

В начало
[Topic event_desc]

KnNoticeCreate()

Функция объявлена в файле coresrv/handle/notice_api.h.

Retcode KnNoticeCreate(Notice *notice);

Функция создает приемник уведомлений notice (объект, в котором накапливаются уведомления).

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic notice_create]

KnNoticeGetEvent()

Функция объявлена в файле coresrv/handle/notice_api.h.

Retcode KnNoticeGetEvent(Notice notice,

rtl_uint64_t msec,

rtl_size_t countMax,

EventDesc *events,

rtl_size_t *count);

Функция извлекает уведомления из приемника уведомлений notice, ожидая наступления событий в течение msec миллисекунд.

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

Выходной параметр events содержит набор извлеченных уведомлений типа EventDesc.

Выходной параметр count содержит число уведомлений, которые были извлечены.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

Пример

const int maxEventsPerNoticeCall = 10;

Retcode rc;

EventDesc events[maxEventsPerNoticeCall];

rtl_size_t eventCount;

rc = KnNoticeGetEvent(notice, INFINITE_TIMEOUT, rtl_countof(events),

&events[0], &eventCount);

В начало
[Topic notice_get_event]

KnNoticeSetObjectEvent()

Функция объявлена в файле coresrv/handle/notice_api.h.

Retcode KnNoticeSetObjectEvent(Handle object, rtl_uint32_t evMask);

Функция сигнализирует, что события из маски событий evMask произошли с ресурсом object.

Нельзя устанавливать флаги общей части маски событий, так как о событиях из общей части маски событий может сигнализировать только ядро KasperskyOS.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic notice_set_object_event]

KnNoticeSubscribeToObject()

Функция объявлена в файле coresrv/handle/notice_api.h.

Retcode KnNoticeSubscribeToObject(Notice notice,

Handle object,

rtl_uint32_t evMask,

rtl_uintptr_t evId);

Функция добавляет запись вида "ресурс – маска событий" в приемник уведомлений notice, чтобы он принимал уведомления о событиях, которые происходят с ресурсом object и соответствуют маске событий evMask.

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

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

Пример использования – см. KnHandleCreateUserObject().

В начало
[Topic notice_subscribe_to_object][Topic libkos_tasks]

EntityConnect()

Функция объявлена в заголовочном файле coresrv/entity/entity_api.h.

Retcode EntityConnect(Entity *cl, Entity *sr);

Функция соединяет процессы IPC-каналом. Для этого функция создает IPC-дескрипторы для процесса-клиента cl и процесса-сервера sr, а затем связывает дескрипторы друг с другом. Создаваемый канал будет включен в группу каналов по умолчанию (имя этой группы совпадает с именем процесса-сервера). Соединяемые процессы должны находиться в остановленном состоянии.

В случае успеха функция возвращает rcOk.

В начало
[Topic entity_connect]

EntityConnectToService()

Функция объявлена в заголовочном файле coresrv/entity/entity_api.h.

Retcode EntityConnectToService(Entity *cl, Entity *sr, const char *name);

Функция соединяет процессы IPC-каналом. Для этого функция создает IPC-дескрипторы для процесса-клиента cl и процесса-сервера sr, а затем связывает дескрипторы друг с другом. Создаваемый канал будет включен в группу каналов с именем name. Соединяемые процессы должны находиться в остановленном состоянии.

В случае успеха функция возвращает rcOk.

В начало
[Topic entity_connect_to_service]

EntityInfo

Структура EntityInfo, описывающая процесс, объявлена в файле if_connection.h.

typedef struct EntityInfo {

/* имя класса процесса */

const char *eiid;

/* максимальное число служб */

nk_iid_t max_endpoints;

/* информация о службах процесса */

const EndpointInfo *endpoints;

/* аргументы для передачи процессу при его запуске */

const char *args[ENTITY_ARGS_MAX + 1];

/* переменные окружения для передачи процессу при его запуске */

const char *envs[ENTITY_ENV_MAX + 1];

/* флаги процесса */

EntityFlags flags;

/* дерево компонентов процесса */

const struct nk_component_node *componentTree;

} EntityInfo;

typedef struct EndpointInfo {

char *name; /* полное квалифицированное имя службы */

nk_iid_t riid; /* идентификатор службы */

char *iface_name; /* имя интерфейса, который реализует служба */

} EndpointInfo;

typedef enum {

ENTITY_FLAGS_NONE = 0,

/* процесс сбрасывается при возникновении необработанного исключения */

ENTITY_FLAG_DUMPABLE = 1,

} EntityFlags;

В начало
[Topic entity_info]

EntityInit()

Функция объявлена в заголовочном файле coresrv/entity/entity_api.h.

Entity *EntityInit(const EntityInfo *info);

Функция создает процесс. Параметр info задает имя класса процесса и (опционально) его службы, аргументы и переменные окружения.

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

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

В случае ошибки функция возвращает RTL_NULL.

В начало
[Topic entity_init]

EntityInitEx()

Функция объявлена в заголовочном файле coresrv/entity/entity_api.h.

Entity *EntityInitEx(const EntityInfo *info, const char *name,

const char *path);

Функция создает процесс.

Параметр info задает имя класса процесса и (опционально) его службы, аргументы и переменные окружения.

Параметр name задает имя процесса. Если он имеет значение RTL_NULL, то в качестве имени процесса будет использоваться имя класса процесса из параметра info.

Параметр path задает имя исполняемого файла в ROMFS-образе решения. Если он имеет значение RTL_NULL, то в качестве имени файла будет использоваться имя класса процесса из параметра info.

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

В случае ошибки функция возвращает RTL_NULL.

В начало
[Topic entity_init_ex]

EntityRun()

Функция объявлена в заголовочном файле coresrv/entity/entity_api.h.

Retcode EntityRun(Entity *entity);

Функция запускает процесс, находящийся в остановленном состоянии. Процесс описывается структурой entity.

В случае успеха функция возвращает rcOk.

В начало
[Topic entity_run]

Динамическое создание каналов

В этом разделе

KnCmAccept()

KnCmConnect()

KnCmDrop()

KnCmListen()

NsCreate()

NsEnumServices()

NsPublishService()

NsUnPublishService()

В начало
[Topic libkos_ns_cm]

KnCmAccept()

Функция объявлена в файле coresrv/cm/cm_api.h.

Retcode KnCmAccept(const char *client, const char *service, rtl_uint32_t rsid,

Handle listener, Handle *handle);

Функция принимает запрос клиентского процесса на создание канала, полученный ранее с помощью вызова KnCmListen(). Функция вызывается серверным процессом.

Входные параметры:

  • client – имя клиентского процесса, отправляющего запрос на создание канала;
  • service – полное квалифицированное имя службы, запрошенное клиентским процессом (например, blkdev.ata);
  • rsid – идентификатор службы;
  • listener – слушающий дескриптор; если он имеет значение INVALID_HANDLE, создается новый слушающий дескриптор, который будет использоваться в качестве серверного IPC-дескриптора создаваемого канала.

Выходной параметр handle содержит серверный IPC-дескриптор создаваемого канала.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic kn_cm_accept]

KnCmConnect()

Функция объявлена в файле coresrv/cm/cm_api.h.

Retcode KnCmConnect(const char *server, const char *service,

rtl_uint32_t msecs, Handle *handle,

rtl_uint32_t *rsid);

Функция отправляет запрос на создание канала с серверным процессом. Функция вызывается клиентским процессом.

Входные параметры:

  • server – имя серверного процесса, предоставляющего службу;
  • service – полное квалифицированное имя службы (например, blkdev.ata);
  • msecs – время ожидания принятия запроса в миллисекундах.

Выходные параметры:

  • handle – клиентский IPC-дескриптор;
  • rsid – идентификатор службы.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic kn_cm_connect]

KnCmDrop()

Функция объявлена в файле coresrv/cm/cm_api.h.

Retcode KnCmDrop(const char *client, const char *service);

Функция отклоняет запрос клиентского процесса на создание канала, полученный ранее с помощью вызова KnCmListen(). Функция вызывается серверным процессом.

Параметры:

  • client – имя клиентского процесса, отправляющего запрос на создание канала;
  • service – полное квалифицированное имя службы, запрошенное клиентским процессом (например, blkdev.ata).

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic kn_cm_drop]

KnCmListen()

Функция объявлена в файле coresrv/cm/cm_api.h.

Retcode KnCmListen(const char *filter, rtl_uint32_t msecs, char *client,

char *service);

Функция проверяет наличие запросов клиентских процессов на создание канала. Функция вызывается серверным процессом.

Входные параметры:

  • filter – параметр не используется;
  • msecs – время ожидания запроса в миллисекундах.

Выходные параметры:

  • client – имя клиентского процесса;
  • service – полное квалифицированное имя службы, запрошенное клиентским процессом (например, blkdev.ata).

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic kn_cm_listen]

NsCreate()

Функция объявлена в файле coresrv/ns/ns_api.h.

Retcode NsCreate(const char *name, rtl_uint32_t msecs, NsHandle *ns);

Функция осуществляет попытку подключиться к серверу имен name в течение msecs миллисекунд. Если параметр name имеет значение RTL_NULL, функция пытается подключиться к серверу имен ns (серверу имен по умолчанию).

Выходной параметр ns содержит дескриптор соединения с сервером имен.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic ns_create]

NsEnumServices()

Функция объявлена в файле coresrv/ns/ns_api.h.

Retcode NsEnumServices(NsHandle ns, const char *type, unsigned index,

char *server, rtl_size_t serverSize,

char *service, rtl_size_t serviceSize);

Функция перечисляет службы с заданным интерфейсом, опубликованные на сервере имен.

Входные параметры:

  • ns – дескриптор соединения с сервером имен, полученный ранее с помощью вызова NsCreate();
  • type – имя интерфейса, который реализует служба (например, kl.drivers.Block);
  • index – индекс для перечисления служб;
  • serverSize – максимальный размер буфера для выходного параметра server в байтах;
  • serviceSize – максимальный размер буфера для выходного параметра service в байтах.

Выходные параметры:

  • server – имя серверного процесса, предоставляющего службу (например, kl.drivers.Ata);
  • service – полное квалифицированное имя службы (например, blkdev.ata).

Например, получить полный список серверных процессов, предоставляющих службу с интерфейсом kl.drivers.Block, можно следующим образом.

rc = NsEnumServices(ns, "kl.drivers.Block", 0, outServerName, ServerNameSize, outServiceName, ServiceNameSize);

rc = NsEnumServices(ns, "kl.drivers.Block", 1, outServerName, ServerNameSize, outServiceName, ServiceNameSize);

...

rc = NsEnumServices(ns, "kl.drivers.Block", N, outServerName, ServerNameSize, outServiceName, ServiceNameSize);

Вызовы функции с инкрементированием индекса продолжаются до тех пор, пока функция не вернет rcResourceNotFound.

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic ns_enum_services]

NsPublishService()

Функция объявлена в файле coresrv/ns/ns_api.h.

Retcode NsPublishService(NsHandle ns, const char *type, const char *server,

const char *service);

Функция публикует службу с заданным интерфейсом на сервере имен.

Параметры:

  • ns – дескриптор соединения с сервером имен, полученный ранее с помощью вызова NsCreate();
  • type – имя интерфейса, который реализует публикуемая служба (например, kl.drivers.Block);
  • server – имя серверного процесса (например, kl.drivers.Ata);
  • service – полное квалифицированное имя службы (например, blkdev.ata).

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic ns_publish_service]

NsUnPublishService()

Функция объявлена в файле coresrv/ns/ns_api.h.

Retcode NsUnPublishService( NsHandle ns, const char *type, const char *server,

const char *service);

Функция снимает с публикации службу на сервере имен.

Параметры:

  • ns – дескриптор соединения с сервером имен, полученный ранее с помощью вызова NsCreate();
  • type – имя интерфейса, который реализует публикуемая служба (например, kl.drivers.Block);
  • server – имя серверного процесса (например, kl.drivers.Ata);
  • service – полное квалифицированное имя службы (например, blkdev.ata).

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic ns_unpublish_service][Topic api_sync]

KosCondvarBroadcast()

Функция объявлена в файле kos/condvar.h.

void KosCondvarBroadcast(KosCondvar *condvar);

Функция пробуждает все потоки из очереди потоков, заблокированных посредством условной переменной condvar.

В начало
[Topic kos_condvar_broadcast]

KosCondvarDeinit()

Функция объявлена в файле kos/condvar.h.

void KosCondvarDeinit(KosCondvar *condvar);

Функция деинициализирует условную переменную condvar.

В начало
[Topic kos_condvar_deinit]

KosCondvarInit()

Функция объявлена в файле kos/condvar.h.

void KosCondvarInit(KosCondvar *condvar);

Функция инициализирует условную переменную condvar.

В начало
[Topic kos_condvar_init]

KosCondvarSignal()

Функция объявлена в файле kos/condvar.h.

void KosCondvarSignal(KosCondvar *condvar);

Функция пробуждает один поток из очереди потоков, заблокированных посредством условной переменной condvar.

В начало
[Topic kos_condvar_signal]

KosCondvarWait()

Функция объявлена в файле kos/condvar.h.

Retcode KosCondvarWait(KosCondvar *condvar, KosMutex *mutex);

Функция блокирует исполнение текущего потока посредством условной переменной condvar, пока он не будет пробужден с помощью KosCondvarSignal() или KosCondvarBroadcast().

mutex – мьютекс, который будет использован для защиты критической секции.

В случае успеха функция возвращает rcOk.

В начало
[Topic kos_condvar_wait]

KosCondvarWaitTimeout()

Функция объявлена в файле kos/condvar.h.

Retcode KosCondvarWaitTimeout(KosCondvar *condvar, KosMutex *mutex,

rtl_uint32_t mdelay);

Функция блокирует исполнение текущего потока посредством условной переменной condvar, пока он не будет пробужден с помощью KosCondvarSignal() или KosCondvarBroadcast(). Поток блокируется не более чем на mdelay миллисекунд.

  • mutex – мьютекс, который будет использован для защиты критической секции.

Функция возвращает rcOk в случае успеха и rcTimeout, если время ожидания истекло.

В начало
[Topic kos_condvar_wait_timeout]

KosEventDeinit()

Функция объявлена в файле kos/event.h.

void KosEventDeinit(KosEvent *event);

Функция освобождает ресурсы, связанные с событием event (уничтожает событие).

В начало
[Topic kos_event_deinit]

KosEventInit()

Функция объявлена в файле kos/event.h.

void KosEventInit(KosEvent *event);

Функция создает событие event.

Созданное событие находится в несигнальном состоянии.

В начало
[Topic kos_event_init]

KosEventReset()

Функция объявлена в файле kos/event.h.

void KosEventReset(KosEvent *event);

Функция переводит событие event в несигнальное состояние (сбрасывает событие).

В начало
[Topic kos_event_reset]

KosEventSet()

Функция объявлена в файле kos/event.h.

void KosEventSet(KosEvent *event);

Функция переводит событие event в сигнальное состояние (сигнализирует событие) и таким образом пробуждает все потоки, ожидающие его.

В начало
[Topic kos_event_set]

KosEventWait()

Функция объявлена в файле kos/event.h.

void KosEventWait(KosEvent *event, rtl_bool reset);

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

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

Функция возвращает rcOk в случае успеха.

В начало
[Topic kos_event_wait]

KosEventWaitTimeout()

Функция объявлена в файле kos/event.h.

Retcode KosEventWaitTimeout(KosEvent *event, rtl_bool reset,

rtl_uint32_t msec);

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

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

Функция возвращает rcOk в случае успеха и rcTimeout при превышении таймаута.

В начало
[Topic kos_event_wait_timeout]

KosMutexDeinit()

Функция объявлена в файле kos/mutex.h.

void KosMutexDeinit(KosMutex *mutex);

Функция уничтожает мьютекст mutex.

В начало
[Topic kos_mutex_deinit]

KosMutexInit()

Функция объявлена в файле kos/mutex.h.

void KosMutexInit(KosMutex *mutex);

Функция выполняет инициализацию мьютекса mutex в незаблокированном состоянии.

В начало
[Topic kos_mutex_init]

KosMutexInitEx()

Функция объявлена в файле kos/mutex.h.

void KosMutexInitEx(KosMutex *mutex, int recursive);

Функция выполняет инициализацию мьютекса mutex в незаблокированном состоянии.

Для инициализации рекурсивного мьютекса в параметр recursive нужно передать значение 1.

В начало
[Topic kos_mutex_init_ex]

KosMutexLock()

Функция объявлена в файле kos/mutex.h.

void KosMutexLock(KosMutex *mutex);

Функция захватывает мьютекс mutex.

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

В начало
[Topic kos_mutex_lock]

KosMutexLockTimeout()

Функция объявлена в файле kos/mutex.h.

Retcode KosMutexLockTimeout(KosMutex *mutex, rtl_uint32_t mdelay);

Функция захватывает мьютекс mutex.

Если мьютекс уже захвачен, поток блокируется на mdelay миллисекунд в ожидании его разблокировки.

Функция возвращает rcOk в случае успеха и rcTimeout, если время ожидания истекло.

В начало
[Topic kos_mutex_lock_timeout]

KosMutexTryLock()

Функция объявлена в файле kos/mutex.h.

Retcode KosMutexTryLock(KosMutex *mutex);

Функция делает попытку захвата мьютекса mutex.

Функция возвращает rcOk, если мьютекс удалось захватить и rcBusy, если мьютекс не удалось захватить, так как он уже захвачен.

В начало
[Topic kos_mutex_try_lock]

KosMutexUnlock()

Функция объявлена в файле kos/mutex.h.

void KosMutexUnlock(KosMutex *mutex);

Функция разблокирует мьютекс mutex.

Для разблокировки рекурсивного мьютекса нужно сделать столько вызовов KosMutexUnlock(), сколько раз рекурсивный мьютекс был заблокирован.

В начало
[Topic kos_mutex_unlock]

KosRWLockDeinit()

Функция объявлена в файле kos/rwlock.h.

void KosRWLockDeinit(KosRWLock *rwlock);

Функция деинициализирует блокировку чтения-записи rwlock.

В начало
[Topic kos_rw_lock_deinit]

KosRWLockInit()

Функция объявлена в файле kos/rwlock.h.

void KosRWLockInit(KosRWLock *rwlock);

Функция инициализирует блокировку чтения-записи rwlock.

В начало
[Topic kos_rw_lock_init]

KosRWLockRead()

Функция объявлена в файле kos/rwlock.h.

void KosRWLockRead(KosRWLock *rwlock);

Функция блокирует потоки чтения.

В начало
[Topic kos_rw_lock_read]

KosRWLockTryRead()

Функция объявлена в файле kos/rwlock.h.

Retcode KosRWLockTryRead(KosRWLock *rwlock);

Функция делает попытку блокировки потоков чтения.

В случае успеха функция возвращает rcOk.

В начало
[Topic kos_rw_lock_try_read]

KosRWLockTryWrite()

Функция объявлена в файле kos/rwlock.h.

Retcode KosRWLockTryWrite(KosRWLock *rwlock);

Функция делает попытку блокировки потоков записи.

В случае успеха функция возвращает rcOk.

В начало
[Topic kos_rw_lock_try_write]

KosRWLockUnlock()

Функция объявлена в файле kos/rwlock.h.

void KosRWLockUnlock(KosRWLock *rwlock);

Функция снимает блокировку чтения-записи rwlock.

В начало
[Topic kos_rw_lock_unlock]

KosRWLockWrite()

Функция объявлена в файле kos/rwlock.h.

void KosRWLockWrite(KosRWLock *rwlock);

Функция блокирует потоки записи.

В начало
[Topic kos_rw_lock_write]

KosSemaphoreDeinit()

Функция объявлена в файле kos/semaphore.h.

Retcode KosSemaphoreDeinit(KosSemaphore *semaphore);

Функция уничтожает семафор semaphore, инициализированный ранее функцией KosSemaphoreInit().

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

Функция возвращает:

  • rcOk в случае успеха;
  • rcInvalidArgument, если semaphore указывает на невалидный семафор;
  • rcFail, если есть потоки, заблокированные этим семафором.
В начало
[Topic kos_semaphore_deinit]

KosSemaphoreInit()

Функция объявлена в файле kos/semaphore.h.

Retcode KosSemaphoreInit(KosSemaphore *semaphore, unsigned count);

Функция инициализирует семафор semaphore с начальным значением count.

Функция возвращает:

  • rcOk в случае успеха;
  • rcInvalidArgument, если semaphore указывает на невалидный семафор;
  • rcFail, если значение count превышает KOS_SEMAPHORE_VALUE_MAX.
В начало
[Topic kos_semaphore_init]

KosSemaphoreSignal()

Функция объявлена в файле kos/semaphore.h.

Retcode KosSemaphoreSignal(KosSemaphore *semaphore);

Функция освобождает (сигнализирует) семафор semaphore.

Функция возвращает:

  • rcOk в случае успеха;
  • rcInvalidArgument, если semaphore указывает на невалидный семафор.
В начало
[Topic kos_semaphore_signal]

KosSemaphoreTryWait()

Функция объявлена в файле kos/semaphore.h.

Retcode KosSemaphoreTryWait(KosSemaphore *semaphore);

Функция делает попытку захвата семафора semaphore.

Функция возвращает:

  • rcOk в случае успеха;
  • rcInvalidArgument, если semaphore указывает на невалидный семафор;
  • rcBusy, если семафор уже захвачен.
В начало
[Topic kos_semaphore_try_wait]

KosSemaphoreWait()

Функция объявлена в файле kos/semaphore.h.

Retcode KosSemaphoreWait(KosSemaphore *semaphore);

Функция ожидает захвата семафора semaphore.

Функция возвращает:

  • rcOk в случае успеха;
  • rcInvalidArgument, если semaphore указывает на невалидный семафор.
В начало
[Topic kos_semaphore_wait]

KosSemaphoreWaitTimeout()

Функция объявлена в файле kos/semaphore.h.

Retcode KosSemaphoreWaitTimeout(KosSemaphore *semaphore, rtl_uint32_t mdelay);

Функция ожидает захвата семафора semaphore в течение mdelay миллисекунд.

Функция возвращает:

  • rcOk в случае успеха;
  • rcInvalidArgument, если semaphore указывает на невалидный семафор;
  • rcTimeout, если время ожидания истекло.
В начало
[Topic kos_semaphore_wait_timeout][Topic libkos_dma]

DmaInfo

Структура, описывающая DMA-буфер, объявлена в файле io/io_dma.h.

typedef struct {

/** DMA-флаги (атрибуты). */

DmaAttr flags;

/** Минимальный порядок DMA-блоков в буфере. */

rtl_size_t orderMin;

/** Размер DMA-буфера. */

rtl_size_t size;

/** Число DMA-блоков (меньше или равно DMA_FRAMES_COUNT_MAX).

* Может быть равно 0, если DMA-буфер недоступен для устройства. */

rtl_size_t count;

/** Массив описателей DMA-блоков. */

union DmaFrameDescriptor {

struct {

/** Порядок (order) DMA-блока. Число страниц в блоке равно двум

* в степени order. */

DmaAddr order: DMA_FRAME_ORDER_BITS;

/** Физический или IOMMU-адрес DMA-блока. */

DmaAddr frame: DMA_FRAME_BASE_BITS;

};

/** Описатель DMA-блока */

DmaAddr raw;

} descriptors[1];

} DmaInfo;

В начало
[Topic dma_info]

DMA-флаги

DMA-флаги (атрибуты) объявлены в файле io/io_dma.h.

  • DMA_DIR_TO_DEVICE – разрешены транзакции из основной памяти в память устройства;
  • DMA_DIR_FROM_DEVICE – разрешены транзакции из памяти устройства в основную память;
  • DMA_DIR_BIDIR – разрешены транзакции из основной памяти в память устройства и наоборот;
  • DMA_ZONE_DMA32 – под буфер разрешено использовать только первые 4 Гб памяти;
  • DMA_ATTR_WRITE_BACK, DMA_ATTR_WRITE_THROUGH, DMA_ATTR_CACHE_DISABLE, DMA_ATTR_WRITE_COMBINE – управление кэшированием страниц памяти.
В начало
[Topic dma_attr]

KnIoDmaBegin()

Функция объявлена в файле coresrv/io/dma.h.

Retcode KnIoDmaBegin(Handle rid, Handle *handle);

Функция разрешает устройству доступ к DMA-буферу с дескриптором rid.

Выходной параметр handle содержит дескриптор данного разрешения.

В случае успеха функция возвращает rcOk.

Пример использования – см. KnIoDmaCreate().

Чтобы запретить устройству доступ к DMA-буферу, необходимо вызвать функцию KnIoClose(), передав в нее дескриптор разрешения handle.

В начало
[Topic kn_io_dma_begin]

KnIoDmaCreate()

Функция объявлена в файле coresrv/io/dma.h.

Retcode KnIoDmaCreate(rtl_uint32_t order, rtl_size_t size, DmaAttr flags,

Handle *outRid);

Функция регистрирует и выделяет физический DMA-буфер.

Входные параметры:

  • order – минимальный допустимый порядок выделения DMA-блоков; фактический порядок каждого блока в DMA-буфере выбирается ядром (но не будет меньше order) и помещается в дескриптор блока; порядок блока определяет число страниц в нем: блок с порядком N состоит из 2^N страниц;
  • size – размер DMA-буфера в байтах (должен быть кратен размеру страницы); сумма размеров выделенных DMA-блоков будет не меньше size;
  • flagsDMA-флаги.

Выходной параметр outRid содержит дескриптор выделенного DMA-буфера.

В случае успеха функция возвращает rcOk.

Если DMA-буфер больше не используется, его необходимо освободить с помощью функции KnIoClose().

Пример

Retcode RegisterDmaMem(rtl_size_t size,

DmaAttr attr,

Handle *handle,

Handle *dmaHandle,

Handle *mappingHandle,

void **addr)

{

Retcode ret;

*handle = INVALID_HANDLE;

*dmaHandle = INVALID_HANDLE;

*mappingHandle = INVALID_HANDLE;

ret = KnIoDmaCreate(rtl_roundup_order(size >> PAGE_SHIFT),

size,

attr,

handle);

if (ret == rcOk) {

ret = KnIoDmaBegin(*handle, dmaHandle);

}

if (ret == rcOk) {

ret = KnIoDmaMap(*handle,

0,

size,

RTL_NULL,

VMM_FLAG_READ | VMM_FLAG_WRITE,

addr,

mappingHandle);

}

if (ret != rcOk) {

if (*mappingHandle != INVALID_HANDLE)

KnHandleClose(*mappingHandle);

if (*dmaHandle != INVALID_HANDLE)

KnHandleClose(*dmaHandle);

if (*handle != INVALID_HANDLE)

KnHandleClose(*handle);

}

return ret;

}

В начало
[Topic kn_io_dma_create]

KnIoDmaGetInfo()

Функция объявлена в файле coresrv/io/dma.h.

Retcode KnIoDmaGetInfo(Handle rid, DmaInfo **outInfo);

Функция получает информацию о DMA-буфере с дескриптором rid.

Выходной параметр outInfo содержит информацию о DMA-буфере.

В случае успеха функция возвращает rcOk.

В отличие от KnIoDmaGetPhysInfo(), параметр outInfo содержит не физические, а IOMMU-адреса DMA-блоков.

В начало
[Topic kn_io_dma_get_info]

KnIoDmaGetPhysInfo()

Функция объявлена в файле coresrv/io/dma.h.

Retcode KnIoDmaGetPhysInfo(Handle rid, DmaInfo **outInfo);

Функция получает информацию о DMA-буфере с дескриптором rid.

Выходной параметр outInfo содержит информацию о DMA-буфере.

В случае успеха функция возвращает rcOk.

В отличие от KnIoDmaGetInfo(), параметр outInfo содержит не IOMMU-адреса, а физические адреса DMA-блоков.

В начало
[Topic kn_io_dma_get_phys_info]

KnIoDmaMap()

Функция объявлена в файле coresrv/io/dma.h.

Retcode KnIoDmaMap(Handle rid, rtl_size_t offset, rtl_size_t length, void *hint,

int vmflags, void **addr, Handle *handle);

Функция отображает участок DMA-буфера на адресное пространство процесса.

Входные параметры:

  • rid – дескриптор выделенного с помощью KnIoDmaCreate() DMA-буфера;
  • offset – странично-выровненное смещение начала участка от начала буфера в байтах;
  • length – размер участка; должен быть кратен размеру страницы и не превышать <размер буфера - offset>;
  • hint – виртуальный адрес начала отображения; если он равен 0, адрес выберет ядро;
  • vmflags – флаги аллокации.

В параметре vmflags можно использовать следующие флаги аллокации (vmm/flags.h):

  • VMM_FLAG_READ и VMM_FLAG_WRITE – атрибуты защиты памяти;
  • VMM_FLAG_LOW_GUARD и VMM_FLAG_HIGH_GUARD – добавление защитной страницы перед и после выделенной памяти соответственно.

Допустимые комбинации атрибутов защиты памяти:

  • VMM_FLAG_READ – разрешено чтение содержимого страницы;
  • VMM_FLAG_WRITE – разрешено изменение содержимого страницы;
  • VMM_FLAG_READ | VMM_FLAG_WRITE – разрешено чтение и изменение содержимого страницы.

Выходные параметры:

  • addr – указатель на виртуальный адрес начала отображенного участка;
  • handle – дескриптор созданного отображения.

В случае успеха функция возвращает rcOk.

Пример использования – см. KnIoDmaCreate().

Чтобы удалить созданное отображение, необходимо вызвать функцию KnIoClose(), передав в нее дескриптор отображения handle.

В начало
[Topic kn_io_dma_map][Topic libkos_iommu]

KnIommuAttachDevice()

Функция объявлена в файле coresrv/iommu/iommu_api.h.

Retcode KnIommuAttachDevice(rtl_uint16_t bdf);

Функция добавляет PCI-устройство с идентификатором bdf в группу IOMMU вызывающего процесса (IOMMU domain).

В случае успеха возвращает rcOk.

В начало
[Topic kn_iommu_attach_device]

KnIommuDetachDevice()

Функция объявлена в файле coresrv/iommu/iommu_api.h.

Retcode KnIommuDetachDevice(rtl_uint16_t bdf);

Функция удаляет PCI-устройство с идентификатором bdf из группы IOMMU вызывающего процесса (IOMMU domain).

В случае успеха функция возвращает rcOk.

В начало
[Topic kn_iommu_detach_device][Topic libkos_ports]

IoReadIoPort8(), IoReadIoPort16(), IoReadIoPort32()

Функции объявлены в файле coresrv/io/ports.h.

rtl_uint8_t IoReadIoPort8(rtl_size_t port);

rtl_uint16_t IoReadIoPort16(rtl_size_t port);

rtl_uint32_t IoReadIoPort32(rtl_size_t port);

Функции вычитывают один, два или четыре байта соответственно из порта port и возвращают прочитанное значение.

В начало
[Topic io_read_io_port]

IoReadIoPortBuffer8(), IoReadIoPortBuffer16(), IoReadIoPortBuffer32()

Функции объявлены в файле coresrv/io/ports.h.

void IoReadIoPortBuffer8(rtl_size_t port, rtl_uint8_t *dst, rtl_size_t cnt);

void IoReadIoPortBuffer16(rtl_size_t port, rtl_uint16_t *dst, rtl_size_t cnt);

void IoReadIoPortBuffer32(rtl_size_t port, rtl_uint32_t *dst, rtl_size_t cnt);

Функции вычитывают последовательность одно-, двух- или четырехбайтовых значений соответственно из порта port и записывают значения в массив dst.

cnt – длина последовательности.

В начало
[Topic io_read_io_port_buffer]

IoWriteIoPort8(), IoWriteIoPort16(), IoWriteIoPort32()

Функции объявлены в файле coresrv/io/ports.h.

void IoWriteIoPort8(rtl_size_t port, rtl_uint8_t data);

void IoWriteIoPort16(rtl_size_t port, rtl_uint16_t data);

void IoWriteIoPort32(rtl_size_t port, rtl_uint32_t data);

Функции записывают одно-, двух- или четырехбайтовое значение data в порт port.

В начало
[Topic io_write_io_port]

IoWriteIoPortBuffer8(), IoWriteIoPortBuffer16(), IoWriteIoPortBuffer32()

Функции объявлены в файле coresrv/io/ports.h.

void IoWriteIoPortBuffer8(rtl_size_t port, const rtl_uint8_t *src,

rtl_size_t cnt);

void IoWriteIoPortBuffer16(rtl_size_t port, const rtl_uint16_t *src,

rtl_size_t cnt);

void IoWriteIoPortBuffer32(rtl_size_t port, const rtl_uint32_t *src,

rtl_size_t cnt);

Функции записывают последовательность одно-, двух- или четырехбайтовых значений соответственно из массива src в порт port.

cnt – длина последовательности.

В начало
[Topic io_write_io_port_buffer]

KnIoPermitPort()

Функция объявлена в файле coresrv/io/ports.h.

Retcode KnIoPermitPort(Handle rid, Handle *handle);

Функция разрешает процессу доступ к порту (диапазону портов) с дескриптором rid.

Выходной параметр handle содержит дескриптор данного разрешения.

Функция возвращает rcOk в случае успеха.

Пример

static Retcode PortInit(IOPort *resource)

{

Retcode rc = rcFail;

rc = KnRegisterPorts(resource->base,

resource->size,

&resource->handle);

if (rc == rcOk)

rc = KnIoPermitPort(resource->handle, &resource->permitHandle);

resource->addr = (void *) (rtl_uintptr_t) resource->base;

return rc;

}

В начало
[Topic kn_io_permit_port]

KnRegisterPort8(), KnRegisterPort16(), KnRegisterPort32()

Функции объявлены в файле coresrv/io/ports.h.

Retcode KnRegisterPort8(rtl_uint16_t port, Handle *outRid);

Retcode KnRegisterPort16(rtl_uint16_t port, Handle *outRid);

Retcode KnRegisterPort32(rtl_uint16_t port, Handle *outRid);

Функции регистрируют восьми-, шестнадцати- или тридцатидвухбитный порт соответственно с адресом port и назначают ему дескриптор outRid.

Функции возвращают rcOk в случае успешного выделения порта.

Если порт больше не используется, его необходимо освободить с помощью функции KnIoClose().

В начало
[Topic kn_register_port]

KnRegisterPorts()

Функция объявлена в файле coresrv/io/ports.h.

Retcode KnRegisterPorts(rtl_uint16_t port, rtl_size_t size, Handle *outRid);

Функция регистрирует диапазон портов (участок памяти) с базовым адресом port и размером size в байтах и назначает ему дескриптор outRid.

Возвращает rcOk в случае успешного выделения диапазона портов.

Пример использования – см. KnIoPermitPort().

Если диапазон портов больше не используется, его необходимо освободить с помощью функции KnIoClose().

В начало
[Topic kn_register_ports][Topic libkos_mmio]

IoReadMmBuffer8(), IoReadMmBuffer16(), IoReadMmBuffer32()

Функции объявлены в файле coresrv/io/mmio.h.

void IoReadMmBuffer8(volatile rtl_uint8_t *baseReg, rtl_uint8_t *dst,

rtl_size_t cnt);

void IoReadMmBuffer16(volatile rtl_uint16_t *baseReg, rtl_uint16_t *dst,

rtl_size_t cnt);

void IoReadMmBuffer32(volatile rtl_uint32_t *baseReg, rtl_uint32_t *dst,

rtl_size_t cnt);

Функции вычитывают последовательность одно-, двух- или четырехбайтовых значений соответственно из регистра, отображаемого по адресу baseReg, и записывают значения в массив dst. cnt – длина последовательности.

В начало
[Topic io_read_mm_buffer]

IoReadMmReg8(), IoReadMmReg16(), IoReadMmReg32()

Функции объявлены в файле coresrv/io/mmio.h.

rtl_uint8_t IoReadMmReg8(volatile void *reg);

rtl_uint16_t IoReadMmReg16(volatile void *reg);

rtl_uint32_t IoReadMmReg32(volatile void *reg);

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

В начало
[Topic io_read_mm_reg]

IoWriteMmBuffer8(), IoWriteMmBuffer16(), IoWriteMmBuffer32()

Функции объявлены в файле coresrv/io/mmio.h.

void IoWriteMmBuffer8(volatile rtl_uint8_t *baseReg, const rtl_uint8_t *src,

rtl_size_t cnt);

void IoWriteMmBuffer16(volatile rtl_uint16_t *baseReg, const rtl_uint16_t *src,

rtl_size_t cnt);

void IoWriteMmBuffer32(volatile rtl_uint32_t *baseReg, const rtl_uint32_t *src,

rtl_size_t cnt);

Функции записывают последовательность одно-, двух- или четырехбайтовых значений соответственно из массива src в регистр, отображаемый по адресу baseReg. cnt - длина последовательности.

В начало
[Topic io_write_mm_buffer]

IoWriteMmReg8(), IoWriteMmReg16(), IoWriteMmReg32()

Функции объявлены в файле coresrv/io/mmio.h.

void IoWriteMmReg8(volatile void *reg, rtl_uint8_t data);

void IoWriteMmReg16(volatile void *reg, rtl_uint16_t data);

void IoWriteMmReg32(volatile void *reg, rtl_uint32_t data);

Функции записывают одно-, двух- или четырехбайтовое значение data в регистр, отображаемый по адресу reg.

В начало
[Topic io_write_mm_reg]

KnIoMapMem()

Функция объявлена в файле coresrv/io/mmio.h.

Retcode KnIoMapMem(Handle rid, rtl_uint32_t prot, rtl_uint32_t attr,

void **addr, Handle *handle);

Функция отображает зарегистрированный участок памяти, которому назначен дескриптор rid, на адресное пространство процесса.

С помощью входных параметров prot и attr можно изменить атрибуты защиты участка памяти, а также отключить кэширование.

Выходные параметры:

  • addr – указатель на адрес начала участка виртуальной памяти;
  • handle – дескриптор участка виртуальной памяти.

Функция возвращает rcOk в случае успеха.

prot – атрибуты защиты участка памяти через MMU, возможные значения:

  • VMM_FLAG_READ – разрешено чтение;
  • VMM_FLAG_WRITE – разрешена запись;
  • VMM_FLAG_READ | VMM_FLAG_WRITE – разрешены чтение и запись;
  • VMM_FLAG_RWX_MASK или VMM_FLAG_READ | VMM_FLAG_WRITE | VMM_FLAG_EXECUTE – полный доступ к участку памяти (эти записи эквивалентны).

attr – атрибуты участка памяти, возможные значения:

  • VMM_FLAG_CACHE_DISABLE – отключить кэширование;
  • VMM_FLAG_LOW_GUARD и VMM_FLAG_HIGH_GUARD – добавление защитной страницы перед и после выделенной памяти соответственно;
  • VMM_FLAG_ALIAS – флаг указывает, что участок памяти может иметь несколько виртуальных адресов.

Пример

static Retcode MemInit(IOMem *resource)

{

Retcode rc = rcFail;

rc = KnRegisterPhyMem(resource->base,

resource->size,

&resource->handle);

if (rc == rcOk)

rc = KnIoMapMem(resource->handle,

VMM_FLAG_READ | VMM_FLAG_WRITE,

VMM_FLAG_CACHE_DISABLE,

(void **) &resource->addr, &resource->permitHandle);

if (rc == rcOk)

resource->addr = ((rtl_uint8_t *) resource->addr

+ resource->offset);

return rc;

}

В начало
[Topic kn_io_map_mem]

KnRegisterPhyMem()

Функция объявлена в файле coresrv/io/mmio.h.

Retcode KnRegisterPhyMem(rtl_uint64_t addr, rtl_size_t size, Handle *outRid);

Функция регистрирует участок памяти размером size байт с началом по адресу addr.

В случае успешной регистрации дескриптор, назначенный участку памяти, будет передан в параметр outRid, а функция вернет rcOk.

Адрес addr должен быть странично-выровненным, а размер size должен быть кратен размеру страницы.

Пример использования – см. KnIoMapMem().

Если участок памяти больше не используется, его необходимо освободить с помощью функции KnIoClose().

В начало
[Topic kn_register_phy_mem]

Прерывания

Описанный здесь интерфейс является низкоуровневым. Для работы с прерываниями в большинстве случаев рекомендуется использовать интерфейс, предоставляемый библиотекой kdf.

В этом разделе

KnIoAttachIrq()

KnIoDetachIrq()

KnIoDisableIrq()

KnIoEnableIrq()

KnRegisterIrq()

В начало
[Topic libkos_interrupts]

KnIoAttachIrq()

Функция объявлена в файле coresrv/io/irq.h.

Retcode KnIoAttachIrq(Handle rid, rtl_uint32_t flags, Handle *handle);

Функция привязывает вызывающий поток к прерыванию.

Входные параметры:

  • rid – дескриптор прерывания, полученный с помощью вызова KnRegisterIrq();
  • flags – флаги прерывания.

Выходной параметр handle содержит IPC-дескриптор, посредством которого вызывающий поток будет ожидать прерывание, выполнив вызов Recv().

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

Флаги прерывания

  • IRQ_LEVEL_LOW – генерация по низкому уровню;
  • IRQ_LEVEL_HIGH – генерация по высокому уровню;
  • IRQ_EDGE_RAISE – генерация по переднему фронту;
  • IRQ_EDGE_FALL – генерация по заднему фронту;
  • IRQ_SHARED – разделяемое прерывание;
  • IRQ_PRIO_LOW – низкий приоритет прерывания;
  • IRQ_PRIO_NORMAL – нормальный приоритет;
  • IRQ_PRIO_HIGH – высокий приоритет;
  • IRQ_PRIO_RT – приоритет реального времени.
В начало
[Topic kn_io_attach_irq]

KnIoDetachIrq()

Функция объявлена в файле coresrv/io/irq.h.

Retcode KnIoDetachIrq(Handle rid);

Функция отвязывает вызывающий поток от прерывания.

rid – дескриптор прерывания, полученный с помощью вызова KnRegisterIrq();

В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.

В начало
[Topic kn_io_detach_irq]

KnIoDisableIrq()

Функция объявлена в файле coresrv/io/irq.h.

Retcode KnIoDisableIrq(Handle rid);

Функция маскирует (запрещает) прерывание с дескриптором rid.

В случае успеха функция возвращает rcOk.

В начало
[Topic kn_io_disable_irq]

KnIoEnableIrq()

Функция объявлена в файле coresrv/io/irq.h.

Retcode KnIoEnableIrq(Handle rid);

Функция демаскирует (разрешает) прерывание с дескриптором rid.

В случае успеха функция возвращает rcOk.

В начало
[Topic kn_io_enable_irq]

KnRegisterIrq()

Функция объявлена в файле coresrv/io/irq.h.

Retcode KnRegisterIrq(int irq, Handle *outRid);

Функция регистрирует прерывание с номером irq.

Выходной параметр outRid содержит дескриптор прерывания.

В случае успеха функция возвращает rcOk.

Если прерывание больше не используется, его необходимо освободить с помощью функции KnIoClose().

В начало
[Topic kn_register_irq]

Освобождение ресурсов

В этом разделе

KnIoClose()

В начало
[Topic libkos_close_resource]

KnIoClose()

Функция объявлена в файле coresrv/io/io_api.h.

Retcode KnIoClose(Handle rid);

Функция освобождает зарегистрированный ресурс ввода-вывода (порт/порты ввода-вывода, DMA-буфер, прерывание или участок памяти для MMIO) с дескриптором rid.

В случае успешного освобождения функция возвращает rcOk.

Пример использования – см. KnIoDmaCreate().

В начало
[Topic kn_io_close][Topic libkos_time]

KnGetMSecSinceStart()

Функция объявлена в файле coresrv/time/time_api.h.

rtl_size_t KnGetMSecSinceStart(void);

Функция возвращает количество миллисекунд, прошедших с момента старта системы.

В начало
[Topic kn_get_msec_since_start]

KnGetRtcTime()

Функция объявлена в файле coresrv/time/time_api.h.

Retcode KnGetRtcTime(RtlRtcTime *rt);

Функция записывает в параметр rt системное POSIX-время в формате RTC.

В случае успеха возвращает rcOk, в случае ошибки – rcFail.

Формат времени RTC задается структурой RtlRtcTime (объявлена в файле rtl/rtc.h.):

typedef struct {

rtl_uint32_t msec; /**< миллисекунды */

rtl_uint32_t sec; /**< секунда (0..59) */

rtl_uint32_t min; /**< минута (0..59) */

rtl_uint32_t hour; /**< час (0..23) */

rtl_uint32_t mday; /**< день (1..31) */

rtl_uint32_t month; /**< месяц (0..11) */

rtl_int32_t year; /**< год - 1900 */

rtl_uint32_t wday; /**< день недели (0..6) */

} RtlRtcTime;

В начало
[Topic kn_get_rtc_time]

KnGetSystemTime()

Функция объявлена в файле coresrv/time/time_api.h.

Retcode KnGetSystemTime(RtlTimeSpec *time);

Функция позволяет получить системное время.

Выходной параметр time содержит системное POSIX-время в формате RtlTimeSpec.

В начало
[Topic kn_get_system_time]

KnSetSystemTime()

Функция объявлена в файле coresrv/time/time_api.h.

Retcode KnSetSystemTime(RtlTimeSpec *time);

Функция позволяет задать системное время.

Параметр time должен содержать POSIX-время в формате RtlTimeSpec.

Не рекомендуется вызывать функцию KnSetSystemTime() в потоке обработчика прерываний.

В начало
[Topic kn_set_system_time]

KnGetSystemTimeRes()

Функция объявлена в файле coresrv/time/time_api.h.

Retcode KnGetSystemTimeRes(RtlTimeSpec *res);

Функция позволяет получить разрешение источника системного времени.

Выходной параметр res содержит разрешение формате RtlTimeSpec.

В начало
[Topic kn_get_system_time_res]

KnGetUpTime()

Функция объявлена в файле coresrv/time/time_api.h.

Retcode KnGetUpTime(RtlTimeSpec *time);

Функция позволяет получить время, прошедшее с момента старта системы.

Выходной параметр time содержит время в формате RtlTimeSpec.

В начало
[Topic kn_get_up_time]

KnGetUpTimeRes()

Функция объявлена в файле coresrv/time/time_api.h.

Retcode KnGetUpTimeRes(RtlTimeSpec *res);

Функция позволяет получить разрешение источника времени, значение которого можно получить через KnGetUpTime().

Выходной параметр res содержит разрешение в формате RtlTimeSpec.

В начало
[Topic kn_get_up_time_res]

RtlTimeSpec

Формат времени timespec задается структурой RtlTimeSpec (объявлена в файле rtl/rtc.h).

typedef struct {

rtl_time_t sec; /**< целое число секунд, прошедшее с начала Unix-эпохи

* или другого заданного момента времени */

rtl_nsecs_t nsec; /**< поправка в наносекундах (число наносекунд,

* прошедших с момента, заданного числом секунд*/

} RtlTimeSpec;

В начало
[Topic rtl_time_spec][Topic libkos_queues]

KosQueueAlloc()

Функция объявлена в файле kos/queue.h.

void *KosQueueAlloc(KosQueueHandle queue);

Функция аллоцирует память под новый объект из буфера очереди queue.

В случае успеха функция возвращает указатель на память под объект, если буфер заполнен – RTL_NULL.

В начало
[Topic kos_queue_alloc]

KosQueueCreate()

Функция объявлена в файле kos/queue.h.

KosQueueHandle KosQueueCreate(unsigned objCount,

unsigned objSize,

unsigned objAlign,

void *buffer);

Функция создает очередь объектов (fifo) и связанный с ней буфер.

Параметры:

  • objCount – максимальное количество объектов в очереди;
  • objSize – размер объекта (байт);
  • objAlign – выравнивание объекта в байтах, должно быть степенью двойки;
  • buffer – указатель на внешний буфер под объекты; если задать его равным RTL_NULL, то буфер будет выделен с помощью функции KosMemAlloc().

Функция возвращает дескриптор созданной очереди и RTL_NULL в случае ошибки.

В начало
[Topic kos_queue_create]

KosQueueDestroy()

Функция объявлена в файле kos/queue.h.

void KosQueueDestroy(KosQueueHandle queue);

Функция удаляет очередь queue и освобождает выделенный под нее буфер.

В начало
[Topic kos_queue_destroy]

KosQueueFlush()

Функция объявлена в файле kos/queue.h.

void KosQueueFlush(KosQueueHandle queue);

Функция извлекает все объекты из очереди queue и освобождает всю память, занятую ими.

В начало
[Topic kos_queue_flush]

KosQueueFree()

Функция объявлена в файле kos/queue.h.

void KosQueueFree(KosQueueHandle queue, void *obj);

Функция освобождает память, занимаемую объектом obj в буфере очереди queue.

Указатель obj может быть получен вызовом функции KosQueueAlloc() или KosQueuePop().

Пример использования – см. KosQueuePop().

В начало
[Topic kos_queue_free]

KosQueuePop()

Функция объявлена в файле kos/queue.h.

void *KosQueuePop(KosQueueHandle queue, rtl_uint32_t timeout);

Функция извлекает из начала очереди queue объект и возвращает указатель на него.

Параметр timeout определяет поведение функции в случае, если очередь пуста:

  • 0 – немедленный возврат RTL_NULL;
  • INFINITE_TIMEOUT – блокировка в ожидании нового объекта в очереди;
  • любое другое значение timeout – ожидание нового объекта в очереди в течение timeout миллисекунд; по истечении этого времени возвращается RTL_NULL.

Пример

int GpioEventDispatch(void *context)

{

GpioEvent *event;

GpioDevice *device = context;

rtl_bool proceed = rtl_true;

do {

event = KosQueuePop(device->queue, INFINITE_TIMEOUT);

if (event != RTL_NULL) {

if (event->type == GPIO_EVENT_TYPE_THREAD_ABORT) {

proceed = rtl_false;

} else {

GpioDeliverEvent(device, event);

}

KosQueueFree(device->queue, event);

}

} while (proceed);

KosPutObject(device);

return rcOk;

}

В начало
[Topic kos_queue_pop]

KosQueuePush()

Функция объявлена в файле kos/queue.h.

void KosQueuePush(KosQueueHandle queue, void *obj);

Функция добавляет объект obj в конец очереди queue.

Указатель obj может быть получен вызовом функции KosQueueAlloc() или KosQueuePop().

В начало
[Topic kos_queue_push]

Барьеры памяти

В этом разделе

IoReadBarrier()

IoReadWriteBarrier()

IoWriteBarrier()

В начало
[Topic libkos_memory_barriers]

IoReadBarrier()

Функция объявлена в файле coresrv/io/barriers.h.

void IoReadBarrier(void);

Функция добавляет барьер чтения из памяти. Linux-аналог: rmb().

В начало
[Topic io_read_barrier]

IoReadWriteBarrier()

Функция объявлена в файле coresrv/io/barriers.h.

void IoReadWriteBarrier(void);

Функция добавляет обобщенный барьер. Linux-аналог: mb().

В начало
[Topic io_read_write_barrier]

IoWriteBarrier()

Функция объявлена в файле coresrv/io/barriers.h.

void IoWriteBarrier(void);

Функция добавляет барьер записи. Linux-аналог: wmb().

В начало
[Topic io_write_barrier]

Получение сведений об использовании процессорного времени и памяти

Библиотека libkos предоставляет API, который позволяет получить сведения об использовании процессорного времени и памяти. Этот API определен в заголовочном файле sysroot-*-kos/include/coresrv/stat/stat_api.h из состава KasperskyOS SDK.

Чтобы получить сведения об использовании процессорного времени и памяти, а также другие статистические сведения, нужно собрать решение с версией ядра KasperskyOS, которая поддерживает счетчики производительности. Подробнее см. "Библиотека image".

Получение сведений об использовании процессорного времени

Время работы процессора отсчитывается с момента запуска ядра KasperskyOS.

Чтобы получить сведения об использовании процессорного времени, нужно использовать функции KnGroupStatGetParam() и KnTaskStatGetParam(). При этом через параметр param этих функций нужно передать значения, приведенные в таблице ниже.

Сведения об использовании процессорного времени

Функция

Значение параметра param

Получаемое значение

KnGroupStatGetParam()

GROUP_PARAM_CPU_KERNEL

Время работы процессора в режиме ядра

KnGroupStatGetParam()

GROUP_PARAM_CPU_USER

Время работы процессора в пользовательском режиме

KnGroupStatGetParam()

GROUP_PARAM_CPU_IDLE

Время работы процессора в режиме бездействия

KnTaskStatGetParam()

TASK_PARAM_TIME_TOTAL

Время работы процессора, затраченное на исполнение процесса

KnTaskStatGetParam()

TASK_PARAM_TIME_USER

Время работы процессора, затраченное на исполнение процесса в пользовательском режиме

Время работы процессора, полученное вызовом функции KnGroupStatGetParam() или KnTaskStatGetParam(), выражено в наносекундах.

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

Чтобы получить сведения об использовании памяти, нужно использовать функции KnGroupStatGetParam() и KnTaskStatGetParam(). При этом через параметр param этих функций нужно передать значения, приведенные в таблице ниже.

Сведения об использовании памяти

Функция

Значение параметра param

Получаемое значение

KnGroupStatGetParam()

GROUP_PARAM_MEM_TOTAL

Размер всей установленной оперативной памяти

KnGroupStatGetParam()

GROUP_PARAM_MEM_FREE

Размер свободной оперативной памяти

KnTaskStatGetParam()

TASK_PARAM_MEM_PHY

Размер оперативной памяти, используемой процессом

Размер памяти, полученный вызовом функции KnGroupStatGetParam() или KnTaskStatGetParam(), представляет собой число страниц памяти. Размер страницы памяти составляет 4 КБ для всех аппаратных платформ, поддерживаемых KasperskyOS.

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

Перечисление процессов

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

  1. Получить список процессов вызовом функции KnGroupStatGetTaskList().
  2. Получить число элементов списка процессов вызовом функции KnTaskStatGetTasksCount().
  3. Выполнить в цикле следующие действия:
    1. Получить элемент списка процессов вызовом функции KnTaskStatEnumTaskList().
    2. Получить имя процесса вызовом функции KnTaskStatGetName().

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

    3. Получить сведения об использовании процессорного времени и памяти процессом вызовами функции KnTaskStatGetParam().
    4. Проверить, что процесс не завершился. Если процесс завершился, то не использовать полученные сведения об использовании процессорного времени и памяти этим процессом.

      Чтобы проверить, что процесс не завершился, нужно вызвать функцию KnTaskStatGetParam() с передачей через параметр param значения TASK_PARAM_STATE. Должно быть получено значение, отличное от TaskStateTerminated.

    5. Завершить работу с элементом списка процессов вызовом функции KnTaskStatCloseTask().
  4. Завершить работу со списком процессов вызовом функции KnTaskStatCloseTaskList().

Расчет загрузки процессора

Показателями загрузки процессора могут быть процент общей загрузки процессора и процент загрузки процессора каждым процессом. Расчет этих показателей выполняется для интервала времени, в начале и конце которого были получены сведения об использовании процессорного времени. (Например, может выполняться мониторинг загрузки процессора с периодическим получением сведений об использовании процессорного времени.) Из значений, полученных в конце интервала, нужно вычесть значения, полученные в начале интервала. То есть для интервала нужно получить следующие приращения:

  • TK – время работы процессора в режиме ядра;
  • TU – время работы процессора в пользовательском режиме;
  • TIDLE – время работы процессора в режиме бездействия;
  • Ti [i=1,2,...,n] – процессорное время, затраченное на исполнение i-го процесса.

Процент общей загрузки процессора рассчитывается так:

(TK+TU)/(TK+TU+TIDLE).

Процент загрузки процессора i-м процессом рассчитывается так:

Ti/(TK+TU+TIDLE).

Получение дополнительных сведений о процессах

Помимо сведений об использовании процессорного времени и памяти функции KnGroupStatGetParam() и KnTaskStatGetParam() позволяют получить, например, такие сведения:

  • число процессов;
  • число потоков исполнения;
  • число потоков исполнения в одном процессе;
  • идентификатор родительского процесса (PPID);
  • приоритет процесса;
  • число дескрипторов, которыми владеет процесс;
  • размер виртуальной памяти процесса.

Функция KnTaskStatGetId() позволяет получить идентификатор процесса (PID).

В начало
[Topic comp_res_util]

Отправка и прием IPC-сообщений

В этом разделе

Call()

Recv()

Reply()

В начало
[Topic ipc_api]

Call()

Функция объявлена в файле coresrv/syscalls.h.

Retcode Call(Handle handle, const SMsgHdr *msgOut, SMsgHdr *msgIn);

Функция отправляет IPC-запрос серверному процессу и блокирует вызывающий поток до получения IPC-ответа или ошибки. Функция вызывается клиентским процессом.

Параметры:

  • handle – клиентский IPC-дескриптор используемого канала;
  • msgOut – буфер, содержащий IPC-запрос;
  • msgIn – буфер под IPC-ответ.

Возвращаемое значение:

  • rcOk – обмен IPC-сообщениями успешно завершен;
  • rcInvalidArgument – IPC-запрос и/или IPC-ответ имеют некорректную структуру;
  • rcSecurityDisallow – отправка IPC-запроса или IPC-ответа запрещена модулем безопасности KSM;
  • rcNotConnected – серверный IPC-дескриптор канала не найден.

Возможны другие коды возврата.

В начало
[Topic ipc_call]

Recv()

Функция объявлена в файле coresrv/syscalls.h.

Retcode Recv(Handle handle, SMsgHdr *msgIn);

Функция блокирует вызывающий поток до получения IPC-запроса. Функция вызывается серверным процессом.

Параметры:

  • handle – серверный IPC-дескриптор используемого канала;
  • msgIn – буфер под IPC-запрос.

Возвращаемое значение:

  • rcOk – IPC-запрос успешно получен;
  • rcInvalidArgument – IPC-запрос имеет некорректную структуру;
  • rcSecurityDisallow – отправка IPC-запроса запрещена модулем безопасности KSM.

Возможны другие коды возврата.

В начало
[Topic ipc_recv]

Reply()

Функция объявлена в файле coresrv/syscalls.h.

Retcode Reply(Handle handle, const SMsgHdr *msgOut);

Функция отправляет IPC-ответ и блокирует вызывающий поток до получения ответа клиентом или получения ошибки. Функция вызывается серверным процессом.

Параметры:

  • handle – серверный IPC-дескриптор используемого канала;
  • msgOut – буфер, содержащий IPC-ответ.

Возвращаемое значение:

  • rcOk – IPC-ответ успешно получен клиентом;
  • rcInvalidArgument – IPC-ответ имеет некорректную структуру;
  • rcSecurityDisallow – отправка IPC-ответа запрещена модулем безопасности KSM.

Возможны другие коды возврата.

В начало
[Topic ipc_reply][Topic posix_api]

Ограничения поддержки POSIX

В KasperskyOS ограниченно реализован интерфейс POSIX с ориентацией на стандарт POSIX.1-2008 (без поддержки XSI). Прежде всего ограничения связаны с обеспечением безопасности.

Ограничения затрагивают:

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

Ограничения представлены:

  • нереализованными интерфейсами;
  • интерфейсами, которые реализованы с отклонениями от стандарта POSIX.1-2008;
  • интерфейсами-заглушками, которые не выполняют никаких действий, кроме присвоения переменной errno значения ENOSYS и возвращения значения -1.

В KasperskyOS сигналы не могут прервать системные вызовы Call(), Recv(), Reply(), которые обеспечивают работу библиотек, реализующих интерфейс POSIX.

Ядро KasperskyOS не посылает сигналы.

Ограничения взаимодействия между процессами

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

fork()

Создать новый (дочерний) процесс.

Заглушка

unistd.h

pthread_

atfork()

Зарегистрировать обработчики, которые вызываются перед и после создания дочернего процесса.

Не реализован

pthread.h

wait()

Ожидать остановки или завершения дочернего процесса.

Заглушка

sys/wait.h

waitid()

Ожидать изменения состояния дочернего процесса.

Не реализован

sys/wait.h

waitpid()

Ожидать остановки или завершения дочернего процесса.

Заглушка

sys/wait.h

execl()

Запустить исполняемый файл.

Заглушка

unistd.h

execle()

Запустить исполняемый файл.

Заглушка

unistd.h

execlp()

Запустить исполняемый файл.

Заглушка

unistd.h

execv()

Запустить исполняемый файл.

Заглушка

unistd.h

execve()

Запустить исполняемый файл.

Заглушка

unistd.h

execvp()

Запустить исполняемый файл.

Заглушка

unistd.h

fexecve()

Запустить исполняемый файл.

Заглушка

unistd.h

setpgid()

Перевести процесс в другую группу или создать группу.

Заглушка

unistd.h

setsid()

Создать сессию.

Не реализован

unistd.h

getpgrp()

Получить идентификатор группы для вызывающего процесса.

Не реализован

unistd.h

getpgid()

Получить идентификатор группы.

Заглушка

unistd.h

getppid()

Получить идентификатор родительского процесса.

Не реализован

unistd.h

getsid()

Получить идентификатор сессии.

Заглушка

unistd.h

times()

Получить значения времени для процесса и его потомков.

Заглушка

sys/times.h

kill()

Послать сигнал процессу или группе процессов.

Можно посылать только сигнал SIGTERM. Параметр pid игнорируется.

signal.h

pause()

Ожидать сигнала.

Не реализован

unistd.h

sigpending()

Проверить наличие полученных заблокированных сигналов.

Не реализован

signal.h

sigprocmask()

Получить и изменить набор заблокированных сигналов.

Заглушка

signal.h

sigsuspend()

Ожидать сигнала.

Заглушка

signal.h

sigwait()

Ожидать сигнала из заданного набора сигналов.

Заглушка

signal.h

sigqueue()

Послать сигнал процессу.

Не реализован

signal.h

sigtimedwait()

Ожидать сигнала из заданного набора сигналов.

Не реализован

signal.h

sigwaitinfo()

Ожидать сигнала из заданного набора сигналов.

Не реализован

signal.h

sem_init()

Создать неименованный семафор.

Нельзя создать неименованный семафор для синхронизации между процессами. Если передать функции ненулевое значение через параметр pshared, то она только вернет значение -1 и присвоит переменной errno значение ENOTSUP.

semaphore.h

sem_open()

Создать/открыть именованный семафор.

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

semaphore.h

pthread_

mutexattr_

setpshared()

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

Нельзя задать атрибут мьютекса, который разрешает использование мьютекса несколькими процессами. Если передать функции значение PTHREAD_PROCESS_SHARED через параметр pshared, то она только вернет значение ENOSYS.

pthread.h

pthread_

barrierattr_

setpshared()

Задать атрибут барьера, который разрешает использование барьера несколькими процессами.

Нельзя задать атрибут барьера, который разрешает использование барьера несколькими процессами. Если передать функции значение PTHREAD_PROCESS_SHARED через параметр pshared, то она только вернет значение ENOSYS.

pthread.h

pthread_

condattr_

setpshared()

Задать атрибут условной переменной, который разрешает использование условной переменной несколькими процессами.

Нельзя задать атрибут условной переменной, который разрешает использование условной переменной несколькими процессами. Если передать функции значение PTHREAD_PROCESS_SHARED через параметр pshared, то она только вернет значение ENOSYS.

pthread.h

pthread_

rwlockattr_

setpshared()

Задать атрибут объекта блокировки чтения-записи, который разрешает использование объекта блокировки чтения-записи несколькими процессами.

Нельзя задать атрибут объекта блокировки чтения-записи, который разрешает использование объекта блокировки чтения-записи несколькими процессами. Если передать функции значение PTHREAD_PROCESS_SHARED через параметр pshared, то она только вернет значение ENOSYS.

pthread.h

pthread_

spin_init()

Создать спин-блокировку.

Нельзя создать спин-блокировку для синхронизации между процессами. Если передать функции значение PTHREAD_PROCESS_SHARED через параметр pshared, то это значение будет проигнорировано.

pthread.h

shm_open()

Создать или открыть объект разделяемой памяти.

Не реализован

sys/mman.h

mmap()

Отобразить в память.

Нельзя выполнить отображение в память для взаимодействия между процессами. Если передать функции значения MAP_SHARED и PROT_WRITE через параметры flags и prot соответственно, то функция вернет значение MAP_FAILED и присвоит переменной errno значение EACCES. Для остальных возможных значений параметра prot значение MAP_SHARED параметра flags будет проигнорировано. Кроме того, через параметр prot нельзя передавать сочетания флагов PROT_WRITE|PROT_EXEC и PROT_READ|PROT_WRITE|PROT_EXEC. В этом случае функция только возвращает значение MAP_FAILED и присваивает переменной errno значение ENOMEM.

sys/mman.h

mprotect()

Задать права доступа к памяти.

По умолчанию функция работает как заглушка. Чтобы использовать функцию, требуется задать специальные параметры ядра KasperskyOS.

sys/mman.h

pipe()

Создать неименованный канал.

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

unistd.h

mkfifo()

Создать специальный файл FIFO (именованный канал).

Заглушка

sys/stat.h

mkfifoat()

Создать специальный файл FIFO (именованный канал).

Не реализован

sys/stat.h

Ограничения взаимодействия между потоками исполнения посредством сигналов

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

pthread_kill()

Послать сигнал потоку исполнения.

Нельзя послать сигнал потоку исполнения. Если передать функции номер сигнала через параметр sig, то она только вернет значение ENOSYS.

signal.h

pthread_sigmask()

Получить и изменить набор заблокированных сигналов.

Заглушка

signal.h

siglongjmp()

Восстановить состояние потока управления и маску сигналов.

Не реализован

setjmp.h

sigsetjmp()

Сохранить состояние потока управления и маску сигналов.

Не реализован

setjmp.h

Ограничения стандартного ввода-вывода

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

dprintf()

Выполнить форматированный вывод в файл.

Не реализован

stdio.h

fmemopen()

Использовать память как поток данных (stream).

Не реализован

stdio.h

open_memstream()

Использовать динамически выделенную память как поток данных (stream).

Не реализован

stdio.h

vdprintf()

Выполнить форматированный вывод в файл.

Не реализован

stdio.h

Ограничения асинхронного ввода-вывода

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

aio_cancel()

Отменить запросы ввода-вывода, которые ожидают обработки.

Не реализован

aio.h

aio_error()

Получить ошибку операции асинхронного ввода-вывода.

Не реализован

aio.h

aio_fsync()

Запросить выполнение операций ввода-вывода.

Не реализован

aio.h

aio_read()

Запросить чтение из файла.

Не реализован

aio.h

aio_return()

Получить статус операции асинхронного ввода-вывода.

Не реализован

aio.h

aio_suspend()

Ожидать выполнения операций асинхронного ввода-вывода.

Не реализован

aio.h

aio_write()

Запросить запись в файл.

Не реализован

aio.h

lio_listio()

Запросить выполнение набора операций ввода-вывода.

Не реализован

aio.h

Ограничения использования робастных мьютексов

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

pthread_mutex_consistent()

Вернуть робастный мьютекс в консистентное состояние.

Не реализован

pthread.h

pthread_mutexattr_getrobust()

Получить атрибут робастности мьютекса.

Не реализован

pthread.h

pthread_mutexattr_setrobust()

Задать атрибут робастности мьютекса.

Не реализован

pthread.h

Ограничения работы с терминалом

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

ctermid()

Получить путь к файлу управляющего терминала.

Функция только возвращает или передает через параметр s пустую строку.

stdio.h

tcsetattr()

Задать параметры терминала.

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

termios.h

tcdrain()

Ожидать завершения вывода.

Функция только возвращает значение -1.

termios.h

tcflow()

Приостановить или возобновить прием или передачу данных.

Приостановка вывода и запуск приостановленного вывода не поддерживаются.

termios.h

tcflush()

Очистить очередь ввода или очередь вывода, или обе эти очереди.

Функция только возвращает значение -1.

termios.h

tcsendbreak()

Разорвать соединение с терминалом на заданное время.

Функция только возвращает значение -1.

termios.h

ttyname()

Получить путь к файлу терминала.

Функция только возвращает нулевой указатель.

unistd.h

ttyname_r()

Получить путь к файлу терминала.

Функция только возвращает значение ошибки.

unistd.h

tcgetpgrp()

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

Функция только возвращает значение -1.

unistd.h

tcsetpgrp()

Задать идентификатор группы процессов, использующих терминал.

Функция только возвращает значение -1.

unistd.h

tcgetsid()

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

Функция только возвращает значение -1.

termios.h

Ограничения работы с оболочкой

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

popen()

Создать дочерний процесс для выполнения команды и канал с этим процессом.

Функция только присваивает переменной errno значение ENOSYS и возвращает значение NULL.

stdio.h

pclose()

Закрыть канал с дочерним процессом, созданным функцией popen(), и ожидать завершения этого дочернего процесса.

Функцию нельзя использовать, так как ее входным параметром является дескриптор потока данных, возвращаемый функцией popen(), которая не может вернуть ничего, кроме значения NULL.

stdio.h

system()

Создать дочерний процесс для выполнения команды.

Заглушка

stdlib.h

wordexp()

Раскрыть строку как в оболочке.

Не реализован

wordexp.h

wordfree()

Освободить память, выделенную для результатов вызова интерфейса wordexp().

Не реализован

wordexp.h

Ограничения манипуляций с дескрипторами файлов

Интерфейс

Назначение

Реализация

Заголовочный файл по стандарту POSIX.1-2008

dup()

Сделать копию дескриптора открытого файла.

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

fcntl.h

dup2()

Сделать копию дескриптора открытого файла.

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

fcntl.h

В начало
[Topic posix_uns_ifaces]

Совместное использование POSIX и других интерфейсов

Использование libkos совместно с Pthreads

В потоке исполнения, созданном с помощью Pthreads, нельзя использовать следующие интерфейсы libkos:

Следующие интерфейсы libkos можно использовать совместно с Pthreads (и другими интерфейсами POSIX):

Использование POSIX совместно с libkos threads

Методы POSIX нельзя использовать в потоках исполнения, созданных с помощью libkos threads.

Использование IPC совместно с Pthreads/libkos threads

Методы для IPC можно использовать в любых потоках исполнения, созданных с использованием Pthreads или libkos threads.

В начало
[Topic posix_and_libkos]

Компонент MessageBus

Компонент MessageBus реализует шину сообщений, которая обеспечивает прием, распределение и доставку сообщений между приложениями, работающими под KasperskyOS. Шина построена по принципу издатель-подписчик. Использование шины сообщений позволяет избежать создания большого количества IPC-каналов для связывания каждого приложения-подписчика с каждым приложением-издателем.

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

Компонент MessageBus представляет собой дополнительный уровень абстракции над KasperskyOS IPC, который позволяет упростить процесс разработки и развития приложений прикладного уровня. MessageBus является отдельной программой доступ к которой осуществляется через IPC, но при этом разработчикам предоставляется библиотека доступа к MessageBus, которая позволяет избежать использования IPC-вызовов напрямую.

API библиотеки доступа предоставляет следующие интерфейсы:

  • IProviderFactory – предоставляет фабричные методы для получения доступа к экземплярам остальных интерфейсов;
  • IProviderControl – интерфейс для регистрации и дерегистрации издателя и подписчика в шине;
  • IProvider (компонент MessageBus) – интерфейс для передачи сообщения в шину;
  • ISubscriber – интерфейс обратного вызова для передачи сообщения подписчику;
  • IWaiter – интерфейс ожидания обратного вызова при появлении соответствующего сообщения.

Структура сообщения

Каждое сообщение содержит два параметра:

  • topic – идентификатор темы сообщения;
  • id – дополнительный параметр, специфицирующий сообщение.

Параметры topic и id уникальны для каждого сообщения. Интерпретация topic+id определяется контрактом между издателем и подписчиком. Например, если изменяются конфигурационные данные с которыми работают издатель и подписчик, издатель высылает сообщение об изменении данных и id конкретной записи с новыми данными. Подписчик, пользуясь отличными от MessageBus механизмами, получает новые данные по ключу id.

В этом разделе

Интерфейс IProviderFactory

Интерфейс IProviderControl

Интерфейс IProvider (компонент MessageBus)

Интерфейсы ISubscriber, IWaiter и ISubscriberRunner

В начало
[Topic messagebus_component]

Интерфейс IProviderFactory

Интерфейс IProviderFactory предоставляет фабричные методы для получения интерфейсов, необходимых для работы с компонентом MessageBus.

Описание интерфейса IProviderFactory представлено в файле messagebus/i_messagebus_control.h.

Для получения экземпляра интерфейса IProviderFactory используется свободная функция InitConnection(), которая принимает имя IPC-соединения прикладной программы с программой MessageBus. Имя соединения задается в файле init.yaml.in при описании конфигурации решения. В случае успешного подключения выходной параметр содержит указатель на интерфейс IProviderFactory.

  • Для получения интерфейса регистрации и дерегистрации (см. "Интерфейс IProviderControl") издателей и подписчиков в шине сообщений используется метод IProviderFactory::CreateBusControl().
  • Для получения интерфейса, содержащего методы для отправки издателем сообщений в шину (см. "Интерфейс IProvider (компонент MessageBus)"), используется метод IProviderFactory::CreateBus().
  • Для получения интерфейсов, содержащих методы для получения подписчиком сообщений из шины (см. "Интерфейсы ISubscriber, IWaiter и ISubscriberRunner") используются методы IProviderFactory::CreateCallbackWaiter и IProviderFactory::CreateSubscriberRunner().

    Мы не рекомендуем использовать интерфейс IWaiter, поскольку вызов метода этого интерфейса является блокирующим.

i_messagebus_control.h (фрагмент)

class IProviderFactory

{

...

virtual fdn::ResultCode CreateBusControl(IProviderControlPtr& controlPtr) = 0;

virtual fdn::ResultCode CreateBus(IProviderPtr& busPtr) = 0;

virtual fdn::ResultCode CreateCallbackWaiter(IWaiterPtr& waiterPtr) = 0;

virtual fdn::ResultCode CreateSubscriberRunner(ISubscriberRunnerPtr& runnerPtr) = 0;

...

};

...

fdn::ResultCode InitConnection(const std::string& connectionId, IProviderFactoryPtr& busFactoryPtr);

В начало
[Topic messagebus_component_iproviderfactory]

Интерфейс IProviderControl

Интерфейс IProviderControl предоставляет методы для регистрации и дерегистрации издателей и подписчиков в шине сообщений.

Описание интерфейса IProviderControl представлено в файле messagebus/i_messagebus_control.h.

Для получение экземпляра интерфейса используется интерфейс IProviderFactory.

Регистрация и дерегистрация издателя

Для регистрации издателя в шине сообщений используется метод IProviderControl::RegisterPublisher(). Метод принимает тему сообщения и помещает в выходной параметр уникальный идентификатор клиента шины. Если тема уже зарегистрирована в шине, то вызов будет отклонен и идентификатор клиента не будет заполнен.

Для дерегистрации издателя в шине сообщений используется метод IProviderControl::UnregisterPublisher(). Метод принимает идентификатор клиента шины, полученный при регистрации. Если указан идентификатор не зарегистрированный как идентификатор издателя, то вызов будет отклонен.

i_messagebus_control.h (фрагмент)

class IProviderControl

{

...

virtual fdn::ResultCode RegisterPublisher(const Topic& topic, ClientId& id) = 0;

virtual fdn::ResultCode UnregisterPublisher(ClientId id) = 0;

...

};

Регистрация и дерегистрация подписчика

Для регистрации подписчика в шине сообщений используется метод IProviderControl::RegisterSubscriber(). Метод принимает имя подписчика и список тем, на которые нужно подписаться, а в выходной параметр помещает уникальный идентификатор клиента шины.

Для дерегистрации подписчика в шине сообщений используется метод IProviderControl::UnregisterSubscriber(). Метод принимает идентификатор клиента шины, полученный при регистрации. Если указан идентификатор не зарегистрированный как идентификатор подписчика, то вызов будет отклонен.

i_messagebus_control.h (фрагмент)

class IProviderControl

{

...

virtual fdn::ResultCode RegisterSubscriber(const std::string& subscriberName, const std::set<Topic>& topics, ClientId& id) = 0;

virtual fdn::ResultCode UnregisterSubscriber(ClientId id) = 0;

...

};

В начало
[Topic messagebus_component_icontrol]

Интерфейс IProvider (компонент MessageBus)

Интерфейс IProvider предоставляет методы для отправки издателем сообщений в шину.

Описание интерфейса IProvider представлено в файле messagebus/i_messagebus.h.

Для получение экземпляра интерфейса используется интерфейс IProviderFactory.

Отправка сообщения в шину

Для оправки сообщения в шину используется метод IProvider::Push(). Метод принимает идентификатор клиента шины, полученный при регистрации, и идентификатор сообщения. Если очередь сообщений в шине заполнена, то вызов будет отклонен.

i_messagebus.h (фрагмент)

class IProvider

{

public:

...

virtual fdn::ResultCode Push(ClientId id, BundleId dataId) = 0;

...

};

В начало
[Topic messagebus_component_iprovider]

Интерфейсы ISubscriber, IWaiter и ISubscriberRunner

Интерфейсы ISubscriber, IWaiter и ISubscriberRunner предоставляют методы для получения и обработки подписчиком сообщений из шины.

Описания интерфейсов ISubscriber, IWaiter и ISubscriberRunner представлено в файле messagebus/i_subscriber.h.

Для получение экземпляров интерфейсов IWaiter и ISubscriberRunner используется интерфейс IProviderFactory. Реализация callback-интерфейса ISubscriber предоставляется приложением-подписчиком.

Получение сообщения из шины

Чтобы перевести подписчика в режим ожидания сообщения от шины, вы можете использовать метод IWaiter::Wait() или ISubscriberRunner::Run(). Методы принимают идентификатор клиента шины и указатель на callback-интерфейс ISubscriber. Если идентификатор клиента не зарегистрирован, то вызов будет отклонен.

Мы не рекомендуем использовать интерфейс IWaiter, поскольку вызов метода IWaiter::Wait() является блокирующим.

При получении сообщения из шины будет вызван метод ISubscriber::OnMessage(). Метод принимает тему и идентификатор сообщения.

i_subscriber.h (фрагмент)

class ISubscriber

{

...

virtual fdn::ResultCode OnMessage(const std::string& topic, BundleId id) = 0;

};

...

class IWaiter

{

...

[[deprecated("Use ISubscriberRunner::Run method instead.")]]

virtual fdn::ResultCode Wait(ClientId id, const ISubscriberPtr& subscriberPtr) = 0;

};

...

class ISubscriberRunner

{

...

virtual fdn::ResultCode Run(ClientId id, const ISubscriberPtr& subscriberPtr) = 0;

};

В начало
[Topic messagebus_component_isubwait]

Коды возврата

Общие сведения

В решении на базе KasperskyOS коды возврата функций различных API (например, API библиотек libkos и kdf, драйверов, транспортного кода, прикладного ПО) имеют тип 32-битного знакового целого числа. Этот тип определен в заголовочном файле sysroot-*-kos/include/rtl/retcode.h из состава KasperskyOS SDK так:

typedef __INT32_TYPE__ Retcode;

Множество кодов возврата состоит из кода успеха со значением 0 и кодов ошибок. Код ошибки интерпретируется как структура данных, формат которой описан в заголовочном файле sysroot-*-kos/include/rtl/retcode.h из состава KasperskyOS SDK. Этот формат предусматривает наличие нескольких полей, которые содержат не только сведения о результатах вызова функции, но и следующую дополнительную информацию:

  • Флаг в поле Customer, сигнализирующий о том, что код ошибки определен разработчиками решения на базе KasperskyOS, а не разработчиками ПО из состава KasperskyOS SDK.

    Благодаря флагу в поле Customer разработчики решения на базе KasperskyOS и разработчики ПО из состава KasperskyOS SDK могут определять коды ошибок из непересекающихся множеств.

  • Глобальный идентификатор кода ошибки в поле Space.

    Глобальные идентификаторы позволяют определять непересекающиеся множества кодов ошибок. Коды ошибок могут быть общими и специфичными. Общие коды ошибок могут использоваться в API любых компонентов решения и в API любых составных частей компонентов решения (например, драйвер или VFS могут быть составной частью компонента решения). Специфичные коды ошибок используются в API одного или нескольких компонентов решения или в API одной или нескольких составных частей компонентов решения.

    Например, идентификатору RC_SPACE_GENERAL соответствуют коды общих ошибок, идентификатору RC_SPACE_KERNEL соответствуют коды ошибок ядра, идентификатору RC_SPACE_DRIVERS соответствуют коды ошибок драйверов.

  • Локальный идентификатор кода ошибки в поле Facility.

    Локальные идентификаторы позволяют определять непересекающиеся подмножества кодов ошибок в рамках множества кодов ошибок, которые соответствуют одному глобальному идентификатору. Например, множество кодов ошибок с глобальным идентификатором RC_SPACE_DRIVERS включает непересекающиеся подмножества кодов ошибок с локальными идентификаторами RC_FACILITY_I2C, RC_FACILITY_USB, RC_FACILITY_BLKDEV.

Глобальные и локальные идентификаторы специфичных кодов ошибок назначаются разработчиками решения на базе KasperskyOS и разработчиками ПО из состава KasperskyOS SDK независимо друг от друга. То есть формируется два множества глобальных идентификаторов. Каждый глобальный идентификатор имеет уникальное смысловое значение в рамках одного множества. Каждый локальный идентификатор имеет уникальное смысловое значение в рамках множества локальных идентификаторов, относящихся к одному глобальному идентификатору. Общие коды ошибок могут использоваться в любых API.

Такой централизованный подход позволяет избежать появления в решении на базе KasperskyOS одинаковых кодов ошибок с разными смысловыми значениями. Это нужно, чтобы исключить проблему транзита кодов ошибок через разные API. Например, такая проблема возникает, когда драйверы вызывают функции библиотеки kdf, получают коды ошибок и возвращают эти коды через свои API. Если формировать коды ошибок без централизованного подхода, то один и тот же код ошибки может иметь разные смысловые значения для библиотеки kdf и для драйвера. В таких условиях драйверы возвращают корректные коды ошибок, если только выполняется преобразование кодов ошибок библиотеки kdf в коды ошибок каждого из драйверов. То есть коды ошибок в решении на базе KasperskyOS назначаются так, чтобы не выполнять конвертацию этих кодов при транзите через разные API.

Приведенные здесь сведения о кодах возврата не относятся к функциям интерфейса POSIX и API стороннего ПО, используемого в решениях на базе KasperskyOS.

Общие коды возврата

Коды возврата, которые являются общими для API любых компонентов решения и их составных частей, определены в заголовочном файле sysroot-*-kos/include/rtl/retcode.h из состава KasperskyOS SDK. Описание общих кодов возврата приведено в таблице ниже.

Общие коды возврата

Код возврата

Описание

rcOk (соответствует значению 0)

Функция завершилась успешно.

rcInvalidArgument

Аргумент функции некорректен.

rcNotConnected

Нет соединения между клиентской и серверной сторонами взаимодействия.

Например, отсутствует серверный IPC-дескриптор.

rcOutOfMemory

Недостаточно памяти для выполнения операции.

rcBufferTooSmall

Слишком маленький буфер.

rcInternalError

Функция завершилась с внутренней ошибкой, которая связана с некорректной логикой.

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

rcTransferError

Ошибка отправки IPC-сообщения.

rcReceiveError

Ошибка приема IPC-сообщения.

rcSourceFault

IPC-сообщение не было передано из-за источника IPC-сообщения.

rcTargetFault

IPC-сообщение не было передано из-за приемника IPC-сообщения.

rcIpcInterrupt

IPC прервано другим потоком процесса.

rcRestart

Сигнализирует, что функцию нужно вызвать повторно.

rcFail

Функция завершилась с ошибкой.

rcNoCapability

Операция над ресурсом недоступна.

rcNotReady

Инициализация не выполнена.

rcUnimplemented

Функция не реализована.

rcBufferTooLarge

Слишком большой буфер.

rcBusy

Ресурс временно недоступен.

rcResourceNotFound

Ресурс не найден.

rcTimeout

Время ожидания истекло.

rcSecurityDisallow

Операция запрещена механизмами безопасности.

rcFutexWouldBlock

Операция приведет к блокировке.

rcAbort

Операция прервана.

rcInvalidThreadState

В обработчике прерывания вызвана недопустимая функция.

rcAlreadyExists

Множество элементов уже содержит добавляемый элемент.

rcInvalidOperation

Операция не может быть выполнена.

rcHandleRevoked

Права доступа к ресурсу отозваны.

rcQuotaExceeded

Квота на ресурс превышена.

rcDeviceNotFound

Устройство не найдено.

Определение кодов ошибок

Чтобы определить код ошибки, разработчику решения на базе KasperskyOS нужно использовать макрос MAKE_RETCODE(), определенный в заголовочном файле sysroot-*-kos/include/rtl/retcode.h из состава KasperskyOS SDK. При этом через параметр customer нужно передать символьную константу RC_CUSTOMER_TRUE.

Пример:

#define LV_EBADREQUEST MAKE_RETCODE(RC_CUSTOMER_TRUE, RC_SPACE_APPS, RC_FACILITY_LogViewer, 5, "Bad request")

Описание ошибки, которое передается через параметр desc, не используется макросом MAKE_RETCODE(). Это описание требуется, чтобы создать базу данных кодов ошибок при сборке решения на базе KasperskyOS. В настоящее время механизм для создания и использования такой базы данных не реализован.

Чтение полей структуры кода ошибки

Макросы RC_GET_CUSTOMER(), RC_GET_SPACE(), RC_GET_FACILITY() и RC_GET_CODE(), определенные в заголовочном файле sysroot-*-kos/include/rtl/retcode.h из состава KasperskyOS SDK, позволяют читать поля структуры кода ошибки.

Макросы RETCODE_HR_PARAMS() и RETCODE_HR_FMT(), определенные в заголовочном файле sysroot-*-kos/include/rtl/retcode_hr.h из состава KasperskyOS SDK, используются для форматированного вывода сведений об ошибке.

В начало
[Topic return_codes]