Чтение онлайн

ЖАНРЫ

QNX/UNIX: Анатомия параллелизма
Шрифт:

// из фактической длины блока передаваемых данных

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;

static resmgr_io_funcs_t io_funcs;

iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs,

_RESMGR_IO_NFUNCS, &io_funcs);

// определяем обработку, отличную от обработки по умолчанию,

// только для двух команд: read & devctl

io_funcs.read = &readfunc;

io_funcs.devctl = &devctlfunc;

static iofunc_attr_t attr;

iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0);

// связываем менеджер с его префиксным именем

if (resmgr_attach(dpp, &resmgr_attr, DEVNAME,

_FTYPE_ANY, 0, &connect_funcs, &io_funcs, &attr) == -1)

exit("prefix attach");

dispatch_context_t* ctp = dispatch_context_alloc(dpp);

while (true) {

if ((ctp = dispatch_block(ctp)) == NULL)

exit("block error");

dispatch_handler(ctp);

}

}

// размер буфера для обмена сообщениями,

// этого нам хватит с большим запасом и надолго ;)

Поделиться с друзьями: