Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 1 - MacApp Theory and Architecture
Chapter 3 - Core Technologies


Segment Management (68K-Based Applications Only)

This section describes the basic issues involved in segmenting an application. These issues apply to 68K-based applications but not to applications built to run native on Power Macintosh computers.

The Power Macintosh Doesn't Require Segmentation

Segmentation is not an issue for native Power Macintosh applications because on a Power Macintosh computer there is no segmentation of the application's code--the Virtual Memory Manager and the Process Manager handle the task of keeping required code in memory. MacApp's code to initialize segment handling, described in "Initializing MacApp's Segment Management," beginning on page 71, uses the qSegments flag to control compilation, ensuring that segmentation code is included only for applications that need it.

Segmenting a 68K Macintosh Application

For the 68K-based Macintosh, segmentation is an important issue.
Inside Macintosh: Processes
describes the Segment Manager and explains why there is a need to divide an application's code into segments that can be loaded into memory on demand. If your application is running on a Macintosh computer with enough memory, many of your code segments (perhaps even all of them) can be resident in memory simultaneously. However, effective segmentation lets your application

If you don't specify otherwise, the segments in your application will use 16-bit addressing and will be limited in size to 32 KB. Global data will also be limited to 32 KB. Sixteen-bit addressing results in a smaller jump table and more efficient code, but it has these potential drawbacks:

Segmentation Strategies

As a result of these trade-offs, there are a number of possible strategies for controlling segmentation in your application.

Using ModelFar Addressing to Create Large Segments

If you build your application using the -ModelFar build option (see
Appendix A), the linker will use 32-bit addressing for code and data segments, eliminating the 32 KB size limitation. Although this approach is simple, it can lead to inefficient code, and should only be used for applications with legitimate size requirements. And even if you build with the -ModelFar option, you should still follow the strategy described below in "Putting Related Code in the Same Segment."

Avoiding Jump-Table Limits

Another way to minimize size limitations is to build your application with the -CFM68K build option. This option specifies that the application will use CFM-68K, the 68K Macintosh equivalent of the Power Macintosh Code Fragment Manager. CFM-68K uses 16-bit addressing, so it creates efficient code, but its implementation allows much more room for jump-table entries and global data.

Creating Segments of Minimal Size

Another strategy for segmenting your application is to organize segments so that they are as small as possible. This ensures that the application heap will contain only code that is needed, increasing the amount of memory available. However, using small segments can lead to excessive segment load calls, which are triggered when a needed function is not present in memory.

Putting Related Code in the Same Segment

A strategy used in the MacApp class library is to put functions that are used together in the same segment. For example, routines used only in initializing the application are placed in one segment. That segment is loaded during initialization, but it may later be replaced by another segment, because it won't be needed again until the next time the application is launched.

Creating Segments

MacApp uses compiler segment directives such as the following to specify the segment for a section of code:

#pragma segment ARes
This tells the compiler that all code following the directive belongs in the ARes segment (but see the following section for information on remapping segments). The directive remains in effect until another segment directive is encountered.

Note
Putting a routine in a segment named ARes does not automatically make the code in that routine resident. See "The 'res!' Resource," beginning on page 81, for information on how to make a segment resident.
MacApp and the sample applications distributed with MacApp use the following segment-naming conventions:

Some of MacApp's segment names are shown in Table 3-3, with examples of the functions each segment contains. (For more information, see "Recipe--Defining Segment Names for Your Application," beginning on page 553.)

Table 3-3 Table 3-3 MacApp segment names and descriptions
Segment nameFunctions stored in the segment (continued)
ACloseRoutines for closing documents and data structures
ADebugDebugging code
ADoCommandCommands for performing operations: TSketcher::TrackMouse
AInitFunctions used only when the application is launched: IYourApplication
ANonRes,

ANonRes2, ...

Most routines should be nonresident, so most applications need more than one segment for nonresident code
AOpenRoutines for opening documents and data structures: DoMakeViews, DoMakeWindows, IYourDocument, DoMakeDocument, IYourView
AReadFileRoutines for reading from disk: DoRead, DoInitialState
ARes, ARes2, ...Resident routines (called often); code should be resident only if calling it must not move memory (for example, memcpy), or if it is called every time through the event loop (such as GetSleepTime): DoSetCursor, DoIdle
ASelCommandCode that determines which command to perform in response to an event
ATerminateFunctions used only when the application is terminated
AWriteFileRoutines for saving files to disk: DoNeedDiskSpace, DoWrite
MADebuggerMacApp debugging code (generated by qDebug, qUserFlag[1-3])
MainMain resident segment; contains system library routines and crucial code for starting the application

