Главная » Просмотр файлов » Руководство программиста в Photon

Руководство программиста в Photon (1037671), страница 42

Файл №1037671 Руководство программиста в Photon (Раздаточные материалы) 42 страницаРуководство программиста в Photon (1037671) страница 422017-12-25СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 42)

перед вызовами функций name_attach() или PhAppAddInput(). Если Вы хотите создать отдельный канал для Photon'а, нет разницы, создаёте ли Вы его и передаёте его функции PhChannelAtach() до или после вызова name_attach(). Но имейте в виду, что поскольку определённые механизмы библиотеки Photon'а предполагают, что канал Photon'а имеет два установленных флага DISCONNECT, они могут неправильно работать, если это не так. Одним из таких механизмов является определение нарушенной связи (см. функции PtConnectionClientSetError() и PtConnectionServerSetError()) и всё, что зависит от этого механизма.

Удаление обработчика ввода

Чтобы удалить обработчик ввода:

  • Получите от него код возврата Pt_END

или

  • Вызовите функцию PtAppRemoveInput(), передав её в качестве аргумента идентификатор, возвращённый функцией PtAppAddInput().

Размер буфера сообщений

Как описано выше, аргументы Вашей функции ввода включают:

msg Указатель на буфер событий, использованный для получения сообщений.

msglen Размер буфера.

Этот буфер может оказаться недостаточно велик, чтобы вместить целиком всё сообщение. Одним из способов обработки этого – выделять первые несколько байт сообщения под указание типа сообщения и отсюда определять, насколько большим оно может быть. Как только Вы узнаете размер сообщения, Вы сможете:

  • Перечитать сообщение целиком, вызвав функцию MsgReadv()

или

  • Скопировать часть, которую Вы уже получили, в новый буфер. Получить остаток сообщения, вызвав MsgReadv(). Добавить остаток сообщения к первой части.

Альтернативным способом является установка размера буфера событий таким, чтобы он мог вместить самое большое сообщение, которое получит Ваше приложение (если Вы это знаете). Это может быть выполнено функцией PtResizeEventMsg(). Обычно Вы должны выполнить этот вызов до того, как предполагаете получить какие-либо сообщения.

 Функция PtResizeEventMsg() не уменьшит буфер сообщений меньше определённого минимального размера. Это потому, что библиотека виджета хочет продолжить функционировать.

Пример – регистрация сообщений об ошибках

Следующий фрагмент кода показывает, как неспециализированный обработчик ввода может быть использован для реагирования на сообщения от других пользователей, регистрирующих ошибки. Когда одно из таких сообщений приходит, приложение отображает содержание сообщения в многострочном текстовом виджете (Этот пример предполагает, что где-то в другом месте задекларировано log_message).

int input_proc(void *client_data, int rcvid, void *msg, size_t msglen) {

struct log_message *log = (struct log_message *)msg;

/* Обработка только регистрирующих (log) сообщений */

if (log->type == LOG_MSG) {

PtWidget_t *text = (PtWidget_t *)client_data;

struct log_message header;

int msg_offset = offsetof(struct log_message, msg);

int log_msglen;

int status;

/* Смотрим: если весь наш заголовок в буфере - это оно */

if (msglen < msg_offset) {

/* Читаем во всём заголовке */

if (MsgRead(rcvid, &header, msg_offset, 0) = = -1) {

status = errno;

MsgError( rcvid, status);

return Pt_HALT; /* отпускаем*/

}

log = &header;

}

log_msglen = msg_offset+log->msg_len;

/* Смотрим, всё ли сообщение в буфере */

if (msglen < log_msglen) {

struct log_message *log_msg = (struct log_message *)alloca(log_msglen);

/* Читаем остаток сообщения из пространства стека */

if (log_msg = = NULL || MsgRead( rcvid, log_msg, log_msglen, 0) = = -1) {

status = errno;

MsgError( rcvid, status);

return Pt_HALT; /* отпускаем */

}

log = log_msg;

}

add_msg(text, log);

status = 0;

MspReply( rcvid, 0, 0, 0);

}

return Pt_HALT;

}

Это приложение регистрирует функцию input_proc() как обработчик ввода для обработки не-Photon'овских сообщений от каких-либо других процессов. Функция input_proc() вначале проверяет тип пришедшего сообщения. Если обработчик ввода не является ответственным за этот тип сообщения, он немедленно возвращает управление. Это важно, поскольку будут вызваны также и какие-либо другие неспециализированные обработчики ввода, которые были зарегистрированы, и только один из них будет нести ответственность по данному сообщению. Если тип полученного сообщения – регистрирующее сообщение, функция убеждается, что Photon прочёл в свой буфер событий сообщение целиком. Это можно определить, проверив длину сообщения, представленную как msglen в обработчике ввода. Если часть сообщения в буфере событий отсутствует, в памяти выделяется буфер сообщения и вызывается функция MsgRead(), чтобы получить сообщение целиком. Затем функция input_proc() вызывает функцию add_msg(), чтобы добавить сообщение в текстовый виджет, и выдаёт ответ на сообщение.

Когда input_proc() завершает свою работу, она возвращает значение Pt_HALT. Это указывает Photon'овской библиотеке виджета не удалять обработчик ввода.

Импульсы Photon'а

[Прим. пер. Импульсы Photon'а – это отнюдь не импульсы QNX 6, а прокси QNX 4. Именно этот механизм.]

В дополнении к синхронному обмену сообщений, Photon поддерживает импульсы. Процесс, желающий уведомить другой процесс, но не желающий при этом ожидать ответа, может использовать импульсы Photon'а. Например, сервер может использовать импульс, чтобы общаться с клиентом в ситуации, когда отсылка сообщения может оставить их обоих SEND-блокированными (и поэтому попавшими в тупик). Импульс Photon'а определяется по его отрицательному идентификатору процесса, который может быть использован в качестве аргумента pid функции PtAppAddInput(). Этот идентификатор процесса является локальным для Вашего приложения. Если Вы хотите, чтобы другой процесс прислал Вам импульс, Вы должны "взвести" импульс, используя функцию PtPulseArm(). Это создаёт объект типа PtPulseMsg_t, который может быть послан другому процессу в сообщении. Другой процесс затем будет способен посылать импульсы, вызывая функцию MsgDeliverEvent().

 В OC QNX версии 6 тип PtPulseMsg_t является структурой sigevent. Биты в msg.sigev_value.sival_int, которые соответствуют _NOTIFY_COND_MASK, сброшены, но могут быть установлены приложением, отсылающим импульс. Более подробно см. в описании функции ionotify() "Справочника библиотечных функций QNX 6".

PtPulseArm() (описанная в "Справочнике библиотечных функций Photon'а ") просто берёт структуру sigevent. Функции PtPulseArmFd() и PtPulseArmPid() существуют для совместимости с более ранними версиями OC QNX и Photon microGUI.

Давайте посмотрим код, который Вам надо написать, чтобы поддерживать импульс в:

  • Приложении Photon'а, которое получает импульсы

  • Приложении Photon'а, которое выпускает импульсы

Приложение Photon'а, получающее импульсы

Это адресат импульсов Photon'а, который делает большую часть подготовительной работы. Ему следует

  1. Создать импульс

  2. Взвести импульс

  3. Отослать сообщение об импульсе процессу, который будет этот импульс испускать

  4. Зарегистрировать обработчик ввода для сообщений импульса

  5. Послать импульс самому себе, если это необходимо

  6. Удалить импульс, когда он больше не будет нужен

В нижеприведенных разделах обсуждается каждый шаг, и далее следует пример.

 Перед своим завершением процесс-получатель импульсов должен дать указание процессу, посылающему импульсы, перестать это делать.

Создание импульса

Чтобы создать импульс Photon'а, вызовите функцию PtAppCreatePulse():

pid_t PtAppCreatePulse(PtAppContext_t app, int priority);

аргументами которой являются:

app Адрес контекста приложения, структуры типа PtAppContext_t, которая управляет всеми данными, связанными с приложением. Вам следует передавать NULL в качестве этого аргумента, так чтобы использовался контекст по умолчанию.

priority приоритет импульса. Если он равен –1, используется приоритет вызывающей программы.

PtAppCreatePulse() возвращает идентификатор импульса, который является отрицательным числом, но никогда не равен –1. Это конец импульса на стороне получателя.

Взведение импульса

Взведение импульса заполняет структуру sigevent, которая может использоваться в большинстве вызовов QNX-функций, принимающих этот тип в качестве аргумента.

 Нет никакой ошибки в том, чтобы иметь больше одного процесса-источника одного и того же импульса, несмотря на то, что получатель не будет в состоянии определить, какой процесс его послал.

Чтобы взвести импульс, вызовите функцию PtPulseArm(). Её прототип:

int PtPulseArm( PtAppContext_t app, pid_t pulse, struct sigevent *msg );

и аргументами являются:

app Указатель на PtAppContext_t структуру, определяющую текущий контекст приложения (обычно NULL)

pulse Импульс, созданный функцией PtAppCreatePulse()

msg указатель на сообщение импульса, созданное функцией. Это конец импульса на стороне отправителя, и мы должны будем отослать его этому процессу, как это описано ниже.

Эта функция возвращает указатель на идентификатор сообщения импульса, который понадобится нам позже.

Пересылка сообщения импульса испускателю импульсов

Метод, который Вы используете для отсылки сообщения импульса, зависит от процесса, который будет испускать импульсы:

  • Для менеджеров ресурсов:

ionotify(fd, _NOTIFY_ACTION_ARM, _NOTIFY_COND_INPUT, &pulsemsg);

  • Для любого другого типа процесса:

/*Создание своего собственного формата сообщения: */

msg.pulsemsg=pulsemsg;

MsgSendv(channel_id, &msg, msg_parts, &rmsg, rmsg_parts);

Регистрация обработчика ввода

Регистрация обработчика ввода для импульса похожа на регистрацию обработчика ввода для сообщения; см. раздел "Добавление обработчика ввода" выше в этой главе. Передайте идентификатор импульса, возвращённый функцией PtAppCreatePulse(), как параметр pid в функции ptAppAddInput().

Аргумент rcvid для обработчика ввода не будет иметь обязательно то же значение, что и идентификатор импульса: он сопоставляет идентификатор импульса в битах, определённых в _NOTIFY_DATA_MASK (см. описание ionotify() в "Справочнике библиотечных функций QNX 6"), но остальные биты берутся из полученного импульса QNX.

Посылка импульса самому себе

Если приложению требуется отослать импульс самому себе, оно может вызвать функцию PtAppPulseTrigger():

int PtAppPulseTrigger(PtAppContext_t app, pid_t pulse);

Параметрами этой функции являются структура типа PtAppContext_t, определяющая контекст приложения (обычно NULL), и идентификатор импульса, возвращённый функцией PtAppCreatePulse().

Удаление импульса

Когда ВАше приложение больше не нуждается в импульсе, он может быть удалён вызовом функции PtAppDeletePulse():

int PtAppDeletePulse(PtAppContext_t app, pid_t pulse_pid);

параметрами которой являются структура типа PtAppContext_t, определяющая контекст приложения (обычно NULL), и идентификатор импульса, возвращённый функцией PtAppCreatePulse().

Пример – очередь сообщений

Это приложение, получающее импульсы Photon'а. Оно открывает очередь сообщений (/dev/mqueue/testqueue по умолчанию), устанавливает импульс, и использует функцию mq_notify(), чтобы отдать ему импульс, когда в очереди сообщений есть нечто для прочтения:

/* Стандартные хеадеры */

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <mqueue.h>

#include <fcntl.h>

#include <errno.h>

#include <sys/stat.h>

/* Инструментальные хеадеры */

#include <Ph.h>

#include <Pt.h>

#include <Ap.h>

/* Локальные хеадеры */

#include "abimport.h"

#include "proto.h"

mqd_t mqd = -1;

struct sigevent sigev;

static void readqueue( void ) {

static unsigned counter;

unsigned mprio;

ssize_t msize;

char mbuf[ 4096 ];

while ( ( msize = mq_receive( mqd, mbuf, sizeof(mbuf), &mprio ) ) >= 0 ) {

char hbuf[ 40 ];

PtTextModifyText( ABW_mtext, 0, 0, -1, hbuf,

sprintf( hbuf, "Msg #%u (prio %d):\n", ++counter, mprio ));

PtTextModifyText( ABW_mtext, 0, 0, -1, mbuf, msize );

}

if ( errno != EAGAIN ) perror( "mq_receive" );

} // Функции readqueue()

static int input_fun( void *data, int rcvid, void *message, size_t mbsize ) {

readqueue();

if ( mq_notify( mqd, &sigev ) == -1 ) perror( "mq_notify" );

return Pt_HALT;

} // Функции input_fun()

Характеристики

Тип файла
Документ
Размер
7,62 Mb
Тип материала
Высшее учебное заведение

Список файлов учебной работы

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6381
Авторов
на СтудИзбе
308
Средний доход
с одного платного файла
Обучение Подробнее