views:

127

answers:

2

Hi,

the question I am having is: when running my app with a launch code other than sysAppLaunchCmdNormalLaunch, I can not use code outside the default code segment - but could I use a shared library that is multi-segmented, thus circumventing this problem?

A bit of background information: I am evaluating the possibility of porting an existing mobile application to PalmOS. A core part of this app is that it is doing some network communication in the background every 10 minutes or so, or when it receives incoming data (via a network/socket callback). During this time, I do not have access to globals and hence not to any code segments in my application other than the default one.

The problem now is that the actions involved in the communication (protocol, data handling, etc) require a lot of code that just does not fit into one segment. Apart from the question whether it makes sense to have that much code run in the 'background', the obvious problem is: how would I run it in the first place? Hence the question, whether putting the code in a shared (multi-segment) library would help.

Looking forward to your insights.

+2  A: 

I don't have experience with using shared libraries, but we've had this problem with our software, and we've come across three different ways to solve the problem.

Possibly the easiest is to enable Expanded Mode when using the Metrowerks compiler, but I'm not completely certain that this works. This special mode allows you to access certain constant global data when called from a non-global launch. However, there are a lot of caveats to using this approach. Also, I have not confirmed that Expanded Mode allows inter-segment jumps for sure. There's a white paper out there written by Ben Combee that explains in detail how to use Expanded Mode. It's titled "Supporting Expanded Mode on Palm OS". I could not find it on the web, so I put up a copy on my website: http://www.normsoft.com/tim/technical/Codewarrior_Expanded_Mode.pdf

Another more complicated option is to load the globals yourself and put a pointer to them in A5. In order to do this, you must modify (or duplicate) the Metrowerks startup code that loads globals and then call this modified code when you receive a non-global launch. Metrowerks includes the full source to this portion of the runtime, so you can do this pretty easily, though some of that code is pretty arcane. We successfully used this technique in one version of Pocket Tunes to access globals and an unlimited number of segments when called from a non-global launch code. Just be sure to restore A5 when returning from the launch code.

The final option is to move all (or some of) the code into PNOlets. This can be a pain because you have to segment your code into 68K and PNO, which can quickly become a nightmare to maintain. We've also successfully used this method, but the maintenance of the interworking code was awful. We finally ended up moving our entire code to a PNOlet using the PEAL loader, which works really well for large code because it automatically segments the code into 64KB chunks and runs the ARM code in-place. However, that is a very large effort because PNOlet development is not well-supported on ARM, so you have to provide a lot of low-level support yourself (like thunks for calling each API function).

Tim Norman
Thanks for this great insight. I was thinking about using PNOlets but unfortunately the time limits for this project are way too tight to do a lot of experimenting. However PEAL looks very interesting!I was also going to use PODS (or gcc), so CW's expanded mode is probably not going to help me ;-)
Steven
Good answer, Tim... better than what I would have written!
Ben Combee
A: 

Store a pointer to a nice large structure you allocate with MemPtr in Ftr memory using FtrSet. This can be retrieved anywhere in your application that needs global access using FtrGet.

Alternately use __STANDALONE_CODE_RESOURCE__ to put each function into a seperate code segment and use a shared functions.c with wrappers to load and lock these into memory to call them.

//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;
}
PhrkOnLsh
you need to unlock that handle when you're done, ohbtw. MemHandleUnlock(H);
PhrkOnLsh