Страниц: [1]
  Печать  
Автор Тема: Менеджер ресурса  (Прочитано 2435 раз)
qnx_user
Full Member
***
Offline Offline

Сообщений: 113


Просмотр профиля
« : Сентября 23, 2015, 11:09:46 am »

Здравствуйте!

Сел за написание собственного менеджера ресурса (драйвер для платы дискретного вывода, ось QNX4). Использую I/O Manager framework (архив iomanager2.tgz с ранее существовавшего ftp-сервера ftp.qnx.com). Входными параметрами классического iomanager являются directory_path - директория где будут располагаться файлы устройств, max_devices - максимальное их кол-во и device - собственно имена наших файлов-устройств.

Допустим я вызываю свой ресурс-менеджер с параметрами: iomanager -p/dev/dio port1 port2, где /dev/dio - директория устройства, а port1 и port2 - файлы портов вывода платы. Мой ресурс-менеджер должен обрабатывать _IO_WRITE сообщения, для чего я добавляю свой обработчик io_write. Вопрос заключается в следующем, как получив _IO_WRITE сообщение от клиента, в функции обработчике определить к какому порту (/dev/dio/port[1,2]) произошло обращение? Т.к. от этого будет зависеть куда я хочу записать входные данные в физический порт 1 или 2 моей платы.

Спасибо.
« Последнее редактирование: Сентября 23, 2015, 11:13:54 am от qnx_user » Записан
PoP
Sr. Member
****
Offline Offline

Сообщений: 336


Просмотр профиля
« Ответ #1 : Сентября 23, 2015, 12:26:14 pm »

iomanager2.tgz приближает написание драйверов под QNX4 к стилю QNX6. Мне он показался нестабильным и далеко не полностью (хотя-бы в базе) аналогчным ресурс менежеру QNX6 (всё даже непохоже и на Neutrino 1). Мне под 4-ку проще всё делать самому. Тем более, что эта библиотека скорее всего серьёзно не тестировалась.
Но влюбом случае для случая нескольких имён цепочка одинакова :
Перехватываем IO_OPEN, там есть путь и пара (pid, fd). Как либо связываем для себя путь и (pid, fd).
В сообщении IO_WRITE (IO_READ, IO_LSEEK и т.д) есть поля pid и fd, по ним определяем к чему идёт обращение.
В QNX6 и, видимо, в iomanager2 (уже не помню) при обработке IO_OPEN исходя из пути вы указываете библиотеке уникальный для всего дерева, начинающегося от корня драйвера, идентификатор файла - inode. При дальнйших вызовах обработчиков система возвращает вам inode ( для 6-ки - ocb->attr-inode, для  iomanager2 вероятно както похоже ).
Во вложении пример. Не помню откуда, но в нём применяются не описанные в хелпе функции вида __get_xxx(). Его легко подстроить под Ваш слчай без всяких  iomanager2.
Записан
qnx_user
Full Member
***
Offline Offline

Сообщений: 113


Просмотр профиля
« Ответ #2 : Сентября 23, 2015, 02:02:32 pm »

Во вложении пример. Не помню откуда, но в нём применяются не описанные в хелпе функции вида __get_xxx(). Его легко подстроить под Ваш слчай без всяких  iomanager2.

Есть книга Р. Кртена "Getting Started with QNX 4", в ней есть глава "Resource Managers", там представлен скелет ресурс-менеджера. Он схож с тем что Вы вложили. Изначально я хотел написать на его основе, но наткнулся на iomanager2. Попробую что получится. Спасибо.

P.S.
При дальнйших вызовах обработчиков система возвращает вам inode ( для 6-ки - ocb->attr-inode, для  iomanager2 вероятно както похоже ).
Да, такое поле действительно есть f->inode->ino_ino, но в нем хранится адрес inode (в файле ialloc.c):
Код:
p->ino_ino = (long) p;     /* just a number */
, где p
Код:
inode_t    *p;
, а не его index. В QNX6+, пробежав бегло документацию, прочитал что inode содержит порядковый номер файла или ресурса. Если записывать туда index, тогда становится понятно как в обработчиках анализировать обращение к тому или иному файлу. То ли это опечатка, то ли я не до конца что-то понимаю Smiley
« Последнее редактирование: Сентября 23, 2015, 02:24:58 pm от qnx_user » Записан
PoP
Sr. Member
****
Offline Offline

