При сборке решения компилятор NK на основе EDL-, CDL- и IDL-описаний генерирует набор специальных методов и типов, упрощающих формирование, отправку, прием и обработку IPC-сообщений.
В качестве примера рассмотрим класс процессов Server
, предоставляющий службу FS
, которая содержит единственный метод Open()
:
Server.edl
entity Server
/* OpsComp - именованный экземпляр компонента Operations */
components {
OpsComp: Operations
}
Operations.cdl
component Operations
/* FS - локальное имя службы, реализующей интерфейс Filesystem */
endpoints {
FS: Filesystem
}
Filesystem.idl
package Filesystem
interface {
Open(in string<256> name, out UInt32 h);
}
На основе этих описаний будут сгенерированы файлы Server.edl.h
, Operations.cdl.h
, и Filesystem.idl.h
содержащие следующие методы и типы:
Методы и типы, общие для клиента и сервера
В нашем примере будет сгенерирован один абстрактный интерфейс – Filesystem
:
typedef struct Filesystem {
const struct Filesystem_ops *ops;
} Filesystem;
typedef nk_err_t
Filesystem_Open_fn(struct Filesystem *, const
struct Filesystem_Open_req *,
const struct nk_arena *,
struct Filesystem_Open_res *,
struct nk_arena *);
typedef struct Filesystem_ops {
Filesystem_Open_fn *Open;
} Filesystem_ops;
При вызове интерфейсного метода в запросе автоматически проставляются соответствующие значения RIID и MID.
В нашем примере будет сгенерирован единственный интерфейсный метод Filesystem_Open
:
nk_err_t Filesystem_Open(struct Filesystem *self,
struct Filesystem_Open_req *req,
const
struct nk_arena *req_arena,
struct Filesystem_Open_res *res,
struct nk_arena *res_arena)
Методы и типы, используемые только на клиенте
Прокси-объект используется как аргумент интерфейсного метода. В нашем примере будет сгенерирован единственный тип прокси-объекта Filesystem_proxy
:
typedef struct Filesystem_proxy {
struct Filesystem base;
struct nk_transport *transport;
nk_iid_t iid;
} Filesystem_proxy;
В нашем примере будет сгенерирована единственная инициализирующая функция Filesystem_proxy_init
:
void Filesystem_proxy_init(struct Filesystem_proxy *self,
struct nk_transport *transport,
nk_iid_t iid)
В нашем примере будет сгенерировано два таких типа: Filesystem_Open_req
(для запроса) и Filesystem_Open_res
(для ответа).
typedef struct __nk_packed Filesystem_Open_req {
__nk_alignas(8)
struct nk_message base_;
__nk_alignas(4) nk_ptr_t name;
} Filesystem_Open_req;
typedef struct Filesystem_Open_res {
union {
struct {
__nk_alignas(8)
struct nk_message base_;
__nk_alignas(4) nk_uint32_t h;
};
struct {
__nk_alignas(8)
struct nk_message base_;
__nk_alignas(4) nk_uint32_t h;
} res_;
struct Filesystem_Open_err err_;
};
} Filesystem_Open_res;
Методы и типы, используемые только на сервере
При наличии вложенных компонентов этот тип также содержит их экземпляры, а инициализирующая функция принимает соответствующие им инициализированные структуры. Таким образом, при наличии вложенных компонентов, их инициализацию необходимо начинать с самого вложенного.
В нашем примере будет сгенерирована структура Operations_component
и функция Operations_component_init
:
typedef struct Operations_component {
struct Filesystem *FS;
};
void Operations_component_init(struct Operations_component *self,
struct Filesystem *FS)
В нашем примере будет сгенерирована структура Server_entity
и функция Server_entity_init
:
#define Server_entity Server_component
typedef struct Server_component {
struct : Operations_component *OpsComp;
} Server_component;
void Server_entity_init(struct Server_entity *self,
struct Operations_component *OpsComp)
В нашем примере будет сгенерировано два таких типа: Filesystem_req
(для запроса) и Filesystem_res
(для ответа).
typedef union Filesystem_req {
struct nk_message base_;
struct Filesystem_Open_req Open;
};
typedef union Filesystem_res {
struct nk_message base_;
struct Filesystem_Open_res Open;
};
При наличии вложенных компонентов эти типы также содержат структуры фиксированной части сообщения для любых методов любых служб, включенных во все вложенные компоненты.
В нашем примере будет сгенерировано два таких типа: Operations_component_req
(для запроса) и Operations_component_res
(для ответа).
typedef union Operations_component_req {
struct nk_message base_;
Filesystem_req FS;
} Operations_component_req;
typedef union Operations_component_res {
struct nk_message base_;
Filesystem_res FS;
} Operations_component_res;
При наличии вложенных компонентов эти типы также содержат структуры фиксированной части сообщения для любых методов любых служб, включенных во все вложенные компоненты.
В нашем примере будет сгенерировано два таких типа: Server_entity_req
(для запроса) и Server_entity_res
(для ответа).
#define Server_entity_req Server_component_req
typedef union Server_component_req {
struct nk_message base_;
Filesystem_req OpsComp_FS;
} Server_component_req;
#define Server_entity_res Server_component_res
typedef union Server_component_res {
struct nk_message base_;
Filesystem_res OpsComp_FS;
} Server_component_res;
Диспетчеры анализируют полученный запрос (значения RIID и MID), вызывают реализацию соответствующего метода, после чего сохраняют ответ в буфер. В нашем примере будут сгенерированы диспетчеры Filesystem_interface_dispatch
, Operations_component_dispatch
и Server_entity_dispatch
.
Диспетчер класса процессов обрабатывает запрос и вызывает методы, реализуемые этим классом. Если запрос содержит некорректный RIID (например, относящийся к другой службе, которой нет у этого класса процессов) или некорректный MID, диспетчер возвращает NK_EOK
или NK_ENOENT
.
nk_err_t Server_entity_dispatch(struct Server_entity *self,
const
struct nk_message *req,
const
struct nk_arena *req_arena,
struct nk_message *res,
struct nk_arena *res_arena)
В специальных случаях можно использовать диспетчеры интерфейса и компонента. Они принимают дополнительный аргумент – ID реализации интерфейса (nk_iid_t
). Запрос будет обработан только если переданный аргумент и RIID из запроса совпадают, а MID корректен. В противном случае диспетчеры возвращают NK_EOK
или NK_ENOENT
.
nk_err_t Operations_component_dispatch(struct Operations_component *self,
nk_iid_t iidOffset,
const
struct nk_message *req,
const
struct nk_arena *req_arena,
struct nk_message *res,
struct nk_arena *res_arena)
nk_err_t Filesystem_interface_dispatch(struct Filesystem *impl,
nk_iid_t iid,
const
struct nk_message *req,
const
struct nk_arena *req_arena,
struct nk_message *res,
struct nk_arena *res_arena)