Содержание
- KasperskyOS API
- Библиотека libkos
- Общие сведения о библиотеке libkos
- Память
- Аллокация памяти
- Потоки
- Дескрипторы
- Уведомления
- Процессы
- Динамическое создание каналов
- Примитивы синхронизации
- KosCondvarBroadcast()
- KosCondvarDeinit()
- KosCondvarInit()
- KosCondvarSignal()
- KosCondvarWait()
- KosCondvarWaitTimeout()
- KosEventDeinit()
- KosEventInit()
- KosEventReset()
- KosEventSet()
- KosEventWait()
- KosEventWaitTimeout()
- KosMutexDeinit()
- KosMutexInit()
- KosMutexInitEx()
- KosMutexLock()
- KosMutexLockTimeout()
- KosMutexTryLock()
- KosMutexUnlock()
- KosRWLockDeinit()
- KosRWLockInit()
- KosRWLockRead()
- KosRWLockTryRead()
- KosRWLockTryWrite()
- KosRWLockUnlock()
- KosRWLockWrite()
- KosSemaphoreDeinit()
- KosSemaphoreInit()
- KosSemaphoreSignal()
- KosSemaphoreTryWait()
- KosSemaphoreWait()
- KosSemaphoreWaitTimeout()
- DMA-буферы
- IOMMU
- Порты ввода-вывода
- IoReadIoPort8(), IoReadIoPort16(), IoReadIoPort32()
- IoReadIoPortBuffer8(), IoReadIoPortBuffer16(), IoReadIoPortBuffer32()
- IoWriteIoPort8(), IoWriteIoPort16(), IoWriteIoPort32()
- IoWriteIoPortBuffer8(), IoWriteIoPortBuffer16(), IoWriteIoPortBuffer32()
- KnIoPermitPort()
- KnRegisterPort8(), KnRegisterPort16(), KnRegisterPort32()
- KnRegisterPorts()
- Ввод-вывод через память (MMIO)
- Прерывания
- Освобождение ресурсов
- Время
- Очереди
- Барьеры памяти
- Получение сведений об использовании процессорного времени и памяти
- Отправка и прием IPC-сообщений
- Поддержка POSIX
- Компонент MessageBus
- Коды возврата
- Библиотека 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
:
Файлы, используемые библиотекой 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
– заголовочные файлы ядра.
Состояния памяти
Каждая страница виртуальной памяти может быть свободна (free), зарезервирована (reserved) или передана (committed).
Переход из свободного состояния в зарезервированное называется резервированием (аллокацией). Предварительное резервирование памяти (без передачи физических страниц) позволяет приложению заранее разметить свое адресное пространство. Обратный переход из зарезервированного в свободное состояние называется освобождением памяти.
Назначение физической памяти для ранее зарезервированной страницы виртуальной памяти называется передачей памяти, а обратный переход из переданного состояния в зарезервированное – возвращением памяти.
Переходы между состояниями страницы памяти
В начало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()
.
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.
В началоKnVmDecommit()
Функция объявлена в файле coresrv/vmm/vmm_api.h
.
Retcode KnVmDecommit(void *addr, rtl_size_t size);
Функция освобождает диапазон страниц (переводит их в зарезервированное состояние).
Параметры:
addr
– странично-выровненный базовый виртуальный адрес участка памяти;size
– размер участка памяти в байтах (должен быть кратен размеру страницы).
В случае успешного освобождения страниц функция возвращает rcOk.
В начало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 – полный доступ к содержимому страницы (эти записи эквивалентны).
KnVmUnmap()
Функция объявлена в файле coresrv/vmm/vmm_api.h
.
Retcode KnVmUnmap(void *addr, rtl_size_t size);
Функция освобождает участок памяти.
Параметры:
addr
– странично-выровненный адрес участка памяти;size
– размер участка памяти.
В случае успешного освобождения страниц функция возвращает rcOk.
В начало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()
.
KosMemAllocEx()
Функция объявлена в файле kos/alloc.h
.
void *KosMemAllocEx(rtl_size_t size, rtl_size_t align, int zeroed);
Функция аналогична KosMemAlloc()
, но при этом имеет дополнительные параметры:
align
– выравнивание участка памяти в байтах (степень двойки);zeroed
– нужно ли заполнить участок памяти нулями (1 – заполнить, 0 – не заполнять).
KosMemFree()
Функция объявлена в файле kos/alloc.h
.
void KosMemFree(void *ptr);
Функция освобождает участок памяти, выделенный с помощью функции KosMemAlloc()
, KosMemZalloc()
или KosMemAllocEx()
.
ptr
– указатель на освобождаемый участок памяти.
KosMemGetSize()
Функция объявлена в файле kos/alloc.h
.
rtl_size_t KosMemGetSize(void *ptr);
Функция возвращает размер (в байтах) участка памяти, выделенного с помощью функции KosMemAlloc()
, KosMemZalloc()
или KosMemAllocEx()
.
ptr
– указатель на участок памяти.
KosMemZalloc()
Функция объявлена в файле kos/alloc.h
.
void *KosMemZalloc(rtl_size_t size);
Функция аналогична KosMemAlloc()
, но при этом заполняет выделяемый участок памяти нулями.
KosThreadCallback()
Прототип callback-функции объявлен в файле kos/thread.h
.
typedef void KosThreadCallback(KosThreadCallbackReason reason);
/* Аргумент callback-функции */
typedef enum KosThreadCallbackReason {
KosThreadCallbackReasonCreate,
KosThreadCallbackReasonDestroy,
} KosThreadCallbackReason;
При создании нового потока все зарегистрированные callback-функции будут вызваны с аргументом KosThreadCallbackReasonCreate
, при завершении – с аргументом KosThreadCallbackReasonDestroy
.
KosThreadCallbackRegister()
Функция объявлена в файле kos/thread.h
.
Retcode KosThreadCallbackRegister(KosThreadCallback *callback);
Функция регистрирует пользовательскую callback-функцию. При создании и завершении потока будут вызваны все зарегистрированные callback-функции.
В началоKosThreadCallbackUnregister()
Функция объявлена в файле kos/thread.h
.
Retcode KosThreadCallbackUnregister(KosThreadCallback *callback);
Функция дерегистрирует (удаляет из списка вызываемых) пользовательскую callback-функцию.
В начало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);
/* Ожидание завершения потоков */
...
}
KosThreadCurrentId()
Функция объявлена в файле kos/thread.h
.
Tid KosThreadCurrentId(void);
Функция запрашивает TID вызывающего потока.
В случае успеха функция возвращает идентификатор потока (TID).
В началоKosThreadExit()
Функция объявлена в файле kos/thread.h
.
void KosThreadExit(rtl_int32_t exitCode);
Функция принудительно завершает текущий поток с кодом выхода exitCode
.
KosThreadGetStack()
Функция объявлена в файле kos/thread.h
.
void *KosThreadGetStack(Tid tid, rtl_uint32_t *size);
Функция получает стек потока с идентификатором tid
.
Выходной параметр size
содержит размер стека.
В случае успеха функция возвращает указатель на начало стека.
В началоKosThreadOnce()
Функция объявлена в файле kos/thread.h
.
typedef int KosThreadOnceState;
Retcode KosThreadOnce(KosThreadOnceState *onceControl,
void (* initRoutine) (void));
Функция позволяет вызвать заданную процедуру initRoutine
в точности один раз, даже при вызове из нескольких потоков.
Параметр onceControl
предназначен для контроля однократного вызова процедуры.
При успешном вызове процедуры, а также если она уже была вызвана ранее, функция KosThreadOnce()
возвращает rcOk.
KosThreadResume()
Функция объявлена в файле kos/thread.h
.
Retcode KosThreadResume(Tid tid);
Функция возобновляет поток с идентификатором tid
, созданный в приостановленном состоянии.
В случае успеха функция возвращает rcOk.
В началоKosThreadSleep()
Функция объявлена в файле kos/thread.h
.
Retcode KosThreadSleep(rtl_uint32_t mdelay);
Функция приостанавливает выполнение текущего потока на mdelay
миллисекунд.
В случае успеха функция возвращает rcOk.
В началоKosThreadSuspend()
Функция объявлена в файле kos/thread.h
.
Retcode KosThreadSuspend(Tid tid);
Функция необратимо останавливает текущий поток, не завершая его.
Параметр tid
должен быть равен идентификатору текущего потока (ограничение текущей имплементации).
В случае успеха функция возвращает rcOk.
В началоKosThreadTerminate()
Функция объявлена в файле kos/thread.h
.
Retcode KosThreadTerminate(Tid tid, rtl_int32_t exitCode);
Функция завершает поток вызывающего процесса. Параметр tid
задает идентификатор потока.
Если tid
указывает на текущий поток, то параметр exitCode
задает код выхода потока.
В случае успеха функция возвращает rcOk.
В началоKosThreadTlsGet()
Функция объявлена в файле kos/thread.h
.
void *KosThreadTlsGet(void);
Функция возвращает указатель на локальное хранилище потока (TLS) или RTL_NULL, если TLS отсутствует.
В началоKosThreadTlsSet()
Функция объявлена в файле kos/thread.h
.
Retcode KosThreadTlsSet(void *tls);
Функция задает адрес локального хранилища потока (TLS).
Входной аргумент tls
содержит адрес TLS.
KosThreadWait()
Функция объявлена в файле kos/thread.h
.
int KosThreadWait(rtl_uint32_t tid, rtl_uint32_t timeout);
Функция приостанавливает выполнение текущего потока до момента завершения потока с идентификатором tid
или до истечения timeout
миллисекунд.
Вызов KosThreadWait()
с нулевым значением timeout
аналогичен вызову KosThreadYield()
.
В случае успеха функция возвращает rcOk, в случае таймаута rcTimeout.
В началоKosThreadYield()
Функция объявлена в файле kos/thread.h
.
void KosThreadYield(void);
Функция передает выполнение вызвавшего ее потока следующему потоку.
Вызов KosThreadYield()
аналогичен вызову KosThreadSleep()
с нулевым значением mdelay
.
KnHandleClose()
Функция объявлена в файле coresrv/handle/handle_api.h
.
Retcode KnHandleClose(Handle handle);
Функция удаляет дескриптор handle
.
В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
Удаление дескриптора не делает недействительными его предков и потомков (в отличие от отзыва дескриптора, который делает недействительными его потомков – см. KnHandleRevoke()
и KnHandleRevokeSubtree()
). Удаление дескриптора также не нарушает целостность дерева наследования дескрипторов. Место удаленного дескриптора занимает его предок – он становится непосредственным предком потомков удаленного дескриптора.
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, иначе возвращает код ошибки.
В начало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;
}
KnHandleRevoke()
Функция объявлена в файле coresrv/handle/handle_api.h
.
Retcode KnHandleRevoke(Handle handle);
Функция удаляет дескриптор handle
и отзывает всех его потомков.
В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
Отзыв дескрипторов не удаляет их, но через отозванные дескрипторы невозможно обращаться к ресурсам. Любая функция, которая принимает дескриптор, завершается с ошибкой rcHandleRevoked, если эта функция вызывается с отозванным дескриптором.
KnHandleRevokeSubtree()
Функция объявлена в файле coresrv/handle/handle_api.h
.
Retcode KnHandleRevokeSubtree(Handle handle, Handle badge);
Функция отзывает дескрипторы, которые образуют поддерево наследования дескриптора handle
.
Корневым узлом поддерева наследования является дескриптор, который порожден передачей дескриптора handle
в ассоциации с объектом контекста передачи ресурса badge
.
В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
Отзыв дескрипторов не удаляет их, но через отозванные дескрипторы невозможно обращаться к ресурсам. Любая функция, которая принимает дескриптор, завершается с ошибкой rcHandleRevoked, если эта функция вызывается с отозванным дескриптором.
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, иначе возвращает код ошибки.
В началоnk_is_handle_dereferenced()
Функция объявлена в файле nk/types.h
.
static inline
nk_bool_t nk_is_handle_dereferenced(const nk_handle_desc_t *desc);
Функция возвращает отличное от нуля значение, если дескриптор в транспортном контейнере дескриптора desc
получен в результате операции разыменования дескриптора.
Функция возвращает нуль, если дескриптор в транспортном контейнере дескриптора desc
получен в результате операции передачи дескриптора.
Управление дескрипторами
Для управления дескрипторами используются функции менеджера дескрипторов (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.
Маска прав дескриптора
Маска прав дескриптора имеет размер 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
).
При создании дескриптора пользовательского ресурса маска прав задается пользователем.
При передаче дескриптора маска прав задается пользователем, но передаваемые права доступа не могут быть повышены относительно прав доступа, которые имеет процесс.
В началоСоздание дескрипторов
Дескрипторы пользовательских ресурсов создаются поставщиками ресурсов. Для создания дескрипторов пользовательских ресурсов используется функция 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()
зарезервирован для возможного использования в будущем и не влияет на ее поведение, но должен принимать значение из интервала, указанного в комментарии к функции.
О маске прав дескриптора см. "Маска прав дескриптора".
В началоПередача дескрипторов
Общие сведения
Передача дескрипторов между программами осуществляется для того, чтобы клиенты (программы, которые используют ресурсы) получали доступ к требуемым ресурсам. По причине локальности дескрипторов передача дескриптора инициирует на стороне принимающей программы создание дескриптора из ее пространства дескрипторов. Этот дескриптор регистрируется как потомок отправленного дескриптора и идентифицирует тот же ресурс.
Один дескриптор может быть передан многократно одной или нескольким программам. Каждая передача порождает нового потомка переданного дескриптора на стороне принимающей программы. Программа может передавать дескрипторы, которые она получила от других программ или ядра KasperskyOS (при создании дескрипторов системных ресурсов). Поэтому у дескриптора может быть несколько поколений потомков. Иерархия порождения дескрипторов для каждого ресурса хранится в ядре KasperskyOS в виде дерева наследования дескрипторов.
Программа может передавать дескрипторы как пользовательских, так и системных ресурсов, если права доступа этих дескрипторов разрешают выполнять передачу. У потомка может быть меньше прав доступа, чем у предка. Например, передающая программа имеет права доступа к файлу на чтение и запись, а передает права доступа только на чтение. Передающая программа также может запретить принимающей программе дальнейшую передачу дескриптора. Права доступа задаются в передаваемой маске прав дескриптора.
Условия для передачи дескрипторов
Чтобы программы могли передавать дескрипторы между собой, должны выполняться следующие условия:
- Между программами создан IPC-канал.
- Политика безопасности решения (
security.psl
) разрешает взаимодействие программ. - Реализованы интерфейсные методы для передачи дескрипторов.
- Программа-клиент получила идентификатор службы (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()
используются только при разыменовании дескрипторов.
Сценарии передачи дескрипторов
Сценарий передачи дескрипторов от программы-клиента программе-серверу включает следующие шаги:
- Передающая программа-клиент упаковывает дескрипторы и маски прав дескрипторов в поля структуры запросов
*_req
типаnk_handle_desc_t
. - Передающая программа-клиент вызывает интерфейсный метод для передачи дескрипторов программе-серверу. Этот метод выполняет системный вызов
Call()
. - Принимающая программа-сервер получает запрос, выполняя системный вызов
Recv()
. - Диспетчер на стороне принимающей программы-сервера вызывает метод, который соответствует запросу. Этот метод извлекает дескрипторы и маски прав дескрипторов из полей структуры запросов
*_req
типаnk_handle_desc_t
.
Сценарий передачи дескрипторов от программы-сервера программе-клиенту включает следующие шаги:
- Принимающая программа-клиент вызывает интерфейсный метод для получения дескрипторов от программы-сервера. Этот метод выполняет системный вызов
Call()
. - Передающая программа-сервер получает запрос, выполняя системный вызов
Recv()
. - Диспетчер на стороне передающей программы-сервера вызывает метод, который соответствует запросу. Этот метод упаковывает дескрипторы, маски прав дескрипторов и дескрипторы объектов контекстов передачи ресурсов в поля структуры ответов
*_res
типаnk_handle_desc_t
. - Передающая программа-сервер отвечает на запрос, выполняя системный вызов
Reply()
. - На стороне принимающей программы-клиента интерфейсный метод возвращает управление. После этого принимающая программа-клиент извлекает дескрипторы и маски прав дескрипторов из полей структуры ответов
*_res
типаnk_handle_desc_t
.
Если передающая программа задает в передаваемой маске прав дескриптора больше прав доступа, чем задано для передаваемого дескриптора (владельцем которого она является), то передача не осуществляется. В этом случае выполнение системного вызова Call()
передающей или принимающей программой-клиентом, а также выполнение системного вызова Reply()
передающей программой-сервером завершается с ошибкой rcSecurityDisallow
.
Разыменование дескрипторов
Разыменование дескриптора – это операция, при которой программа-клиент отправляет программе-серверу дескриптор, а программа-сервер получает указатель на контекст передачи ресурса, маску прав отправленного дескриптора и предка отправленного программой-клиентом дескриптора, которым программа-сервер уже владеет. Разыменование выполняется, когда программа-клиент, вызывая методы работы с ресурсом (например, чтения, записи, закрытия доступа), передает программе-серверу дескриптор, который был получен от этой программы-сервера при открытии доступа к ресурсу.
Разыменование дескрипторов требует выполнения тех же условий и использует те же механизмы и типы данных, что и передача дескрипторов. Сценарий разыменования дескриптора включает следующие шаги:
- Программа-клиент упаковывает дескриптор в поле структуры запросов
*_req
типаnk_handle_desc_t
. - Программа-клиент вызывает интерфейсный метод для отправки дескриптора программе-серверу с целью выполнения действий с ресурсом. Этот метод выполняет системный вызов
Call()
. - Программа-сервер принимает запрос, выполняя системный вызов
Recv()
. - Диспетчер на стороне программы-сервера вызывает метод, который соответствует запросу. Этот метод проверяет, что выполнена именно операция разыменования, а не передача дескриптора. Затем вызванный метод опционально проверяет, что права доступа разыменованного дескриптора (который отправлен программой-клиентом) разрешают запрашиваемые действия с ресурсом, и извлекает указатель на контекст передачи ресурса из поля структуры запросов
*_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)
В общем случае программе-серверу не требуется дескриптор, который получен в результате разыменования, поскольку программа-сервер, как правило, сохраняет дескрипторы, которыми владеет, например, в составе контекстов пользовательских ресурсов. Но при необходимости программа-сервер может извлечь этот дескриптор из транспортного контейнера дескриптора.
В началоОтзыв дескрипторов
Программа может отзывать потомков дескриптора, которым она владеет. Отзыв дескрипторов осуществляется согласно дереву наследования дескрипторов.
Отзыв дескрипторов не удаляет их, но через отозванные дескрипторы невозможно обращаться к ресурсам. Любая функция, которая принимает дескриптор, завершается с ошибкой 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);
Уведомление о состоянии ресурсов
Программы могут отслеживать события, которые происходят с ресурсами (как системными, так и пользовательскими), а также информировать о событиях с пользовательскими ресурсами другие программы.
Функции подсистемы уведомлений объявлены в заголовочном файле coresrv/handle/notice_api.h
. Подсистема уведомлений предусматривает использование масок событий.
Маска событий – значение, биты которого интерпретируются как события, которые должны отслеживаться или уже произошли. Маска событий имеет размер 32 бита и состоит из общей и специальной части. Общая часть описывает события, неспецифичные для любых ресурсов (флаги этих событий определены в заголовочном файле handle/event_descr.h
). Например, в общей части находится флаг EVENT_OBJECT_DESTROYED
, который определяет событие "прекращение существования ресурса". Специальная часть описывает события, специфичные для пользовательского ресурса. Структура специальной части определяется поставщиком ресурса с использованием макроса OBJECT_EVENT_SPEC()
, который определен в заголовочном файле handle/event_descr.h
. Поставщику ресурса необходимо экспортировать публичные заголовочные файлы с описанием структуры специальной части.
Сценарий получения уведомлений о событиях, которые происходят с ресурсом, включает следующие шаги:
- Функцией
KnNoticeCreate()
создается приемник уведомлений (объект, в котором накапливаются уведомления). - В приемник уведомлений функцией
KnNoticeSubscribeToObject()
добавляются записи вида "ресурс – маска событий", чтобы настроить его на прием уведомлений о событиях, которые происходят с интересующими ресурсами. Набор отслеживаемых событий задается для каждого ресурса маской событий. - Чтобы извлекать уведомления из приемника уведомлений, вызывается функция
KnNoticeGetEvent()
.
Чтобы уведомлять программы о событиях, которые происходят с пользовательским ресурсом, используется функция KnNoticeSetObjectEvent()
. Вызов этой функции инициирует появление соответствующих уведомлений в приемниках уведомлений, которые настроены на отслеживание этих событий с этим ресурсом.
notice_api.h (фрагмент)
/**
* Функция создает приемник уведомлений notice.
* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
*/
Retcode Kn
NoticeCreate(Notice *notice);
/**
* Функция добавляет запись вида "ресурс – маска событий"
* в приемник уведомлений notice, чтобы он принимал уведомления о
* событиях, которые происходят с ресурсом object и соответствуют
* маске событий evMask. Входной параметр evId задает идентификатор
* записи, который назначается пользователем и используется, чтобы
* идентифицировать запись в полученных уведомлениях.
* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
*/
Retcode Kn
NoticeSubscribeToObject(Notice notice,
Handle object,
rtl_uint32_t evMask,
rtl_uintptr_t evId);
/**
* Функция извлекает уведомления из приемника уведомлений notice,
* ожидая наступления событий в течение msec миллисекунд.
* Входной параметр countMax задает максимальное число
* уведомлений, которое может быть извлечено. Выходной параметр
* events содержит набор извлеченных уведомлений типа EventDesc.
* Выходной параметр count содержит число уведомлений, которые
* были извлечены.
* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
*/
Retcode Kn
NoticeGetEvent(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 Kn
NoticeSetObjectEvent(Handle object, rtl_uint32_t evMask);
Удаление дескрипторов
Программа может удалять дескрипторы, которыми она владеет. Удаление дескриптора не делает недействительными его предков и потомков (в отличие от отзыва дескриптора, который делает недействительными его потомков). То есть через предков и потомков удаленного дескриптора обеспечивается доступ к ресурсу, который они идентифицируют. Также удаление дескриптора не нарушает целостность дерева наследования дескрипторов, которое относится к ресурсу, идентифицируемому этим дескриптором. Место удаленного дескриптора занимает его предок. То есть предок удаленного дескриптора становится непосредственным предком потомков удаленного дескриптора.
Удаление дескрипторов выполняется функцией KnHandleClose()
, которая объявлена в заголовочном файле coresrv/handle/handle_api.h
.
handle_api.h (фрагмент)
/**
* Функция удаляет дескриптор handle.
* В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
*/
Retcode KnHandleClose(Handle handle);
Пример использования 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);
}
Сценарий включает следующие шаги:
- Поставщик ресурса создает контекст пользовательского ресурса и вызывает функцию
KnHandleCreateUserObject()
для создания дескриптора ресурса. Поставщик ресурса сохраняет дескриптор ресурса в контексте пользовательского ресурса. - Клиент вызывает метод открытия доступа к ресурсу
OpenResource()
.- Поставщик ресурса создает контекст передачи ресурса и вызывает функцию
KnHandleCreateBadge()
для создания объекта контекста передачи ресурса и настройки приемника уведомлений на прием уведомлений о закрытии и прекращении существования объекта контекста передачи ресурса. Поставщик ресурса сохраняет дескриптор объекта контекста передачи ресурса и указатель на контекст пользовательского ресурса в контексте передачи ресурса. - Поставщик ресурса, используя макрос
nk_handle_desc()
, упаковывает дескриптор ресурса, маску прав дескриптора и указатель на объект контекста передачи ресурса в транспортный контейнер дескриптора. - Выполняется передача дескриптора от поставщика ресурса клиенту, в результате которой клиент получает потомка дескриптора, которым владеет поставщик ресурса.
- Вызов метода
OpenResource()
завершается успешно. Клиент извлекает дескриптор и маску прав дескриптора из транспортного контейнера дескриптора функциямиnk_get_handle()
иnk_get_rights()
соответственно. Маска прав дескриптора не требуется клиенту для обращения к ресурсу и передается, чтобы клиент мог узнать свои права доступа к ресурсу.
- Поставщик ресурса создает контекст передачи ресурса и вызывает функцию
- Клиент вызывает метод использования ресурса
UseResource()
.- Дескриптор, который получен от поставщика ресурса на шаге 2, используется в качестве аргумента метода
UseResource()
. Перед вызовом этого метода клиент упаковывает дескриптор в транспортный контейнер дескриптора макросомnk_handle_desc()
. - Выполняется разыменование дескриптора, в результате которого поставщик ресурса получает указатель на контекст передачи ресурса.
- Поставщик ресурса, используя функцию
nk_is_handle_dereferenced()
, проверяет, что выполнена операция разыменования, а не передача дескриптора. - Поставщик ресурса проверяет, что права доступа разыменованного дескриптора (который отправлен клиентом) разрешают запрашиваемую операцию над ресурсом, и извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора. Для этого поставщик ресурса использует функцию
nk_get_badge_op()
, которая извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора, если в полученной маске прав установлены флаги, соответствующие запрашиваемой операции. - Поставщик ресурса, используя контекст передачи ресурса и контекст пользовательского ресурса, выполняет запрашиваемую клиентом операцию над ресурсом. Затем поставщик ресурса отправляет клиенту результат выполнения этой операции.
- Вызов метода
UseResource()
завершается успешно. Клиент получает результат выполнения операции над ресурсом.
- Дескриптор, который получен от поставщика ресурса на шаге 2, используется в качестве аргумента метода
- Клиент вызывает метод закрытия доступа к ресурсу
CloseResource()
.- Дескриптор, который получен от поставщика ресурса на шаге 2, используется в качестве аргумента метода
CloseResource()
. Перед вызовом этого метода клиент упаковывает дескриптор в транспортный контейнер дескриптора макросомnk_handle_desc()
. После вызова методаCloseResource()
клиент удаляет дескриптор функциейKnHandleClose()
. - Выполняется разыменование дескриптора, в результате которого поставщик ресурса получает указатель на контекст передачи ресурса.
- Поставщик ресурса, используя функцию
nk_is_handle_dereferenced()
, проверяет, что выполнена операция разыменования, а не передача дескриптора. - Поставщик ресурса, используя функцию
nk_get_badge()
, извлекает указатель на контекст передачи ресурса из транспортного контейнера дескриптора. - Поставщик ресурса отзывает дескриптор, которым владеет клиент, функцией
KnHandleRevokeSubtree()
. В качестве аргументов этой функции используются дескриптор ресурса, которым владеет поставщик ресурса, и дескриптор объекта контекста передачи ресурса. Поставщик ресурса получает доступ к этим дескрипторам через указатель на контекст передачи ресурса. (Технически не требуется отзывать дескриптор, которым владеет клиент, так как клиент его уже удалил. Но поставщик ресурса не может быть уверен в том, что клиент удалил дескриптор, поэтому выполняется отзыв). - Вызов метода
CloseResource()
завершается успешно.
- Дескриптор, который получен от поставщика ресурса на шаге 2, используется в качестве аргумента метода
- Поставщик ресурса освобождает память, которая была выделена под контекст передачи ресурса и контекст пользовательского ресурса.
- Поставщик ресурса вызовом функции
KnNoticeGetEvent()
получает уведомление, что объект контекста передачи ресурса закрыт, и удаляет дескриптор объекта контекста передачи ресурса функциейKnHandleClose()
. - Поставщик ресурса вызовом функции
KnNoticeGetEvent()
получает уведомление, что объект контекста передачи ресурса прекратил свое существование, и освобождает память, которая была выделена под контекст передачи ресурса. - Поставщик ресурса удаляет дескриптор ресурса функцией
KnHandleClose()
и освобождает память, которая была выделена под контекст пользовательского ресурса.
- Поставщик ресурса вызовом функции
Маска событий
Маска событий – значение, биты которого интерпретируются как события, которые должны отслеживаться или уже произошли. Маска событий имеет размер 32 бита и состоит из общей и специальной части. Общая часть описывает события, неспецифичные для любых ресурсов (флаги этих событий определены в заголовочном файле handle/event_descr.h
). Например, в общей части находится флаг EVENT_OBJECT_DESTROYED
, который определяет событие "прекращение существования ресурса". Специальная часть описывает события, специфичные для пользовательского ресурса. Структура специальной части определяется поставщиком ресурса с использованием макроса OBJECT_EVENT_SPEC()
, который определен в заголовочном файле handle/event_descr.h
. Поставщику ресурса необходимо экспортировать публичные заголовочные файлы с описанием структуры специальной части.
EventDesc
Структура, описывающая уведомление, объявлена в файле coresrv/handle/notice_api.h
.
typedef struct {
rtl_uintptr_t eventId;
rtl_uint32_t eventMask;
} EventDesc;
eventId
– идентификатор записи "ресурс – маска событий" в приемнике уведомлений.
eventMask
– маска событий, которые произошли.
KnNoticeCreate()
Функция объявлена в файле coresrv/handle/notice_api.h
.
Retcode KnNoticeCreate(Notice *notice);
Функция создает приемник уведомлений notice
(объект, в котором накапливаются уведомления).
В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
В начало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);
KnNoticeSetObjectEvent()
Функция объявлена в файле coresrv/handle/notice_api.h
.
Retcode KnNoticeSetObjectEvent(Handle object, rtl_uint32_t evMask);
Функция сигнализирует, что события из маски событий evMask
произошли с ресурсом object
.
Нельзя устанавливать флаги общей части маски событий, так как о событиях из общей части маски событий может сигнализировать только ядро KasperskyOS.
В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
В начало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()
.
EntityConnect()
Функция объявлена в заголовочном файле coresrv/entity/entity_api.h
.
Retcode EntityConnect(Entity *cl, Entity *sr);
Функция соединяет процессы IPC-каналом. Для этого функция создает IPC-дескрипторы для процесса-клиента cl
и процесса-сервера sr
, а затем связывает дескрипторы друг с другом. Создаваемый канал будет включен в группу каналов по умолчанию (имя этой группы совпадает с именем процесса-сервера). Соединяемые процессы должны находиться в остановленном состоянии.
В случае успеха функция возвращает rcOk.
В началоEntityConnectToService()
Функция объявлена в заголовочном файле coresrv/entity/entity_api.h
.
Retcode EntityConnectToService(Entity *cl, Entity *sr, const char *name);
Функция соединяет процессы IPC-каналом. Для этого функция создает IPC-дескрипторы для процесса-клиента cl
и процесса-сервера sr
, а затем связывает дескрипторы друг с другом. Создаваемый канал будет включен в группу каналов с именем name
. Соединяемые процессы должны находиться в остановленном состоянии.
В случае успеха функция возвращает rcOk.
В начало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;
EntityInit()
Функция объявлена в заголовочном файле coresrv/entity/entity_api.h
.
Entity *EntityInit(const EntityInfo *info);
Функция создает процесс. Параметр info
задает имя класса процесса и (опционально) его службы, аргументы и переменные окружения.
Создаваемый процесс будет иметь имя по умолчанию (совпадает с именем класса процесса), а также и имя исполняемого файлу по умолчанию (также совпадает с именем класса процесса).
В случае успеха функция возвращает структуру, описывающую новый процесс. Созданный процесс находится в остановленном состоянии.
В случае ошибки функция возвращает RTL_NULL.
В начало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.
В началоEntityRun()
Функция объявлена в заголовочном файле coresrv/entity/entity_api.h
.
Retcode EntityRun(Entity *entity);
Функция запускает процесс, находящийся в остановленном состоянии. Процесс описывается структурой entity
.
В случае успеха функция возвращает rcOk.
В начало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, иначе возвращает код ошибки.
В начало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, иначе возвращает код ошибки.
В началоKnCmDrop()
Функция объявлена в файле coresrv/cm/cm_api.h
.
Retcode KnCmDrop(const char *client, const char *service);
Функция отклоняет запрос клиентского процесса на создание канала, полученный ранее с помощью вызова KnCmListen()
. Функция вызывается серверным процессом.
Параметры:
client
– имя клиентского процесса, отправляющего запрос на создание канала;service
– полное квалифицированное имя службы, запрошенное клиентским процессом (например,blkdev.ata
).
В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
В начало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, иначе возвращает код ошибки.
В начало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, иначе возвращает код ошибки.
В начало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, иначе возвращает код ошибки.
В начало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, иначе возвращает код ошибки.
В начало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, иначе возвращает код ошибки.
В началоKosCondvarBroadcast()
Функция объявлена в файле kos/condvar.h
.
void KosCondvarBroadcast(KosCondvar *condvar);
Функция пробуждает все потоки из очереди потоков, заблокированных посредством условной переменной condvar
.
KosCondvarDeinit()
Функция объявлена в файле kos/condvar.h
.
void KosCondvarDeinit(KosCondvar *condvar);
Функция деинициализирует условную переменную condvar
.
KosCondvarInit()
Функция объявлена в файле kos/condvar.h
.
void KosCondvarInit(KosCondvar *condvar);
Функция инициализирует условную переменную condvar
.
KosCondvarSignal()
Функция объявлена в файле kos/condvar.h
.
void KosCondvarSignal(KosCondvar *condvar);
Функция пробуждает один поток из очереди потоков, заблокированных посредством условной переменной condvar
.
KosCondvarWait()
Функция объявлена в файле kos/condvar.h
.
Retcode KosCondvarWait(KosCondvar *condvar, KosMutex *mutex);
Функция блокирует исполнение текущего потока посредством условной переменной condvar
, пока он не будет пробужден с помощью KosCondvarSignal() или KosCondvarBroadcast().
mutex
– мьютекс, который будет использован для защиты критической секции.
В случае успеха функция возвращает rcOk.
В началоKosCondvarWaitTimeout()
Функция объявлена в файле kos/condvar.h
.
Retcode KosCondvarWaitTimeout(KosCondvar *condvar, KosMutex *mutex,
rtl_uint32_t mdelay);
Функция блокирует исполнение текущего потока посредством условной переменной condvar
, пока он не будет пробужден с помощью KosCondvarSignal() или KosCondvarBroadcast(). Поток блокируется не более чем на mdelay
миллисекунд.
mutex
– мьютекс, который будет использован для защиты критической секции.
Функция возвращает rcOk в случае успеха и rcTimeout, если время ожидания истекло.
В началоKosEventDeinit()
Функция объявлена в файле kos/event.h
.
void KosEventDeinit(KosEvent *event);
Функция освобождает ресурсы, связанные с событием event
(уничтожает событие).
KosEventInit()
Функция объявлена в файле kos/event.h
.
void KosEventInit(KosEvent *event);
Функция создает событие event
.
Созданное событие находится в несигнальном состоянии.
В началоKosEventReset()
Функция объявлена в файле kos/event.h
.
void KosEventReset(KosEvent *event);
Функция переводит событие event
в несигнальное состояние (сбрасывает событие).
KosEventSet()
Функция объявлена в файле kos/event.h
.
void KosEventSet(KosEvent *event);
Функция переводит событие event
в сигнальное состояние (сигнализирует событие) и таким образом пробуждает все потоки, ожидающие его.
KosEventWait()
Функция объявлена в файле kos/event.h
.
void KosEventWait(KosEvent *event, rtl_bool reset);
Функция ожидает перехода события в сигнальное состояние.
Параметр reset
указывает, следует ли автоматически сбросить событие при успешном завершении ожидания.
Функция возвращает rcOk в случае успеха.
В началоKosEventWaitTimeout()
Функция объявлена в файле kos/event.h
.
Retcode KosEventWaitTimeout(KosEvent *event, rtl_bool reset,
rtl_uint32_t msec);
Функция ожидает перехода события в сигнальное состояние в течение msec
миллисекунд.
Параметр reset
указывает, следует ли автоматически сбросить событие при успешном завершении ожидания.
Функция возвращает rcOk в случае успеха и rcTimeout при превышении таймаута.
В началоKosMutexDeinit()
Функция объявлена в файле kos/mutex.h
.
void KosMutexDeinit(KosMutex *mutex);
Функция уничтожает мьютекст mutex
.
KosMutexInit()
Функция объявлена в файле kos/mutex.h
.
void KosMutexInit(KosMutex *mutex);
Функция выполняет инициализацию мьютекса mutex
в незаблокированном состоянии.
KosMutexInitEx()
Функция объявлена в файле kos/mutex.h
.
void KosMutexInitEx(KosMutex *mutex, int recursive);
Функция выполняет инициализацию мьютекса mutex
в незаблокированном состоянии.
Для инициализации рекурсивного мьютекса в параметр recursive
нужно передать значение 1.
KosMutexLock()
Функция объявлена в файле kos/mutex.h
.
void KosMutexLock(KosMutex *mutex);
Функция захватывает мьютекс mutex
.
Если мьютекс уже захвачен, поток блокируется в ожидании его разблокировки.
В началоKosMutexLockTimeout()
Функция объявлена в файле kos/mutex.h
.
Retcode KosMutexLockTimeout(KosMutex *mutex, rtl_uint32_t mdelay);
Функция захватывает мьютекс mutex
.
Если мьютекс уже захвачен, поток блокируется на mdelay
миллисекунд в ожидании его разблокировки.
Функция возвращает rcOk в случае успеха и rcTimeout, если время ожидания истекло.
В началоKosMutexTryLock()
Функция объявлена в файле kos/mutex.h
.
Retcode KosMutexTryLock(KosMutex *mutex);
Функция делает попытку захвата мьютекса mutex
.
Функция возвращает rcOk, если мьютекс удалось захватить и rcBusy, если мьютекс не удалось захватить, так как он уже захвачен.
В началоKosMutexUnlock()
Функция объявлена в файле kos/mutex.h
.
void KosMutexUnlock(KosMutex *mutex);
Функция разблокирует мьютекс mutex
.
Для разблокировки рекурсивного мьютекса нужно сделать столько вызовов KosMutexUnlock()
, сколько раз рекурсивный мьютекс был заблокирован.
KosRWLockDeinit()
Функция объявлена в файле kos/rwlock.h
.
void KosRWLockDeinit(KosRWLock *rwlock);
Функция деинициализирует блокировку чтения-записи rwlock
.
KosRWLockInit()
Функция объявлена в файле kos/rwlock.h
.
void KosRWLockInit(KosRWLock *rwlock);
Функция инициализирует блокировку чтения-записи rwlock
.
KosRWLockRead()
Функция объявлена в файле kos/rwlock.h
.
void KosRWLockRead(KosRWLock *rwlock);
Функция блокирует потоки чтения.
В началоKosRWLockTryRead()
Функция объявлена в файле kos/rwlock.h
.
Retcode KosRWLockTryRead(KosRWLock *rwlock);
Функция делает попытку блокировки потоков чтения.
В случае успеха функция возвращает rcOk.
В началоKosRWLockTryWrite()
Функция объявлена в файле kos/rwlock.h
.
Retcode KosRWLockTryWrite(KosRWLock *rwlock);
Функция делает попытку блокировки потоков записи.
В случае успеха функция возвращает rcOk.
В началоKosRWLockUnlock()
Функция объявлена в файле kos/rwlock.h
.
void KosRWLockUnlock(KosRWLock *rwlock);
Функция снимает блокировку чтения-записи rwlock
.
KosRWLockWrite()
Функция объявлена в файле kos/rwlock.h
.
void KosRWLockWrite(KosRWLock *rwlock);
Функция блокирует потоки записи.
В началоKosSemaphoreDeinit()
Функция объявлена в файле kos/semaphore.h
.
Retcode KosSemaphoreDeinit(KosSemaphore *semaphore);
Функция уничтожает семафор semaphore
, инициализированный ранее функцией KosSemaphoreInit()
.
Безопасно уничтожать инициализированный семафор, на котором в настоящее время нет заблокированных потоков. Эффект уничтожения семафора, на котором в данный момент заблокированы другие потоки, непредсказуем.
Функция возвращает:
- rcOk в случае успеха;
- rcInvalidArgument, если
semaphore
указывает на невалидный семафор; - rcFail, если есть потоки, заблокированные этим семафором.
KosSemaphoreInit()
Функция объявлена в файле kos/semaphore.h
.
Retcode KosSemaphoreInit(KosSemaphore *semaphore, unsigned count);
Функция инициализирует семафор semaphore
с начальным значением count
.
Функция возвращает:
- rcOk в случае успеха;
- rcInvalidArgument, если
semaphore
указывает на невалидный семафор; - rcFail, если значение
count
превышает KOS_SEMAPHORE_VALUE_MAX.
KosSemaphoreSignal()
Функция объявлена в файле kos/semaphore.h
.
Retcode KosSemaphoreSignal(KosSemaphore *semaphore);
Функция освобождает (сигнализирует) семафор semaphore
.
Функция возвращает:
- rcOk в случае успеха;
- rcInvalidArgument, если
semaphore
указывает на невалидный семафор.
KosSemaphoreTryWait()
Функция объявлена в файле kos/semaphore.h
.
Retcode KosSemaphoreTryWait(KosSemaphore *semaphore);
Функция делает попытку захвата семафора semaphore
.
Функция возвращает:
- rcOk в случае успеха;
- rcInvalidArgument, если
semaphore
указывает на невалидный семафор; - rcBusy, если семафор уже захвачен.
KosSemaphoreWait()
Функция объявлена в файле kos/semaphore.h
.
Retcode KosSemaphoreWait(KosSemaphore *semaphore);
Функция ожидает захвата семафора semaphore
.
Функция возвращает:
- rcOk в случае успеха;
- rcInvalidArgument, если
semaphore
указывает на невалидный семафор.
KosSemaphoreWaitTimeout()
Функция объявлена в файле kos/semaphore.h
.
Retcode KosSemaphoreWaitTimeout(KosSemaphore *semaphore, rtl_uint32_t mdelay);
Функция ожидает захвата семафора semaphore
в течение mdelay
миллисекунд.
Функция возвращает:
- rcOk в случае успеха;
- rcInvalidArgument, если
semaphore
указывает на невалидный семафор; - rcTimeout, если время ожидания истекло.
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;
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 – управление кэшированием страниц памяти.
KnIoDmaBegin()
Функция объявлена в файле coresrv/io/dma.h
.
Retcode KnIoDmaBegin(Handle rid, Handle *handle);
Функция разрешает устройству доступ к DMA-буферу с дескриптором rid
.
Выходной параметр handle
содержит дескриптор данного разрешения.
В случае успеха функция возвращает rcOk.
Пример использования – см. KnIoDmaCreate().
Чтобы запретить устройству доступ к DMA-буферу, необходимо вызвать функцию KnIoClose()
, передав в нее дескриптор разрешения handle
.
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
;flags
– DMA-флаги.
Выходной параметр 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;
}
KnIoDmaGetInfo()
Функция объявлена в файле coresrv/io/dma.h
.
Retcode KnIoDmaGetInfo(Handle rid, DmaInfo **outInfo);
Функция получает информацию о DMA-буфере с дескриптором rid
.
Выходной параметр outInfo
содержит информацию о DMA-буфере.
В случае успеха функция возвращает rcOk.
В отличие от KnIoDmaGetPhysInfo()
, параметр outInfo
содержит не физические, а IOMMU-адреса DMA-блоков.
KnIoDmaGetPhysInfo()
Функция объявлена в файле coresrv/io/dma.h
.
Retcode KnIoDmaGetPhysInfo(Handle rid, DmaInfo **outInfo);
Функция получает информацию о DMA-буфере с дескриптором rid
.
Выходной параметр outInfo
содержит информацию о DMA-буфере.
В случае успеха функция возвращает rcOk.
В отличие от KnIoDmaGetInfo()
, параметр outInfo
содержит не IOMMU-адреса, а физические адреса DMA-блоков.
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
.
KnIommuAttachDevice()
Функция объявлена в файле coresrv/iommu/iommu_api.h
.
Retcode KnIommuAttachDevice(rtl_uint16_t bdf);
Функция добавляет PCI-устройство с идентификатором bdf
в группу IOMMU вызывающего процесса (IOMMU domain).
В случае успеха возвращает rcOk.
В началоKnIommuDetachDevice()
Функция объявлена в файле coresrv/iommu/iommu_api.h
.
Retcode KnIommuDetachDevice(rtl_uint16_t bdf);
Функция удаляет PCI-устройство с идентификатором bdf
из группы IOMMU вызывающего процесса (IOMMU domain).
В случае успеха функция возвращает rcOk.
В начало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
и возвращают прочитанное значение.
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
– длина последовательности.
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
.
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
– длина последовательности.
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;
}
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()
.
KnRegisterPorts()
Функция объявлена в файле coresrv/io/ports.h
.
Retcode KnRegisterPorts(rtl_uint16_t port, rtl_size_t size, Handle *outRid);
Функция регистрирует диапазон портов (участок памяти) с базовым адресом port
и размером size
в байтах и назначает ему дескриптор outRid
.
Возвращает rcOk в случае успешного выделения диапазона портов.
Пример использования – см. KnIoPermitPort()
.
Если диапазон портов больше не используется, его необходимо освободить с помощью функции KnIoClose()
.
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
– длина последовательности.
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
, и возвращают прочитанное значение.
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
- длина последовательности.
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
.
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;
}
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()
.
Прерывания
Описанный здесь интерфейс является низкоуровневым. Для работы с прерываниями в большинстве случаев рекомендуется использовать интерфейс, предоставляемый библиотекой kdf.
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 – приоритет реального времени.
KnIoDetachIrq()
Функция объявлена в файле coresrv/io/irq.h
.
Retcode KnIoDetachIrq(Handle rid);
Функция отвязывает вызывающий поток от прерывания.
rid
– дескриптор прерывания, полученный с помощью вызова KnRegisterIrq()
;
В случае успеха функция возвращает rcOk, иначе возвращает код ошибки.
В началоKnIoDisableIrq()
Функция объявлена в файле coresrv/io/irq.h
.
Retcode KnIoDisableIrq(Handle rid);
Функция маскирует (запрещает) прерывание с дескриптором rid
.
В случае успеха функция возвращает rcOk.
В началоKnIoEnableIrq()
Функция объявлена в файле coresrv/io/irq.h
.
Retcode KnIoEnableIrq(Handle rid);
Функция демаскирует (разрешает) прерывание с дескриптором rid
.
В случае успеха функция возвращает rcOk.
В началоKnRegisterIrq()
Функция объявлена в файле coresrv/io/irq.h
.
Retcode KnRegisterIrq(int irq, Handle *outRid);
Функция регистрирует прерывание с номером irq
.
Выходной параметр outRid
содержит дескриптор прерывания.
В случае успеха функция возвращает rcOk.
Если прерывание больше не используется, его необходимо освободить с помощью функции KnIoClose()
.
KnIoClose()
Функция объявлена в файле coresrv/io/io_api.h
.
Retcode KnIoClose(Handle rid);
Функция освобождает зарегистрированный ресурс ввода-вывода (порт/порты ввода-вывода, DMA-буфер, прерывание или участок памяти для MMIO) с дескриптором rid
.
В случае успешного освобождения функция возвращает rcOk.
Пример использования – см. KnIoDmaCreate().
В началоKnGetMSecSinceStart()
Функция объявлена в файле coresrv/time/time_api.h
.
rtl_size_t KnGetMSecSinceStart(void);
Функция возвращает количество миллисекунд, прошедших с момента старта системы.
В начало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;
KnGetSystemTime()
Функция объявлена в файле coresrv/time/time_api.h
.
Retcode KnGetSystemTime(RtlTimeSpec *time);
Функция позволяет получить системное время.
Выходной параметр time
содержит системное POSIX-время в формате RtlTimeSpec
.
KnSetSystemTime()
Функция объявлена в файле coresrv/time/time_api.h
.
Retcode KnSetSystemTime(RtlTimeSpec *time);
Функция позволяет задать системное время.
Параметр time
должен содержать POSIX-время в формате RtlTimeSpec
.
Не рекомендуется вызывать функцию KnSetSystemTime()
в потоке обработчика прерываний.
KnGetSystemTimeRes()
Функция объявлена в файле coresrv/time/time_api.h
.
Retcode KnGetSystemTimeRes(RtlTimeSpec *res);
Функция позволяет получить разрешение источника системного времени.
Выходной параметр res
содержит разрешение формате RtlTimeSpec
.
KnGetUpTime()
Функция объявлена в файле coresrv/time/time_api.h
.
Retcode KnGetUpTime(RtlTimeSpec *time);
Функция позволяет получить время, прошедшее с момента старта системы.
Выходной параметр time
содержит время в формате RtlTimeSpec
.
KnGetUpTimeRes()
Функция объявлена в файле coresrv/time/time_api.h
.
Retcode KnGetUpTimeRes(RtlTimeSpec *res);
Функция позволяет получить разрешение источника времени, значение которого можно получить через KnGetUpTime()
.
Выходной параметр res
содержит разрешение в формате RtlTimeSpec
.
RtlTimeSpec
Формат времени timespec задается структурой RtlTimeSpec
(объявлена в файле rtl/rtc.h
).
typedef struct {
rtl_time_t sec; /**< целое число секунд, прошедшее с начала Unix-эпохи
* или другого заданного момента времени */
rtl_nsecs_t nsec; /**< поправка в наносекундах (число наносекунд,
* прошедших с момента, заданного числом секунд*/
} RtlTimeSpec;
KosQueueAlloc()
Функция объявлена в файле kos/queue.h
.
void *KosQueueAlloc(KosQueueHandle queue);
Функция аллоцирует память под новый объект из буфера очереди queue
.
В случае успеха функция возвращает указатель на память под объект, если буфер заполнен – RTL_NULL.
В началоKosQueueCreate()
Функция объявлена в файле kos/queue.h
.
KosQueueHandle KosQueueCreate(unsigned objCount,
unsigned objSize,
unsigned objAlign,
void *buffer);
Функция создает очередь объектов (fifo) и связанный с ней буфер.
Параметры:
objCount
– максимальное количество объектов в очереди;objSize
– размер объекта (байт);objAlign
– выравнивание объекта в байтах, должно быть степенью двойки;buffer
– указатель на внешний буфер под объекты; если задать его равным RTL_NULL, то буфер будет выделен с помощью функцииKosMemAlloc()
.
Функция возвращает дескриптор созданной очереди и RTL_NULL в случае ошибки.
В началоKosQueueDestroy()
Функция объявлена в файле kos/queue.h
.
void KosQueueDestroy(KosQueueHandle queue);
Функция удаляет очередь queue
и освобождает выделенный под нее буфер.
KosQueueFlush()
Функция объявлена в файле kos/queue.h
.
void KosQueueFlush(KosQueueHandle queue);
Функция извлекает все объекты из очереди queue
и освобождает всю память, занятую ими.
KosQueueFree()
Функция объявлена в файле kos/queue.h
.
void KosQueueFree(KosQueueHandle queue, void *obj);
Функция освобождает память, занимаемую объектом obj
в буфере очереди queue
.
Указатель obj
может быть получен вызовом функции KosQueueAlloc()
или KosQueuePop()
.
Пример использования – см. KosQueuePop()
.
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;
}
KosQueuePush()
Функция объявлена в файле kos/queue.h
.
void KosQueuePush(KosQueueHandle queue, void *obj);
Функция добавляет объект obj
в конец очереди queue
.
Указатель obj
может быть получен вызовом функции KosQueueAlloc()
или KosQueuePop()
.
IoReadBarrier()
Функция объявлена в файле coresrv/io/barriers.h
.
void IoReadBarrier(void);
Функция добавляет барьер чтения из памяти. Linux-аналог: rmb()
.
IoReadWriteBarrier()
Функция объявлена в файле coresrv/io/barriers.h
.
void IoReadWriteBarrier(void);
Функция добавляет обобщенный барьер. Linux-аналог: mb()
.
IoWriteBarrier()
Функция объявлена в файле coresrv/io/barriers.h
.
void IoWriteBarrier(void);
Функция добавляет барьер записи. Linux-аналог: wmb()
.
Получение сведений об использовании процессорного времени и памяти
Библиотека libkos
предоставляет API, который позволяет получить сведения об использовании процессорного времени и памяти. Этот API определен в заголовочном файле sysroot-*-kos/include/coresrv/stat/stat_api.h
из состава KasperskyOS SDK.
Чтобы получить сведения об использовании процессорного времени и памяти, а также другие статистические сведения, нужно собрать решение с версией ядра KasperskyOS, которая поддерживает счетчики производительности. Подробнее см. "Библиотека image".
Получение сведений об использовании процессорного времени
Время работы процессора отсчитывается с момента запуска ядра KasperskyOS.
Чтобы получить сведения об использовании процессорного времени, нужно использовать функции KnGroupStatGetParam()
и KnTaskStatGetParam()
. При этом через параметр param
этих функций нужно передать значения, приведенные в таблице ниже.
Сведения об использовании процессорного времени
Функция |
Значение параметра |
Получаемое значение |
---|---|---|
|
|
Время работы процессора в режиме ядра |
|
|
Время работы процессора в пользовательском режиме |
|
|
Время работы процессора в режиме бездействия |
|
|
Время работы процессора, затраченное на исполнение процесса |
|
|
Время работы процессора, затраченное на исполнение процесса в пользовательском режиме |
Время работы процессора, полученное вызовом функции KnGroupStatGetParam()
или KnTaskStatGetParam()
, выражено в наносекундах.
Получение сведений об использовании памяти
Чтобы получить сведения об использовании памяти, нужно использовать функции KnGroupStatGetParam()
и KnTaskStatGetParam()
. При этом через параметр param
этих функций нужно передать значения, приведенные в таблице ниже.
Сведения об использовании памяти
Функция |
Значение параметра |
Получаемое значение |
---|---|---|
|
|
Размер всей установленной оперативной памяти |
|
|
Размер свободной оперативной памяти |
|
|
Размер оперативной памяти, используемой процессом |
Размер памяти, полученный вызовом функции KnGroupStatGetParam()
или KnTaskStatGetParam()
, представляет собой число страниц памяти. Размер страницы памяти составляет 4 КБ для всех аппаратных платформ, поддерживаемых KasperskyOS.
Размер оперативной памяти, используемой процессом, характеризует только ту память, которая выделена непосредственно для этого процесса. Например, если в память процесса отображен буфер MDL, созданный другим процессом, то размер этого буфера не включается в это значение.
Перечисление процессов
Чтобы получить сведения об использовании процессорного времени и памяти каждым процессом, нужно выполнить следующие действия:
- Получить список процессов вызовом функции
KnGroupStatGetTaskList()
. - Получить число элементов списка процессов вызовом функции
KnTaskStatGetTasksCount()
. - Выполнить в цикле следующие действия:
- Получить элемент списка процессов вызовом функции
KnTaskStatEnumTaskList()
. - Получить имя процесса вызовом функции
KnTaskStatGetName()
.Это требуется, чтобы идентифицировать процесс, для которого будут получены сведения об использовании процессорного времени и памяти.
- Получить сведения об использовании процессорного времени и памяти процессом вызовами функции
KnTaskStatGetParam()
. - Проверить, что процесс не завершился. Если процесс завершился, то не использовать полученные сведения об использовании процессорного времени и памяти этим процессом.
Чтобы проверить, что процесс не завершился, нужно вызвать функцию
KnTaskStatGetParam()
с передачей через параметрparam
значенияTASK_PARAM_STATE
. Должно быть получено значение, отличное отTaskStateTerminated
. - Завершить работу с элементом списка процессов вызовом функции
KnTaskStatCloseTask()
.
- Получить элемент списка процессов вызовом функции
- Завершить работу со списком процессов вызовом функции
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).
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-дескриптор канала не найден.
Возможны другие коды возврата.
В началоRecv()
Функция объявлена в файле coresrv/syscalls.h
.
Retcode Recv(Handle handle, SMsgHdr *msgIn);
Функция блокирует вызывающий поток до получения IPC-запроса. Функция вызывается серверным процессом.
Параметры:
handle
– серверный IPC-дескриптор используемого канала;msgIn
– буфер под IPC-запрос.
Возвращаемое значение:
- rcOk – IPC-запрос успешно получен;
- rcInvalidArgument – IPC-запрос имеет некорректную структуру;
- rcSecurityDisallow – отправка IPC-запроса запрещена модулем безопасности KSM.
Возможны другие коды возврата.
В началоReply()
Функция объявлена в файле coresrv/syscalls.h
.
Retcode Reply(Handle handle, const SMsgHdr *msgOut);
Функция отправляет IPC-ответ и блокирует вызывающий поток до получения ответа клиентом или получения ошибки. Функция вызывается серверным процессом.
Параметры:
handle
– серверный IPC-дескриптор используемого канала;msgOut
– буфер, содержащий IPC-ответ.
Возвращаемое значение:
- rcOk – IPC-ответ успешно получен клиентом;
- rcInvalidArgument – IPC-ответ имеет некорректную структуру;
- rcSecurityDisallow – отправка IPC-ответа запрещена модулем безопасности KSM.
Возможны другие коды возврата.
В началоОграничения поддержки POSIX
В KasperskyOS ограниченно реализован интерфейс POSIX с ориентацией на стандарт POSIX.1-2008 (без поддержки XSI). Прежде всего ограничения связаны с обеспечением безопасности.
Ограничения затрагивают:
- взаимодействие между процессами;
- взаимодействие между потоками исполнения посредством сигналов;
- стандартный ввод-вывод;
- асинхронный ввод-вывод;
- использование робастных мьютексов;
- работу с терминалом;
- использование оболочки;
- манипуляции с дескрипторами файлов.
Ограничения представлены:
- нереализованными интерфейсами;
- интерфейсами, которые реализованы с отклонениями от стандарта POSIX.1-2008;
- интерфейсами-заглушками, которые не выполняют никаких действий, кроме присвоения переменной
errno
значенияENOSYS
и возвращения значения-1
.
В KasperskyOS сигналы не могут прервать системные вызовы Call()
, Recv()
, Reply()
, которые обеспечивают работу библиотек, реализующих интерфейс POSIX.
Ядро KasperskyOS не посылает сигналы.
Ограничения взаимодействия между процессами
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Создать новый (дочерний) процесс. |
Заглушка |
|
|
Зарегистрировать обработчики, которые вызываются перед и после создания дочернего процесса. |
Не реализован |
|
|
Ожидать остановки или завершения дочернего процесса. |
Заглушка |
|
|
Ожидать изменения состояния дочернего процесса. |
Не реализован |
|
|
Ожидать остановки или завершения дочернего процесса. |
Заглушка |
|
|
Запустить исполняемый файл. |
Заглушка |
|
|
Запустить исполняемый файл. |
Заглушка |
|
|
Запустить исполняемый файл. |
Заглушка |
|
|
Запустить исполняемый файл. |
Заглушка |
|
|
Запустить исполняемый файл. |
Заглушка |
|
|
Запустить исполняемый файл. |
Заглушка |
|
|
Запустить исполняемый файл. |
Заглушка |
|
|
Перевести процесс в другую группу или создать группу. |
Заглушка |
|
|
Создать сессию. |
Не реализован |
|
|
Получить идентификатор группы для вызывающего процесса. |
Не реализован |
|
|
Получить идентификатор группы. |
Заглушка |
|
|
Получить идентификатор родительского процесса. |
Не реализован |
|
|
Получить идентификатор сессии. |
Заглушка |
|
|
Получить значения времени для процесса и его потомков. |
Заглушка |
|
|
Послать сигнал процессу или группе процессов. |
Можно посылать только сигнал |
|
|
Ожидать сигнала. |
Не реализован |
|
|
Проверить наличие полученных заблокированных сигналов. |
Не реализован |
|
|
Получить и изменить набор заблокированных сигналов. |
Заглушка |
|
|
Ожидать сигнала. |
Заглушка |
|
|
Ожидать сигнала из заданного набора сигналов. |
Заглушка |
|
|
Послать сигнал процессу. |
Не реализован |
|
|
Ожидать сигнала из заданного набора сигналов. |
Не реализован |
|
|
Ожидать сигнала из заданного набора сигналов. |
Не реализован |
|
|
Создать неименованный семафор. |
Нельзя создать неименованный семафор для синхронизации между процессами. Если передать функции ненулевое значение через параметр |
|
|
Создать/открыть именованный семафор. |
Нельзя открыть именованный семафор, который был создан другим процессом. Именованные семафоры (как и неименованные) являются локальными, то есть они доступны только тому процессу, который их создал. |
|
|
Задать атрибут мьютекса, который разрешает использование мьютекса несколькими процессами. |
Нельзя задать атрибут мьютекса, который разрешает использование мьютекса несколькими процессами. Если передать функции значение |
|
|
Задать атрибут барьера, который разрешает использование барьера несколькими процессами. |
Нельзя задать атрибут барьера, который разрешает использование барьера несколькими процессами. Если передать функции значение |
|
|
Задать атрибут условной переменной, который разрешает использование условной переменной несколькими процессами. |
Нельзя задать атрибут условной переменной, который разрешает использование условной переменной несколькими процессами. Если передать функции значение |
|
|
Задать атрибут объекта блокировки чтения-записи, который разрешает использование объекта блокировки чтения-записи несколькими процессами. |
Нельзя задать атрибут объекта блокировки чтения-записи, который разрешает использование объекта блокировки чтения-записи несколькими процессами. Если передать функции значение |
|
|
Создать спин-блокировку. |
Нельзя создать спин-блокировку для синхронизации между процессами. Если передать функции значение |
|
|
Создать или открыть объект разделяемой памяти. |
Не реализован |
|
|
Отобразить в память. |
Нельзя выполнить отображение в память для взаимодействия между процессами. Если передать функции значения |
|
|
Задать права доступа к памяти. |
По умолчанию функция работает как заглушка. Чтобы использовать функцию, требуется задать специальные параметры ядра KasperskyOS. |
|
|
Создать неименованный канал. |
Нельзя использовать неименованный канал для передачи данных между процессами. Неименованные каналы являются локальными, то есть они доступны только тому процессу, который их создал. |
|
|
Создать специальный файл FIFO (именованный канал). |
Заглушка |
|
|
Создать специальный файл FIFO (именованный канал). |
Не реализован |
|
Ограничения взаимодействия между потоками исполнения посредством сигналов
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Послать сигнал потоку исполнения. |
Нельзя послать сигнал потоку исполнения. Если передать функции номер сигнала через параметр |
|
|
Получить и изменить набор заблокированных сигналов. |
Заглушка |
|
|
Восстановить состояние потока управления и маску сигналов. |
Не реализован |
|
|
Сохранить состояние потока управления и маску сигналов. |
Не реализован |
|
Ограничения стандартного ввода-вывода
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Выполнить форматированный вывод в файл. |
Не реализован |
|
|
Использовать память как поток данных (stream). |
Не реализован |
|
|
Использовать динамически выделенную память как поток данных (stream). |
Не реализован |
|
|
Выполнить форматированный вывод в файл. |
Не реализован |
|
Ограничения асинхронного ввода-вывода
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Отменить запросы ввода-вывода, которые ожидают обработки. |
Не реализован |
|
|
Получить ошибку операции асинхронного ввода-вывода. |
Не реализован |
|
|
Запросить выполнение операций ввода-вывода. |
Не реализован |
|
|
Запросить чтение из файла. |
Не реализован |
|
|
Получить статус операции асинхронного ввода-вывода. |
Не реализован |
|
|
Ожидать выполнения операций асинхронного ввода-вывода. |
Не реализован |
|
|
Запросить запись в файл. |
Не реализован |
|
|
Запросить выполнение набора операций ввода-вывода. |
Не реализован |
|
Ограничения использования робастных мьютексов
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Вернуть робастный мьютекс в консистентное состояние. |
Не реализован |
|
|
Получить атрибут робастности мьютекса. |
Не реализован |
|
|
Задать атрибут робастности мьютекса. |
Не реализован |
|
Ограничения работы с терминалом
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Получить путь к файлу управляющего терминала. |
Функция только возвращает или передает через параметр |
|
|
Задать параметры терминала. |
Скорость ввода, скорость вывода и другие параметры, специфичные для аппаратных терминалов, игнорируются. |
|
|
Ожидать завершения вывода. |
Функция только возвращает значение |
|
|
Приостановить или возобновить прием или передачу данных. |
Приостановка вывода и запуск приостановленного вывода не поддерживаются. |
|
|
Очистить очередь ввода или очередь вывода, или обе эти очереди. |
Функция только возвращает значение |
|
|
Разорвать соединение с терминалом на заданное время. |
Функция только возвращает значение |
|
|
Получить путь к файлу терминала. |
Функция только возвращает нулевой указатель. |
|
|
Получить путь к файлу терминала. |
Функция только возвращает значение ошибки. |
|
|
Получить идентификатор группы процессов, использующих терминал. |
Функция только возвращает значение |
|
|
Задать идентификатор группы процессов, использующих терминал. |
Функция только возвращает значение |
|
|
Получить идентификатор группы процессов для лидера сессии, связанной с терминалом. |
Функция только возвращает значение |
|
Ограничения работы с оболочкой
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Создать дочерний процесс для выполнения команды и канал с этим процессом. |
Функция только присваивает переменной |
|
|
Закрыть канал с дочерним процессом, созданным функцией |
Функцию нельзя использовать, так как ее входным параметром является дескриптор потока данных, возвращаемый функцией |
|
|
Создать дочерний процесс для выполнения команды. |
Заглушка |
|
|
Раскрыть строку как в оболочке. |
Не реализован |
|
|
Освободить память, выделенную для результатов вызова интерфейса |
Не реализован |
|
Ограничения манипуляций с дескрипторами файлов
Интерфейс |
Назначение |
Реализация |
Заголовочный файл по стандарту POSIX.1-2008 |
---|---|---|---|
|
Сделать копию дескриптора открытого файла. |
Поддерживаются дескрипторы обычных файлов, стандартных потоков ввода-вывода, сокетов и каналов. Не гарантируется, что будет получен наименьший свободный дескриптор. |
|
|
Сделать копию дескриптора открытого файла. |
Поддерживаются дескрипторы обычных файлов, стандартных потоков ввода-вывода, сокетов и каналов. Через параметр |
|
Совместное использование POSIX и других интерфейсов
Использование libkos совместно с Pthreads
В потоке исполнения, созданном с помощью Pthreads, нельзя использовать следующие интерфейсы libkos:
- примитивы синхронизации;
- потоки;
- DMA-буферы;
- порты ввода-вывода;
- ввод-вывод через память (MMIO);
- прерывания.
Следующие интерфейсы libkos можно использовать совместно с Pthreads (и другими интерфейсами POSIX):
Использование POSIX совместно с libkos threads
Методы POSIX нельзя использовать в потоках исполнения, созданных с помощью libkos threads.
Использование IPC совместно с Pthreads/libkos threads
Методы для IPC можно использовать в любых потоках исполнения, созданных с использованием Pthreads или libkos threads.
В началоКомпонент 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
Интерфейс 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);
Интерфейс 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;
...
};
Интерфейс 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;
...
};
Интерфейсы 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;
};
Коды возврата
Общие сведения
В решении на базе 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. Описание общих кодов возврата приведено в таблице ниже.
Общие коды возврата
Код возврата |
Описание |
---|---|
|
Функция завершилась успешно. |
|
Аргумент функции некорректен. |
|
Нет соединения между клиентской и серверной сторонами взаимодействия. Например, отсутствует серверный IPC-дескриптор. |
|
Недостаточно памяти для выполнения операции. |
|
Слишком маленький буфер. |
|
Функция завершилась с внутренней ошибкой, которая связана с некорректной логикой. Примерами внутренних ошибок являются: выход значений за допустимые пределы, появление нулевых указателей и значений там, где этого быть не должно. |
|
Ошибка отправки IPC-сообщения. |
|
Ошибка приема IPC-сообщения. |
|
IPC-сообщение не было передано из-за источника IPC-сообщения. |
|
IPC-сообщение не было передано из-за приемника IPC-сообщения. |
|
IPC прервано другим потоком процесса. |
|
Сигнализирует, что функцию нужно вызвать повторно. |
|
Функция завершилась с ошибкой. |
|
Операция над ресурсом недоступна. |
|
Инициализация не выполнена. |
|
Функция не реализована. |
|
Слишком большой буфер. |
|
Ресурс временно недоступен. |
|
Ресурс не найден. |
|
Время ожидания истекло. |
|
Операция запрещена механизмами безопасности. |
|
Операция приведет к блокировке. |
|
Операция прервана. |
|
В обработчике прерывания вызвана недопустимая функция. |
|
Множество элементов уже содержит добавляемый элемент. |
|
Операция не может быть выполнена. |
|
Права доступа к ресурсу отозваны. |
|
Квота на ресурс превышена. |
|
Устройство не найдено. |
Определение кодов ошибок
Чтобы определить код ошибки, разработчику решения на базе KasperskyOS нужно использовать макрос MAKE_RETCODE()
, определенный в заголовочном файле sysroot-*-kos/include/rtl/retcode.h
из состава KasperskyOS SDK. При этом через параметр customer
нужно передать символьную константу RC_CUSTOMER_TRUE
.
Пример:
Описание ошибки, которое передается через параметр 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, используются для форматированного вывода сведений об ошибке.