Сообщений: 336


Просмотр профиля
« Ответ #3 : Сентября 23, 2015, 07:02:37 pm »

В общем случае inode - не индекс, и не порядковый номер, просто любое уникальное в педелах драйвера число. Ну, у Вас написано же в коментарии /* just a number */. Указатель - тоже число.
Например :
....
#define NDEV 2
....
char *name[NDEV] = { "/dev/dio/port1", "/dev/dio/port2" };
....
io_open(..) {
for ( i = 0 ; i < NDEV ; i++ ) if ( !strcomp(xx->path, name) ) { p->inode = name; break; }
if ( i == NDEV ) return ENOENT;
....
Записан
Dark
Sr. Member
****
Offline Offline

Сообщений: 343


Просмотр профиля
« Ответ #4 : Сентября 24, 2015, 10:16:34 am »

Указатель - тоже число.

char *name[NDEV] = { "/dev/dio/port1", "/dev/dio/port2" };
....
p->inode = name;

Пагубная практика. Как показывают наблюдения за последнее десятилетие, в будущем частенько код из 4ки портируют в 6ку.
« Последнее редактирование: Сентября 24, 2015, 10:19:37 am от Dark » Записан
AG
QOR.Moderator
*****
Offline Offline

Сообщений: 872



Просмотр профиля WWW
« Ответ #5 : Сентября 24, 2015, 10:24:36 am »

Пагубная практика. Как показывают наблюдения за последнее десятилетие, в будущем частенько код из 4ки портируют в 6ку.

Соглашусь. Передавать указатель кому-то и потом верить что тебе вернули правильный указатель вредно. Если на другой стороне есть ошибки в коде, то жди SIGSEGV в гости.
Записан

Dark
Sr. Member
****
Offline Offline

Сообщений: 343


Просмотр профиля
« Ответ #6 : Сентября 24, 2015, 10:27:44 am »

+ разрядность адреса при портировании
Записан
PoP
Sr. Member
****
Offline Offline

Сообщений: 336


Просмотр профиля
« Ответ #7 : Сентября 24, 2015, 01:35:12 pm »

Пагубная практика. Как показывают наблюдения за последнее десятилетие, в будущем частенько код из 4ки портируют в 6ку.
Не вижу проблемы - в 6ке inode не указатель :
Код:
alex@POP:/opt/qnx660/target/qnx6/usr/include/sys$ cat iofunc.h |grep inode
#define IOFUNC_MOUNT_32BIT          0x00000100  /* offset, nbytes, inode and size are always 32-bit */
 * File or device attributes (usually embeded within an inode)         *
    ino_t                           inode;      /* mount point specific inode */
    ino64_t                         inode;      /* mount point specific inode */
    ino_t                           inode;      /* mount point specific inode */
    ino_t                           inode_hi;
    ino_t                           inode_hi;
    ino_t                           inode;      /* mount point specific inode */
    int32_t                         inode;      /* mount point specific inode */
    int32_t                         inode_hi;
    int32_t                         inode_hi;
    int32_t                         inode;      /* mount point specific inode */
alex@POP:/opt/qnx660/target/qnx6/usr/include/sys$ cat iofunc.h |grep inode
#define IOFUNC_MOUNT_32BIT          0x00000100  /* offset, nbytes, inode and size are always 32-bit */
 * File or device attributes (usually embeded within an inode)         *
    ino_t                           inode;      /* mount point specific inode */
    ino64_t                         inode;      /* mount point specific inode */
    ino_t                           inode;      /* mount point specific inode */
    ino_t                           inode_hi;
    ino_t                           inode_hi;
    ino_t                           inode;      /* mount point specific inode */
    int32_t                         inode;      /* mount point specific inode */
    int32_t                         inode_hi;
    int32_t                         inode_hi;
    int32_t                         inode;      /* mount point specific inode */
alex@POP:/opt/qnx660/target/qnx6/usr/include/sys$ cat types.h |grep ino_t
typedef __INO_T ino_t;
alex@POP:/opt/qnx660/target/qnx6/usr/include/sys$ cat target_nto.h |grep __INO_T
#undef __INO_T
#define __INO_T _Uint64t
#define __INO_T _Uint32t
alex@POP:/opt/qnx660/target/qnx6/usr/include/sys$
Ну, а в библиотеке "I/O Manager framework " для 4ки, судя по цитатам выше,  inode_t аналог 6-рочного iofunc_attr_t, ну а inode->ino_ino аналог attr->inode. Ну а то, что библиотека запихивает в ino_ino адрес inode - вполне логично, каждому пути соответствет своя структура (видимо inode_t в  iomanager2.tgz или iofunc_attr_t в 6ке). Так что и значение получится уникальным. Это не значит, что его нельзя поменять на что то своё, тоже уникальное, но более подходящее для идентификации пути. Мне, например, для железок удобнее чтобы масками можно было сразу определить ветку/подветку/[подветку]/файл. Ну а strcm() выше я написал только для упрощения понимания, в реальный драйвер пихать такие тормоза конечно нельзя.

P.S Самое смешное -  в последнее время я какраз переносил драйвера из под 6ки в 4ку.
Записан
qnx_user
Full Member
***
Offline Offline

Сообщений: 113


Просмотр профиля
« Ответ #8 : Сентября 24, 2015, 02:17:35 pm »

Код:
static io_write( pid_t p, file_t *f, unsigned n, void *buf, unsigned len )
{
struct _io_write_reply writeReply;

unsigned long *data    = f->inode->ino_data;
ino_t          channel = f->inode->ino_ino;

*data = *((unsigned long *)buf);

if ( 1 == channel ) {
if ( verbose ) printf( "Writing data (%Xh) to the port1 (%Xh)\n", *data, module );
outpd( module, *data );
} else if ( 2 == channel ) {
if ( verbose ) printf( "Writing data (%Xh) to the port2 (%Xh)\n", *data, module+4 );
outpd( module+4, *data );
}

writeReply.status = EOK;
writeReply.nbytes = n;
writeReply.zero   = 0;

Reply( p, &writeReply, sizeof(writeReply) );
}
Вот пример, как я попытался реализовать то что хотел. Если в ino_ino записывать именно индекс, тогда становится понятным как анализировать какой файл открыт, в функциях обработчиках сообщений. Ситуация когда туда записывается адрес структуры inode_t, получается странная ситуация сама структура inode содержит в себе элемент, который содержит в себе адрес структуры в которой она содержится (правда что мы заговорили об адресах, когда фактически ino_ino нужно рассматривать просто как число). Зачем? Я этот адрес и так могу получить, т.к. адрес этой структуры передается в функцию обработчик io_write входным параметром (file_t->inode). И если оставить так, то как я по этому магическому числу, пойму какой именно файл читает клиент?
« Последнее редактирование: Сентября 24, 2015, 02:20:12 pm от qnx_user » Записан
Dark
Sr. Member
****
Offline Offline

Сообщений: 343


Просмотр профиля
« Ответ #9 : Сентября 24, 2015, 02:24:54 pm »

Если бы inode был указателем как раз проблемы бы не было. QNX на Эльбрусе 64-битный, есть основания полагать что и канадцы в сторону разрядности на мобильных решениях поглядывают.

Реализуете описанный выше подход, а при переносе старшую часть адреса будете терять. Ладно еще если указатель на данные пересылать начнете, тут по указателю инструкции (IP) при SIGSEGV можно понять о чем речь. А вот если пристраститесь и начнете указатели на функции интами хранить, то готовьтесь к неинформативному IP. И это только половина беды, поскольку виртуальные адреса сегодня могут не содержать старшей части, а завтра, при попутном ветре, внезапно начать.

P.S Самое смешное -  в последнее время я какраз переносил драйвера из под 6ки в 4ку.

Смешное начинается при переносе кода на 64-битные системы.
Записан
PoP
Sr. Member
****
Offline Offline

Сообщений: 336


Просмотр профиля
« Ответ #10 : Сентября 24, 2015, 06:20:59 pm »

Смешное начинается при переносе кода на 64-битные системы.
Проходили. Теперь стараюсь использоватьint32_t, uint16_t и т.д. Ну, хотябы при общении с железками и в общих структурах.
Записан
Страниц: [1]
  Печать  
 
Перейти в: