Мультисегментированное приложение / библиотека PalmOS в фоновом режиме
У меня возникает вопрос: при запуске моего приложения с кодом запуска, отличным от sysAppLaunchCmdNormalLaunch, я не могу использовать код вне сегмента кода по умолчанию - но могу ли я использовать разделяемую библиотеку с несколькими сегментами, что позволяет обойти эту проблему?
Немного справочной информации: я оцениваю возможность портирования существующего мобильного приложения на PalmOS. Основная часть этого приложения состоит в том, что оно выполняет сетевое взаимодействие в фоновом режиме каждые 10 минут или около того, или когда оно получает входящие данные (через обратный вызов сети / сокета). В течение этого времени у меня нет доступа к глобальным переменным и, следовательно, к любым сегментам кода в моем приложении, кроме сегмента по умолчанию.
Проблема сейчас в том, что для действий, связанных с обменом данными (протокол, обработка данных и т. Д.), Требуется много кода, который просто не помещается в один сегмент. Помимо вопроса, имеет ли смысл запускать так много кода в фоновом режиме, очевидна проблема: как бы я запустил его в первую очередь? Отсюда вопрос, поможет ли помещение кода в разделяемую (многосегментную) библиотеку.
Ждем ваших идей.
2 ответа
У меня нет опыта использования общих библиотек, но у нас была эта проблема с нашим программным обеспечением, и мы нашли три различных способа решения этой проблемы.
Возможно, проще всего включить расширенный режим при использовании компилятора Metrowerks, но я не совсем уверен, что это работает. Этот специальный режим позволяет вам получать доступ к определенным постоянным глобальным данным при вызове из неглобального запуска. Тем не менее, есть много предостережений при использовании этого подхода. Кроме того, я не подтвердил, что расширенный режим разрешает межсегментные переходы наверняка. Там есть белая книга, написанная Беном Комби, которая подробно объясняет, как использовать расширенный режим. Он называется "Поддержка расширенного режима в Palm OS". Я не смог найти его в Интернете, поэтому я разместил копию на своем веб-сайте: http://www.normsoft.com/tim/technical/Codewarrior_Expanded_Mode.pdf
Другим более сложным вариантом является загрузка глобалов самостоятельно и указатель на них в A5. Чтобы сделать это, вы должны изменить (или продублировать) код запуска Metrowerks, который загружает глобальные переменные, а затем вызвать этот измененный код при получении неглобального запуска. Metrowerks включает полный исходный код этой части среды выполнения, поэтому вы можете сделать это довольно легко, хотя часть этого кода довольно загадочна. Мы успешно использовали эту технику в одной версии Pocket Tunes для доступа к глобальным и неограниченному количеству сегментов при вызове из неглобального кода запуска. Просто обязательно восстановите А5 при возврате из кода запуска.
Последний вариант - переместить весь (или часть) код в PNOlets. Это может быть проблемой, потому что вы должны сегментировать свой код в 68K и PNO, что может быстро стать кошмаром для обслуживания. Мы также успешно использовали этот метод, но поддержка кода взаимодействия была ужасной. В итоге мы переместили весь наш код в PNOlet с помощью загрузчика PEAL, который действительно хорошо работает для большого кода, поскольку он автоматически сегментирует код на куски по 64 КБ и запускает код ARM на месте. Однако, это очень большое усилие, потому что разработка PNOlet не очень хорошо поддерживается в ARM, поэтому вы должны обеспечить большую низкоуровневую поддержку самостоятельно (например, вызовы для вызова каждой функции API).
Сохраните указатель на красивую большую структуру, которую вы выделяете с помощью MemPtr в памяти Ftr с помощью FtrSet. Это можно найти в любом месте вашего приложения, которому необходим глобальный доступ с помощью FtrGet.
Поочередно использовать __STANDALONE_CODE_RESOURCE__
поместить каждую функцию в отдельный сегмент кода и использовать общий файл functions.c с обертками для загрузки и блокировки их в памяти для их вызова.
//segment 1000
UInt32 foobar( char* hi )
{
return 12;
}
// functions.c
typedef (UInt32)(*fooPtr)( char* ); // this is now a type representing a pointer to your function.
UInt32 foobar( char* hi )
{
LocalID id; UInt16 cn; SysCurAppDatabase(&cn,&id);
DmOpenRef ref = DmOpenDatabase (cn, id, dmModeReadOnly );
MemHandle H = DmGetResource('code',1000);
fooPtr code = MemHandleLock(H);
UInt32 result = (*fooPtr)( hi);
return result;
}