Remapping Segment Names

If your application follows the segment-naming convention described in the previous section, you may be surprised to find that a segment name you used is nowhere to be seen in a link map for the application. (The next section describes how to create a link map.) The likely explanation is that, in fine tuning its segmentation, MacApp remapped your segment name.

Information about how MacApp remaps segment names can be found in the file {MADependencies}Definitions_68K, which is described in Appendix A. For example, Definitions_68K contains the following lines:

   -sn AReadFile=GReadFile 
   -sn MAFileRead=GReadFile 
These lines indicate that any functions placed by a #pragma statement in the segment AReadFile will be remapped to the segment GReadFile (or Global Read File), as will any functions placed in the segment MAFileRead. So any code you place in the AReadFile segment ends up in the same segment as MacApp's file-reading code.

Note
{MADependencies} is a notation used in the MPW programming environment. When you execute a command line containing "{MADependencies}" (without the quotation marks) in the MPW worksheet, the expression is expanded to the full directory name of the MacApp Dependencies folder, for example, YourHardDisk:MacApp:Tools:Dependencies.
Segment remapping can be a source of confusion. For example, you might place a small number of functions in a segment, then get a link error that the segment has overflowed. The explanation may be that your code has been remapped to a segment that was already nearly full with other code.

On the plus side, you can use segment remapping as a tool to fine tune your code segmentation. It is usually easier to add or change -sn segment directives (in the OtherSegMappings section of your application's MAMake file) than to modify a potentially large number of #pragma statements located throughout your code. For more information see "Recipe--Defining Segment Names for Your Application," beginning on page 553.

Creating a Link Map

To determine the exact segment location of each routine in your application, you can create a link map. With MPW and the MABuild tool, for example, you create a link map by building your application with a line like the following:

MABuild -link -map [other options] YourAppName > YourAppName.map
The resulting link map file is named YourAppName.map. Appendix A describes how to build an application with the MABuild tool. The Macintosh Programmer Workshop Reference provides information on link options.

The 'seg!' Resource

MacApp uses the 'seg!' resource to store information about segmentation. A 'seg!' resource contains a list of the segment names the application has in memory at the point of greatest memory usage. Greatest memory usage usually occurs when printing, or when launching the application to open or print an existing document.

MacApp uses the information in the 'seg!' resource in calculating the memory requirements for the application (see page 65). MacApp defines its own 'seg!' resource in the file defaults.r:

#if !qPowerPC
resource 'seg!' (kDefaultSegResource,
#if qNames
   "Default seg!",
#endif
   purgeable) {
   {  "GNonRes";
      "GClipboard";
      "GClose";
      "GFile";
      "GOpen";
      "GSelCommand";
      "GDoCommand";
      "BBNonRes";
      "BBOpen";
      "GNonRes2";
      "GPrint";
      "GReadResource";
   };
};
#endif qPowerPC
Note that this resource is defined only if the application is not built for a Power Macintosh (#if !qPowerPC).

An application can have more than one 'seg!' resource, so you have two options in specifying the segments your application uses at its point of greatest memory usage:

Note
When including MacApp segments, be sure to use MacApp's remapped segment names.

The 'res!' Resource

The 'res!' resource defines those segments that should always be resident in the heap. (MacApp makes a segment permanently resident with the global routine SetResidentSegment.) Memory used by resident segments is unavailable for other operations throughout the life of the application, so you should avoid unnecessarily making a segment resident.

Note
Resident segments are loaded into the application's heap during initialization and locked, so that they are always available while the application is running. For this reason it is very likely that every segment present in a 'res!' resource will also be listed in a 'seg!' resource.
In general, you put code in a resident segment because you can't afford to have a segment load occur when you call that code or because the code is called frequently (for example, every time through the event loop). You might make a segment resident if it contains functions that are called during interrupt time, when a segment can't be loaded.

You can minimize the number of resident segments (and avoid segment loading) by putting routines that call each other in the same segment so that the calls will not require the use of a jump table. However, routines declared as virtual are always dispatched through the jump table.

MacApp defines a 'res!' resource in the file Memory.r. An application can have more than one 'res!' resource, so you can add to MacApp's resident segments by adding your own 'res!' resource, as the IconEdit sample application does in the file IconEdit.r:

#if !qPowerPC
resource 'res!' (kIconEditApp,
#if qNames
   "IconEditApp",
#endif
   purgeable) {
   {  "ARes";
   };
};
#endif qPowerPC
Note
A detailed technical discussion of MacApp segmentation issues can be found in the technical note "PT 21--MacApp Segmentation Illuminations," available from Apple Developer Technical Services.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996