4. Наконец, последним вариантом обмена с менеджером ресурса является обмен «сырыми», неформатированными сообщениями. Но это уже вариация простого обмена сообщениями, а как ее реализовать в коде, показано в приложении В. Зайцева.
С другой стороны, такая повышенная гибкость простого обмена сообщениями в отношении размеров передаваемых данных — предмет потенциальных ошибок, в то время как регламентируемое POSIX поведение обменных функций несет в себе дополнительный контроль корректности.
Если техника менеджеров ресурсов — это только надстройка над базовым механизмом обмена сообщениями, то возникает совершенно естественный вопрос: какова же плата за использование этого производительного и «комфортного» механизма?
Для анализа «скоростных» характеристик альтернативных механизмов обмена сообщениями создадим группу приложений (клиентские и сервер, файлы cli.cc , clr.cc и srv.cc ), а чтобы отдельно не выписывать определения, используемые приложениями, вынесем их в отдельный файл определений ( файл common.h ).
Общие определения проекта
const char VERSION[] = "vers. 1.03";
// имя, под которым будет регистрироваться в пространстве
// имен наш тестовый менеджер ресурса
static const char DEVNAME[_POSIX_PATH_MAX] = "/dev/srr";
// "базовая часть" команды devctl(), конкретный код команды будет
// формироваться динамически на основе этой части, но исходя
// из фактической длины блока передаваемых данных
const unsigned int DCMD_CMD = 1,
DCMD_SRR = _POSIX_DEVDIR_TOFROM + (_DCMD_NET << 8) + DCMD_CMD;
// структура ответов менеджера ресурса по запросу read()
struct result {
pid_t pid;
int chid;
uint64_t cps;
result(void) {
pid = getpid();
// если уж возвращать, то и служебную информацию ;)
cps = SYSPAGE_ENTRY(qtime)->cycles_per_sec;
}
}
// завершение с извещением кода причины
inline void exit(const char *msg) {
cout << '\r';
perror(msg);
exit(EXIT_FAILURE);
}
В этой части каких-либо комментариев заслуживает разве что структура result
. Наш сервер устроен «наоборот»: информационный обмен данными он осуществляет по запросу devctl()
, запрос read()
нам «не нужен», и мы используем его только для возврата информации (PID + CHID) об автономном канале обмена сообщениями. Заодно мы передаем в поле cps этой структуры значение тактовой частоты процессора сервера, что позволяет знать, «с кем мы имеем дело» при экспериментах в сети.
Теперь мы вполне готовы написать код сервера. Этот сервер ( файл srv.cc ), в отличие от традиционных, имеет два независимых канала подключения: как менеджер ресурсов и как сервер простого обмена сообщениями. Как менеджер он по запросу read()
возвращает адресные компоненты (PID, CHID) для обмена сообщениями (ND клиент должен восстановить самостоятельно). По запросу devctl()
, а также по запросу по автономному каналу обмена сообщениями сервер просто ретранслирует обратно полученный от клиента блок данных (в каком-то смысле по обоим каналам обмена наш сервер является «зеркалом», отражающим данные).
Сервер запросов
result data;
//---------------------------------------------------------
// реализация обработчика read()
static int readfunc(resmgr_context_t *ctp, io_read_t *msg,
iofunc_ocb_t *ocb) {
int sts = iofunc_read_verify(ctp, msg, ocb, NULL);
if (sts != EOK) return sts;
// возвращать одни и те же статические данные...
MsgReply(ctp->rcvid, sizeof(result), &data, sizeof(result));
return _RESMGR_NOREPLY;
}
//---------------------------------------------------------
// реализация обработчика devctl.
static int devctlfunc(resmgr_context_t *ctp, io_devctl_t *msg,
iofunc_ocb_t *ocb) {
int sts = iofunc_devctl_default(ctp, msg, ocb);
if (sts != _RESMGR_DEFAULT) return sts;
// разбор динамически создаваемого кода devctl(),
// извлечение из него длины принятого блока
unsigned int nbytes = (msg->i.dcmd - DCMD_SRR) >> 16;
msg->o.nbytes = nbytes;
// и тут же ретрансляция блока назад
return _RESMGR_PTR(ctp, &msg->i, sizeof(msg->i) + nbytes);
}
//---------------------------------------------------------
// установка однопоточного менеджера, выполняемая
// в отдельном потоке
static void* install(void* data) {
dispatch_t *dpp;
if ((dpp = dispatch_create()) == NULL)
exit("dispatch allocate");
resmgr_attr_t resmgr_attr;
memset(&resmgr_attr, 0, sizeof(resmgr_attr));
resmgr_attr.nparts_max = 1;
resmgr_attr.msg_max_size = 2048;
static resmgr_connect_funcs_t connect_funcs;
Читать дальше
Конец ознакомительного отрывка
Купить книгу