При сборке решения компилятор NK на основе EDL-, CDL- и IDL-описаний генерирует набор специальных методов и типов, упрощающих формирование, отправку, прием и обработку IPC-сообщений.
Рассмотрим статическое описание сущности Server
из примера echo. Это описание состоит из трех файлов: Server.edl
, Ping.cdl
и Ping.idl
:
Server.edl
/* Описание сущности Server. */
entity Server
/* pingComp - именованный экземпляр компонента Ping. */
components {
pingComp: Ping
}
Ping.cdl
/* Описание компонента Ping. */
component Ping
/* pingImpl - реализация интерфейса Ping. */
interfaces {
pingImpl: Ping
}
Ping.idl
/* Описание интерфейса Ping. */
package Ping
interface {
Ping(in UInt32 value, out UInt32 result);
}
На основе этих файлов будут сгенерированы файлы Server.edl.h
, Ping.cdl.h
, и Ping.idl.h
содержащие следующие методы и типы:
Методы и типы, общие для клиента и сервера
В нашем примере будет сгенерирован один абстрактный интерфейс – Ping
:
struct Ping_ops {
nk_err_t (*Ping)(struct Ping *,
const struct Ping_req *,
const struct nk_arena *,
struct Ping_res *,
struct nk_arena *); };
struct Ping {
const struct Ping_ops *ops;
};
При вызове интерфейсного метода в запросе автоматически проставляются соответствующие значения RIID и MID, после чего вызывается функция nk_transport_call()
.
В нашем примере будет сгенерирован единственный интерфейсный метод Ping_Ping
:
nk_err_t Ping_Ping(struct Ping *,
const struct Ping_Ping_req *,
const struct nk_arena *,
struct Ping_Ping_res *,
struct nk_arena *);
Методы и типы, используемые только на клиенте
Прокси-объект используется как аргумент интерфейсного метода. В нашем примере будет сгенерирован единственный тип прокси-объекта Ping_proxy
:
struct Ping_proxy {
struct Ping base;
struct nk_transport *transport;
nk_iid_t iid;
};
В нашем примере будет сгенерирована единственная инициализирующая функция Ping_proxy_init
:
void Ping_proxy_init(struct Ping_proxy *, struct nk_transport *, nk_iid_t);
В нашем примере будет сгенерировано два таких типа: Ping_Ping_req
(для запроса) и Ping_Ping_res
(для ответа).
struct Ping_Ping_req {
struct nk_message base_;
nk_uint32_t value;
};
struct Ping_Ping_res {
struct nk_message base_;
nk_uint32_t result;
};
Методы и типы, используемые только на сервере
При наличии вложенных компонентов этот тип также содержит их экземпляры, а инициализирующая функция принимает соответствующие им инициализированные структуры. Таким образом, при наличии вложенных компонентов, их инициализацию необходимо начинать с самого вложенного.
В нашем примере будет сгенерирована структура Ping_component
и функция Ping_component_init
:
struct Ping_component {
struct Ping *pingImpl;
};
void Ping_component_init(struct Ping_component *, struct Ping *);
В нашем примере будет сгенерирована структура Server_entity
и функция Server_entity_init
:
struct Server_entity {
struct Ping_component *pingComp;
};
void Server_entity_init(struct Server_entity *, struct Ping_component *);
В нашем примере будет сгенерировано два таких типа: Ping_req
(для запроса) и Ping_res
(для ответа).
union Ping_req {
struct nk_message base_;
struct Ping_Ping_req Ping;
};
union Ping_res {
struct nk_message base_;
struct Ping_Ping_res Ping;
};
При наличии вложенных компонентов эти типы также содержат структуры фиксированной части сообщения для любых методов любых интерфейсов, реализации которых включены во все вложенные компоненты.
В нашем примере будет сгенерировано два таких типа: Ping_component_req
(для запроса) и Ping_component_res
(для ответа).
union Ping_component_req {
struct nk_message base_;
union Ping_req pingImpl;
};
union Ping_component_res {
struct nk_message base_;
union Ping_res pingImpl;
};
При наличии вложенных компонентов эти типы также содержат структуры фиксированной части сообщения для любых методов любых интерфейсов, реализации которых включены во все вложенные компоненты.
В нашем примере будет сгенерировано два таких типа: Server_entity_req
(для запроса) и Server_entity_res
(для ответа).
union Server_entity_req {
struct nk_message base_;
union Ping_req pingComp_pingImpl;
};
union Server_entity_res {
struct nk_message base_;
union Ping_res pingComp_pingImpl;
};
Диспетчеры анализируют полученный запрос (значения RIID и MID), вызывают реализацию соответствующего метода, после чего сохраняют ответ в буфер. В нашем примере будут сгенерированы диспетчеры Ping_dispatch
, Ping_component_dispatch
и Server_entity_dispatch
.
Диспетчер сущности обрабатывает запрос и вызывает методы, реализуемые этой сущностью. Если запрос содержит некорректный RIID (например, относящийся к другой реализации интерфейса, которой нет у этой сущности) или некорректный MID, диспетчер возвращает NK_EOK
или NK_ENOENT
.
nk_err_t Server_entity_dispatch(struct Server_entity *,
const union Server_entity_req *,
const struct nk_arena *,
union Server_entity_res *,
struct nk_arena *);
В специальных случаях можно использовать диспетчеры интерфейса и компонента. Они принимают дополнительный аргумент – ID реализации интерфейса (nk_iid_t
). Запрос будет обработан только если переданный аргумент и RIID из запроса совпадают, а MID корректен. В противном случае диспетчеры возвращают NK_EOK
или NK_ENOENT
.
nk_err_t Ping_dispatch(struct Ping *,
nk_iid_t,
const union Ping_req *,
const struct nk_arena *,
union Ping_res *,
struct nk_arena *);
nk_err_t Ping_component_dispatch(struct Ping_component *,
nk_iid_t,
const union Ping_component_req *,
const struct nk_arena *,
union Ping_component_res *,
struct nk_arena *);