Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform Страница 72
- Категория: Компьютеры и Интернет / Программное обеспечение
- Автор: Роб Кёртен
- Год выпуска: -
- ISBN: -
- Издательство: -
- Страниц: 87
- Добавлено: 2019-07-03 10:23:42
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту pbn.book@yandex.ru для удаления материала
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform краткое содержание
Прочтите описание перед тем, как прочитать онлайн книгу «Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform» бесплатно полную версию:Книга "Введение в QNX/Neutrino 2» откроет перед вами в мельчайших подробностях все секреты ОСРВ нового поколения от компании QNX Software Systems Ltd (QSSL) — QNX/Neutrino 2. Книга написана в непринужденной манере, легким для чтения и понимания стилем, и поможет любому, от начинающих программистов до опытных системотехников, получить необходимые начальные знания для проектирования надежных систем реального времени, от встраиваемых управляющих приложений до распределенных сетевых вычислительных системВ книге подробно описаны основные составляющие ОС QNX/Neutrino и их взаимосвязи. В частности, уделено особое внимание следующим темам:• обмен сообщениями: принципы функционирования и основы применения;• процессы и потоки: базовые концепции, предостережения и рекомендации;• таймеры: организация периодических событий в программах;• администраторы ресурсов: все, что относится к программированию драйверов устройств;• прерывания: рекомендации по эффективной обработке.В книге представлено множество проверенных примеров кода, подробных разъяснений и рисунков, которые помогут вам детально вникнуть в и излагаемый материал. Примеры кода и обновления к ним также можно найти на веб-сайте автора данной книги, www.parse.com.
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform читать онлайн бесплатно
off = xoffset->offset;
} else if (xtype == _IO_XTYPE_NONE) {
off = ocb->offset;
start_data_offset = sizeof(msg->i);
} else {
// Неизвестный тип; игнорировать
return (ENOSYS);
}
// 2) Выделить достаточно большой буфер для данных
nbytes = msg->i.nbytes;
if ((buffer = malloc(nbytes)) == NULL) {
return (ENOMEM);
}
// 3) Считать данные от клиента (возможно, повторно)
if (resmgr_msgread(ctp, buffer, nbytes,
start_data_offset) == -1) {
free(buffer);
return (errno);
}
// 4) Сделать что-нибудь с данными
process_data(off, buffer, nbytes);
// 5) Освободить память буфера
free(buffer);
// 6) Установить, сколько байт должна возвращать
// клиентская функция «write»
_IO_SET_WRITE_NBYTES(ctp, nbytes);
// 7) Если данные записаны, обновить структуры
// данных POSIX и смещение OCB
if (nbytes) {
ocb->attr->flags |=
IOFUNC_ATTR_MTIME | IОFUNC_ATTR_DIRTY_TIME;
if (xtype == _IO_XTYPE_NONE) {
ocb->offset += nbytes;
}
}
// 8) Пусть библиотека сама ответит, что все в порядке
return (EOK);
}
Как вы видите, некоторые начальные действия идентичны таковым из примера функции io_read() — функция iofunc_write_verify() аналогична функции iofunc_read_verify(), и проверка переопределения xtype выполняется точно также.
Этап 1Здесь мы выполняем обработку переопределения xtype, в значительной степени аналогичную примеру с io_read() — за исключением того, что смещение не сохраняется в поле структуры входящего сообщения. Причина этого состоит в том, что обычной практикой для определения начального адреса поступающих от клиента данных является использование размера структуры входящего сообщения. Мы предпринимаем дополнительные усилия, чтобы удостовериться, что смещение начала данных (doffset) в коде обработки xtype является корректным.
Этап 2Здесь мы выделяем буфер, достаточный для размещения в нем данных. Число байт, которые клиент собирается записать, представлено нам в поле nbytes объединения msg, оно заполняется автоматически Си-библиотекой клиента в коде функции write(). Отметим, что у нас недостаточно памяти для обработки запроса malloc(), мы возвращаем клиенту ENOMEM, чтобы он знал, почему его запрос потерпел неудачу.
Этап 3Здесь мы применяем вспомогательную функцию resmgr_msgread() для считывания всего объема данных от клиента непосредственно в только что выделенный для этого буфер. В большинстве случаев здесь вполне сошла бы функция MsgRead(), но в случаях, когда сообщение является частью составного сообщения, функция resmgr_msgread() выполни для нас еще и соответствующие «магические» действия (о том, почему это надо, см. раздел «Составные сообщения»). Параметры функции resmgr_msgread() довольно очевидны: мы передаем ей указатель на внутренний контекстный блок (ctp), буфер, в который мы хотим поместить данные (buffer), и число байт, которые мы хотим считать (поле nbytes объединения msg). Последний параметр — это смещение, которое мы вычислили ранее, на этапе 1. Смещение реально позволяет пропустить заголовок, помещенный туда функцией write() клиентской Си-библиотеки, и сразу перейти к данным. Здесь возникает два интересных момента:
• мы могли бы взять произвольное смещение, чтобы считывать любые фрагменты данных в любом порядке, как нам заблагорассудится;
• мы могли бы использовать функцию resmgr_msgreadv() (обратите внимание на символ «V» в названии) для считывания данных от клиента в вектор ввода/вывода, возможно, описывающий несколько разных буферов, подобно тому, как мы делали с буферами кэша при обсуждении файловых систем в главе «Обмен сообщениями».
Этап 4Здесь вы можете делать с данными все, что вашей душе угодно — я, например, вызвал некую условную функцию process_data() и передал ей буфер и его размер.
Этап 5Критически важный этап! Упустить его из виду очень просто, но это неизбежно приведет к «утечкам памяти». Обратите также внимание, как мы позаботились об освобождении памяти в случае неудачи на этапе 3.
Этап 6Здесь мы используем макрос _IO_SET_WRITE_NBYTES() для сохранения числа записанных байт, которое затем будет передано назад клиенту в качестве значения, возвращаемого функцией write(). Важно отметить, что вы должны возвратить фактическое число байт! От этого зависит судьба клиента.
Этап 7Пришло время навести лоск для функций stat(), lseek() и последующих write(), аналогично тому, как мы это делали в нашей io_read() (и опять мы изменяем смещение в ocb только в том случае, если это не сообщение типа _IO_XTYPE_OFFSET). Однако, поскольку мы выполняем запись в устройство, мы используем при этом константу IOFUNC_ATTR_MTIME вместо константы IOFUNC_ATTR_ATIME. Флаг MTIME означает «время модификации» (modification time) — функция write() определенно его изменяет.
Этап 8Последний этап прост: мы возвращаем константу EOK, которая сообщает библиотеке администратора ресурсов, что она должна ответить клиенту. Здесь наша работа закончена. Библиотека администратора ресурсов использует в ответе данные о числе записанных байт, которые мы сохранили с помощью макроса IO_SET_WRITE_NBYTES(), и разблокирует клиента. Клиентская функция write() возвратит число байт, записанное нашим устройством.
Простой пример функции io_devctl()
Клиентский вызов devctl() формально определен так:
#include <sys/types.h>
#include <unistd.h>
#include <devctl.h>
int devctl(int fd, int dcmd, void *dev_data_ptr,
size_t nbytes, int *dev_info_ptr);
Прежде чем рассматривать эту функцию с позиций администратора ресурсов, надо сначала понять, что это за зверь. Функция devctl() применяется для «нестандартных» и «управляющих» операций. Например, вы можете записывать данные в звуковую плату (реальные оцифрованные звуковые фрагменты, которые звуковая плата должна будет конвертировать в аналоговый аудиосигнал) и принять решение об изменении числа каналов от одного (моно) до двух (стерео) или об изменении частоты дискретизации данных от стандарта CD (44.1 кГц) к стандарту DAT (48 кГц). Такие вещи было бы правильно делать при помощи функции devctl(). При написании администратора ресурсов вы можете решить, что вам вообще не нужны никакие devctl(), и что всю необходимую функциональность можно свести к стандартным функциям read() и write(). С другой стороны, вы можете захотеть использовать как вызовы devctl() наряду с вызовами read() и write(), так и только devctl() — это будет зависеть от вашего устройства.
Функция devctl() принимает 5 аргументов:
fd Дескриптор файла администратора ресурсов, которому вы посылаете команду devctl(). dcmd Собственно команда — комбинация из двух разрядов направления обмена данными и 30 разрядов команды (см. ниже). dev_data_ptr Указатель на область данных, которые передаются, принимаются или и то, и другое. nbytes Размер области данных, на которую указывает dev_data_ptr. dev_info_ptr Переменная для дополнительной информации, установку которой может выполнить администратор ресурса.Двумя старшими разрядами команды dcmd кодируется направление обмена данными, если он вообще имеет место. Подробности см. выше в описании функций ввода/вывода (параграф «io_devctl()»).
Когда администратор ресурсов принимает сообщение _IO_DEVCTL, оно обрабатывается вашей функцией io_devctl(). Ниже представлен очень простой пример, который предполагается использовать для настройки каналов и частоты дискретизации для аудиоустройства, как упоминалось выше.
/*
* io_devctl1.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
Жалоба
Напишите нам, и мы в срочном порядке примем меры.