3.2. The 32-bit user process model

This section provides a brief explanation about 32-bit user process models. Every 32-bit user process has its own address space, whose maximum size is 4 GB. An address space is prepared by the kernel as part of the process initialization tasks as a subset of virtual memory address on the system. A 32-bit address space is composed of up to sixteen 256 MB memory chunks called segments. Each segment has a specific purpose illustrated in several figures in the following sections. A segment is divided into smaller size memory chunks called pages. A page is an atomic unit, with which the virtual memory manager (VMM) in the kernel uses to satisfy many different memory requests.

On AIX, the default page size is 4 KB, unless the large page support[3] is used. If the default page size, 4 KB, is used, a segment contains 256 MB / 4 KB = 256 / 4 × 1024 = 64 K = 65,536 pages.

[3] See 3.6, “Large page support” on page 157 for more detail about the large page support.

In the 32-bit user process model, there are several variations, called large memory model and very large memory model, depending on the required heap size for the process. We also explain these models in the following sections:

3.2.1. Default memory model

Figure 3-3 on page 111 illustrates the segment usage of the default 32-bit memory model. This is the default memory model, unless you explicitly set a linker option (-b:maxdata) when generating executables or set an environment value (LDR_CNTRL) when executing 32-bit executables.

Figure 3-2. Default memory model (segment usage)[4]


[4] The access to the 0xE segment from a user process has been supported on AIX Version 4.2.1 and later.

Figure 3-3. Default memory model (detail)


The usage of each segment is briefly described in the following:

  • The first segment, 0x0, is reserved by system for the kernel text and data. Therefore, access from the user process to the segment 0x0 is prohibited.[5]

    [5] User processes can access to kernel data only through the system calls with specific ways.

  • The 0x1 segment contains user process text. If another process shares the same executable file, there will be only one instance of the text pages for that executable file on the system.

  • The 0x2 segment contains user data, heap, and stack. We provide detailed information about this segment in “Process private segment (0x2)” on page 111.

  • The 0xD segment contains shared library text. This segment is shared by all 32-bit user processes. The virtual addresses of loaded shared text objects can be examined using the genkld command. For further information about the usage of genkld, see 2.7.2, “genkld” on page 88.

  • The 0xF segment contains per-process shared library data.

  • Segments 0x3 - 0xC and 0xE are attached to the address space if the process called shmat() or mmap() routines to allocate shared memory segments. These segments are allocated in order, starting from 0x3 towards 0xE excluding 0xD, unless DSA (Dynamic Segment Allocation) is used. Further detailed explanation is provided in 3.5.1, “Order in the 32-bit default memory model” on page 153 and 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.

Process private segment (0x2)

The process private segment, 0x2, is the most interesting segment for application developers on AIX. In this segment, many memory components that are mandatory for a user process are allocated (see Figure 3-3). In this figure, white rectangles represent un-allocated virtual address pages; if a process touches these address ranges, it receives the SIGSEGV[6] signal and dumps a core file. Highlighted rectangles represent allocated virtual address pages. You may notice that a 32-bit address space is quite vacant in most cases.

[6] Signal for segmentation violation

First of all, some pages within this segment are prepared by the kernel as a part of the process initialization tasks. The access to those pages from the user process is prohibited (represented as several highlighted rectangles under the Kernel in the right most rectangle). The information contained in this area are only accessible from the user process through system calls.

The rest of the pages within this segment can be accessed by the process, though there is a big hole between the process heap (represented as “User data” in the figure) and stack. If the process touches pages in this hole, it receives the SIGSEGV signal and dumps a core file.

User data contains three different memory components: initialized data, un-initialized data,[7] and heap. To demonstrate how they are mapped into virtual pages, we have prepared a simple program shown in Example 3-2 on page 113.

[7] The un-initialized data is generally referred to as BSS (block started by symbol) in computer science terminology.

When compiled and executed, it prints addresses of several predefined symbols in the XCOFF format, as shown in Example 3-1. Those symbols, starting from the underscore character, are well explained in “XCOFF Object (a.out) File Format”, AIX 5L Version 5.2 Files Reference. We only explain _data and _edata here; the _data symbol defines the starting address of the initialized data in the executable file, while the _edata symbol defines the first location address after the initialized data in the executable file.

The size command tells you the size of the .text, .data, and .bss segments of the specified executable file.[8]

[8] The -x option instructs the command to display data in the hexadecimal format.

Example 3-1. Addresses of several predefined symbols
$ size -fx a.out
a.out: 428(.text) + 234(.data) + 8(.bss) + 2db(.loader) = 0x93f
$ a.out
_text =                 0x10000128
_etext =                0x10000550
_data =                 0x20000550
							_edata =                0x20000784
argv[] =                0x2ff22a14
environ[] =             0x2ff22ff4
errnop =                0x2ff22ffc
errno =                 0x2ff22ff8
i_initialized =         0x200006f0
l_uninitialized =       0x20000788
str_buf =               0x2ff219b0
heap_mem =              0x20000798

As for the addresses of_data and_edata, we can easily subtract 0x20000550 from 0x20000784 using the bc command, as shown in the following example:

$ bc
ibase=F
obase=F
20000784 - 20000550
234
^D

To quit the command, type Control-D. The ibase=F and obase=F keywords instruct the command to treat both input and output as hexadecimal numbers. The answer is 0x234, which is equivalent to the .data segment size in the executable file reported by the size command.

Note

You need to use upper-case characters (A - F) to represent hexadecimal 0xA - 0xF with the bc command.


After the initialized data, un-initialized data (BSS) is loaded into the memory as shown by the address of l_uninitilized. Then heap starts as shown by the address of heap_mem. It grows toward the last address of this segment (0x2FFFFFFF).

On the other hand, the stack grows from a relatively higher address toward the first address of this segment (0x20000000). The user process stack contains several predefined symbols, such as argv, environ, errno, and so on. The user process stack grows, if the process calls functions or allocates auto storage class symbols.

Note

Thread stacks for Pthreads, except the initial thread within a multi-threaded processes, are allocated in the process heap. See 8.3.4, “Thread stack” on page 292 for further information about the thread stack for multi-threaded processes.


Example 3-2. underscore_symbols_32.c[9]
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

extern int errnop;
extern int errno;
extern _text;
extern _etext;
extern _data;
extern _edata;
extern char *environ[];

int     i_initialized = 1;      /* initialized global variable. */
long    l_uninitialized;        /* uninitialized global variable. */

int
main(int argc, char *argv[])
{
    char    str_buf[BUFSIZ];    /* auto storage class variable. */
    char    *heap_mem;          /* heap memory. */

    if ((heap_mem = malloc(BUFSIZ)) == (void *)NULL) {
        sprintf(str_buf, "malloc() failed with errno = %d", errno);
        perror(str_buf);
    }

    printf("_text =			0x%08p
", &_text);
    printf("_etext =		0x%08p
", &_etext);
    printf("_data =			0x%08p
", &_data);
    printf("_edata =		0x%08p
", &_edata);

    printf("argv[] =		0x%08p
", argv);
    printf("environ[] =		0x%08p
", environ);
    printf("errnop =		0x%08p
", &errnop);
    printf("errno =		0x%08p
", &errno);

    printf("i_initialized = 	0x%08p
", &i_initialized);
    printf("l_uninitialized = 	0x%08p
", &l_uninitialized);
    printf("str_buf = 		0x%08p
", str_buf);
    printf("heap_mem = 		0x%08p
", heap_mem);

    exit(0);
}

[9] Extern symbols start with underscore are run-time symbols prepared by the system loader.

Because the process heap and stack share the same segment, the heap size must be smaller than 256 MB in the default memory model. This is the reason why the default definition of user soft data limit is 131,072 KB = 128 MB (see Example 3-6 on page 125).

We provide detailed information about how heap and stack grows in this segment in 3.2.6, “Resource limits in 32-bit model” on page 125.

Environment variables

Environment variables are accessible from a process using either of the following, regardless of user process models, including 64-bit:

  • The environ extern symbol (see Example 3-2 on page 113).

  • The third parameter of the main() routine. This parameter is commonly represented as envp, as shown in the following example:

    int main(int argc, char *argv[], char *envp[]);
    
  • The getenv() sub-routine call.

On AIX, environment variables are copied into the process stack by the system loader as a part of the process initialization tasks. The maximum size of environment variables per process are defined by a system-wide configuration value, ncargs, as shown in the following example:[10]

[10] The ncargs system parameter has been supported on AIX since Version 5L Version 5.1.

# lsattr -El sys0 -a ncargs
ncargs 6 ARG/ENV list size in 4K byte blocks True

The default value 6 means 6 pages x 4 [KB/page] = 24 KB. If a process is given environment variables that require more than ncargs x 4 KB, those environment values that exceeded the value will not be copied into virtual pages and cannot be accessed by the process.

If you need to increase ncargs, do either of the following as the root user:

  • Use the chattr command:

    # chattr -El sys0 -a ncargs=N
    								

    where N is the number of pages that can be used for environment variables per-process basis.

  • Use SMIT

    Select System Environments → Change / Show Characteristics of Operating System, then specify an appropriate number in the “ARG/ENV list size in 4K byte block” field, and then press Enter.

In both ways, the minimum value is 6, and the maximum value is 128 (512 KB). This change takes affect immediately and is preserved over boot.

Note

The default value ncargs = 6 is sufficient for most processes. Change it only when your applications absolutely require a larger size of environment variables. If there are many processes that require a large size of environment variables, those processes may consume a significant amount of memory.


3.2.2. Large memory model

Although many 32-bit applications do not require a heap size more than 256 MB, there has been a huge demand to run 32-bit user processes with a larger size of initialized data, process heap, or process stack. To address this demand, AIX has been supporting another memory model called large memory model, as a variation of the 32-bit user process model.

The concept of the large memory model is simple. By sacrificing segments available for shared memory segments, the user process running in the large memory model can place its heap on those segments (see Figure 3-4).

Figure 3-4. Large memory model (segment usage)


In Figure 3-4, four segments (0x3 - 0x6) are reserved for heap, so seven segments (0x7 - 0xC and 0xE) are available for shared memory segments.

Because the process heap and initialized and un-initialized data are moved from the 0x2 segment to 0x3, the user stack can enjoy more room in the 0x2 segment in this model.

To apply the large memory model to your application programs, see 3.2.4, “Using the large and very large memory model” on page 121.

Note

In the large memory model, the soft data limit of a process has a slightly different effect (see 3.2.6, “Resource limits in 32-bit model” on page 125).


3.2.3. Very large memory model

In addition to the large memory model, AIX 5L Version 5.2 supports another model, called very large memory model, as a variation of the 32-bit user process model. AIX 5L Version 5.1 also supports some of the features provided by the very large memory model; it does support up to 2 GB heap memory, but not up to 3.25 GB.

Although the concept of the very large memory model remains the same, there are three different allocation mechanisms, depending on the maxdata value setting explained in 3.2.6, “Resource limits in 32-bit model” on page 125:

To apply the very large memory model to your application programs, see 3.2.4, “Using the large and very large memory model” on page 121.

Note

In the very large memory model, the soft data limit of a process has a slightly different effect (see 3.2.6, “Resource limits in 32-bit model” on page 125).


Heap size less than 2.5 GB

The big difference between the very large memory model and the large memory model is that segments can be dynamically allocated. In the large memory model, the allocation of segments are rigid, and there is no way to alter this segment allocation while executing the application program. The very large memory model relaxes this limitation by providing a new function, called dynamic segment allocation (DSA).

With DSA, segments are dynamically allocated to either the process heap or shared memory segments in the address space. Once a segment is allocated to either the process heap or shared memory segments, it cannot be returned to the free pool of segments, even if all virtual pages in the segment are relinquished.

In Figure 3-5 on page 118, we are assuming that a process is running with maxdata=0xA0000000 and the DSA option specified, which means the process can acquire heap memory up to 10 segments (2.5 GB).

Figure 3-5. Very large memory model (0 < maxdata > 0xB0000000)


Another big difference between the very large and large memory models is the direction of how shared memory segments are allocated. In this figure, shared memory segments will be allocated in the segments, starting from 0xE, 0xC, 0xB, and on towards 0x3, if the target segments are not already allocated to the process heap. To understand how these segments are allocated, see 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.

Because of the process heap, initialized and un-initialized data are moved from the 0x2 segment to 0x3, and the user stack can enjoy more room in the 0x2 segment in this model.

Note

AIX 5L Version 5.1 supports this model only when maxdata is less than or equal to 0x80000000.


Heap size greater than 2.5 GB

If a process is running with maxdata=0xB0000000 and greater with DSA, then the address space has a significant change; there are no shared text segments available, as shown in Figure 3-6 on page 119. Therefore, all the shared text and data that are referenced by the process will be loaded into the 0x2 segment, as private shared objects, even if the other processes has already loaded shared objects into the system memory. The process performance might be affected by this change.

Figure 3-6. Very large memory model (0xB0000000 =< maxdata < 0xD0000000)


However, by sacrificing segments 0xD - 0xF, the process can acquire heap memory up to 13 segments (3.25 GB). Also, shared memory segments will be allocated in the segments, starting from 0xF, 0xE, 0xD, and on towards 0x3, if the target segments are not already allocated to the process heap. To understand how these segments are allocated, see 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.

Heap size less than 256 MB

If a process is running with maxdata=0 with DSA, then all the following memory components are packed into the 0x2 segment:

  • Initialized data

  • Uninitialized data

  • Process heap

  • Process stack

  • Shared library text

  • Shared library data

Apparently, this does not provide much room for the process heap; in fact, it is smaller than the default memory model. However, it ensures that all 13 segments (3.25 GB) are available for shared memory segments in the address space. Some application programs that manage their own memory requests on shared memory segments can exploit this memory model. To understand how these segments are allocated, see 3.5.2, “Order in the 32-bit very large memory model with DSA” on page 154.

Note

If you decide to apply this memory model to your application, it is your responsibility to ensure that the process heap and stack usage are well managed. You must be aware that the 0x2 segment can be easily corrupted in this model.


Figure 3-7. Very large memory model (maxdata = 0)


Note

  • On AIX 5L Version 5.1, shared library text and data will be loaded into segments 0xD and 0xF in this model (maxdata=0 with DSA).

  • This model does not support large pages (see 3.6, “Large page support” on page 157).


3.2.4. Using the large and very large memory model

To use the large memory model, any one of the following methods are supported:

  • Specify the -bmaxdata:0xN0000000 linker option when linking your source codes (where N is hexadecimal from 0 to 8).

  • After compiling the source code, binary-edit the XCOFF header file of the generated executable file using the /usr/ccs/bin/ldedit command. For example:

    $ /usr/ccs/bin/ldedit -bmaxdata:0x60000000 a.out
    
  • Specify the LDR_CNTRL environment value when running the executable. For example:

    $ LDR_CNTRL=MAXDATA=0x80000000 a.out
    

To use the very large memory model, the following methods are supported:

  • Specify the -bmaxdata:0xN00000000/dsa compiler option when compiling your source codes (where N is hexadecimal from 0 to D).

  • After compiling the source code, binary-edit the XCOFF header file of the generated executable file using the /usr/ccs/bin/ldedit command. For example:

    $ /usr/ccs/bin/ldedit -bmaxdata:0x80000000/dsa a.out
    
  • Specify the LDR_CNTRL environment value when running the executable. For example:

    $ LDR_CNTRL=MAXDATA=0xC0000000@DSA a.out
    

Note

When using the LDR_CNTRL environment variable, the keyword DSA must be upper case character, while dsa must be lower case characters in the other two methods.


To demonstrate the usage, we have prepared the short example program shown in Example 3-3. When executed, it takes an integer as a command line parameter, which will be used as an index to allocate memory with a size of multiplies of 256 MB from the process heap.

Example 3-3. grabheap_32.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

#define ONE_SEG (256 * 1024 * 1024)
int main(int argc, char *argv[])
{
    char    *p;
    char    buf[BUFSIZ];
    int     rc;
    size_t  sz, sz_7;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s digit-number
", argv[0]);
        exit(1);
    }
    sz = atoi(argv[1]);

    if (sz > 7) {
        sz_7 = sz - 7;

        if ((p = malloc(7 * ONE_SEG)) == (void *)NULL) {
            sprintf(buf, "1st malloc() with 7 × 256 MB failed with errno = %d"
                    , errno);
            perror(buf);
        } else {
            printf("1: starting address of 7 × 256 MB memory heap is 0x%08p
"
                , p);
            printf("1: ending address of 7 × 256 MB memory heap is 0x%08p
"
                , p + (7 * ONE_SEG));
        }
        if ((p = malloc(sz_7 * ONE_SEG)) == (void *)NULL) {
            sprintf(buf, "2nd malloc() with %d x 256 MB failed with errno = %d"
                    , sz_7, errno);
            perror(buf);
        } else {
            printf("2: starting address of %d x 256 MB memory heap is 0x%08p
"
                , sz_7, p);
            printf("2: ending address of %d x 256 MB memory heap is 0x%08p
"
                , sz_7, p + (sz_7 * ONE_SEG) - 1);
        }
    } else {
        if ((p = malloc(sz * ONE_SEG)) == (void *)NULL) {
            sprintf(buf, "malloc() with %d x 256 MB failed with errno = %d"
                    , sz, errno);
            perror(buf);
        } else {
            printf("starting address of %d x 256 MB memory heap is 0x%08p
"
                , sz, p);
            printf("ending address of %d x 256 MB memory heap is 0x%08p
"
                , sz, p + (sz * ONE_SEG) - 1);
        }
    }
   exit(0);
}

The following example shows the output when we run Example 3-3 on page 121 using the very large memory model on AIX 5L Version 5.1:

$ oslevel -r
5100-03
$ cc grabheap_32.c
$ LDR_CNTRL=MAXDATA=0xD0000000@DSA ./a.out 7
starting address of 7 × 256 MB memory heap is 0x30000968
ending address of 7 × 256 MB memory heap is 0xa0000967
$ LDR_CNTRL=MAXDATA=0xD0000000@DSA ./a.out 8
1: starting address of 7 × 256 MB memory heap is 0x30000968
1: ending address of 7 × 256 MB memory heap is 0xa0000967
2nd malloc() with 1 × 256 MB failed with errno = 12: Not enough space

The second call of malloc() failed with errno = 12 (ENOMEM), because it requested another 256 MB in addition to the already acquired 7 × 256 MB (1.75 GB) heap memory. Although AIX 5L Version 5.1 supports the heap size up to 2 GB, there is always a very small amount of overhead memory (initialized and un-initialized data) required in the beginning of segment 0x3 in the large and very large memory model regardless of operating system versions.

The following example shows the output when we run Example 3-3 on page 121 using the very large memory model on AIX 5L Version 5.2:

$ oslevel
5.2.0.0
$ cc grabheap_32.c
$ LDR_CNTRL=MAXDATA=0xD0000000@DSA ./a.out 12
1: starting address of 7 × 256 MB memory heap is 0x30000988
1: ending address of 7 × 256 MB memory heap is 0xa0000987
2: starting address of 5 × 256 MB memory heap is 0a0000998
2: ending address of 5 × 256 MB memory heap is 0xf0000997

The first call of malloc() acquired memory from the segment 0x3 to 0xA and the second call acquired memory from the segment 0xA to 0xF; the outcome is clear. This process successfully acquired 12 × 256 MB = 3 GB memory in total. In fact, the program could have requested more memory, roughly 256 MB; therefore, it could have acquired roughly 3.25 GB memory in total.

If your application needs a heap size larger than 2 GB in the very large memory model, then it must call system heap allocation routines, such as malloc() and calloc(), more than once, like we did in Example 3-3 on page 121. The reason for this limitation is that the sbrk() system call, which is internally called from system heap allocation routines, takes a signed integer value as a parameter. Therefore, it cannot extend the break value more than 2 GB within a single call.

For further information about the use of the system heap, see Chapter 4, “Managing the memory heap” on page 165.

3.2.5. Checking large memory model executables

After compiling your source code with the -bmaxdata:0xN0000000 option, use the file command with the modified /etc/magic file to check if the o_maxdata field in the XCOFF header of executable is correctly set. On AIX, instead of the /etc/magic file, the file command consults with a locale message file (depending on the current locale setting) by default. Therefore, to have the command refer to the modified /etc/magic file, do the following:

1.
Log in to the system as the root user.

2.
Create a backup of the original /etc/magic:

# cp -p /etc/magic /etc/magic.orig

3.
Edit the file and add highlighted lines in Example 3-4 using a text editor, then save the file and exit.

4.
Run the file command against the executable file with the -m /etc/magic option.

Example 3-4. Excerpt of modified /etc/magic
0   short     0x01df       executable (RISC System/6000) or object module
>12 long      >0       not stripped
>18 byte      0x14         LP_TEXT
						>18 byte      0x18         LP_DATA
						>19 byte      >0x3F        /DSA
						>76 long      0x00000000   (maxdata=0)
						>76 long      0x10000000   (maxdata=1)
						>76 long      0x20000000   (maxdata=2)
						>76 long      0x30000000   (maxdata=3)
						>76 long      0x40000000   (maxdata=4)
						>76 long      0x50000000   (maxdata=5)
						>76 long      0x60000000   (maxdata=6)
						>76 long      0x70000000   (maxdata=7)
						>76 long      0x80000000   (maxdata=8)
						>76 long      0x90000000   (maxdata=9)
						>76 long      0xA0000000   (maxdata=A)
						>76 long      0xB0000000   (maxdata=B)
						>76 long      0xC0000000   (maxdata=C)
						>76 long      0xD0000000   (maxdata=D)
0   short     0x01f7       64-bit XCOFF executable or object module
>18 byte      0x14         LP_TEXT
						>18 byte      0x18         LP_DATA
						>19 byte      >0x3F        /DSA
>20 long      >0       not stripped

Example 3-5 shows the sample output from the executable file compiled with the -bmaxdata:0x80000000/dsa option.

Example 3-5. Checking large memory executable with modified /etc/magic
$ cc -bmaxdata:0x80000000 helloworld.c
$ file a.out
a.out:          executable (RISC System/6000) or object module not stripped
$ file -m /etc/magic a.out
a.out:          executable (RISC System/6000) or object module not stripped /DSA (maxdata=8)
					

For further information about the /etc/magic file and XCOFF format, please refer to the AIX 5L Version 5.2 Files Reference.

3.2.6. Resource limits in 32-bit model

The resource limits are used to regulate several resources consumed by a process on UNIX operating systems. Although the resource limits are set on a per-user basis, they are applied on a per-process basis. Therefore, if a user is executing hundreds of processes, the user may consume huge amounts of resources, even if the resource setting values for the user are relatively small numbers.

To display the current user’s resource limits, use the ulimit command (see Example 3-6).

Example 3-6. Default resource limits setting
$ ulimit -Ha
time(seconds)        unlimited
file(blocks)         2097151
data(kbytes)         unlimited
stack(kbytes)        unlimited
memory(kbytes)       unlimited
coredump(blocks)     unlimited
nofiles(descriptors) unlimited
$ ulimit -Sa
time(seconds)        unlimited
file(blocks)         2097151
data(kbytes)         131072
stack(kbytes)        32768
memory(kbytes)       32768
coredump(blocks)     2097151
nofiles(descriptors) 2000

The -H option instructs the command to display hard resource limits, while the -S option instructs the command to display soft resource limits. [11] The hard resource limit values are set by the root user using the chuser command for each user. The soft resource limit values can be relaxed by the relaxed by the individual user using the ulimit command, as long as the values are smaller than or equal to the hard resource limit values.

[11] Resource limits are defined in the /etc/security/limits file on a per-user basis.

Although there are seven types of resource limits displayed in Example 3-6 on page 125, we only discuss the data and stack resource limits, which regulate process heap and stack usage. For further information about resource limits, please refer to the command reference of ulimit, found in the AIX 5L Version 5.2 Reference Documentation: Commands Reference.

Resource limits in the default memory model

In the default memory model, soft data and stack resource limits are strictly enforced. During the process initialization tasks, the kernel sets soft data and stack resource limits in the process address space (see Figure 3-8 on page 126). While the process is running, the heap and stack can grow up to the soft data limits from opposite directions, as represented by arrows in the figure.

Figure 3-8. Data and stack resource limits (default 32-bit process model)


If either the data or stack soft limit is set to unlimited before the program execution, or if the setrlimit() routine is called to set these limit values to unlimited while the process is running, it is your responsibility to prevent the process stack from being overwritten by the over-grown process heap.

Resource limits in the very large and large memory model

When you execute a program that uses the large memory model, the operating system attempts to modify the soft limit on the data size to match the maxdata value. If the maxdata value is greater than the current hard limit on the data size, either the program will not execute, if the environment variable XPB_SUS_ENV has the value set to ON, or the soft limit will be set to the current hard limit. If the maxdata value is smaller than the size of the program’s static data, the program will not execute.

To demonstrate this behavior, we have prepared a simple program, shown in Example 3-10 on page 128. When compiled and executed, it prints the soft and hard resource limit values by calling the getrlimit() sub-routine.

When we have executed this program in the default memory model, it prints the values shown in Example 3-7 on page 127.

Example 3-7. Verifying resource limits in default memory model
$ a.out
Resource name               Soft                Hard
RLIMIT_CORE           1073741312          2147483647
RLIMIT_CPU            2147483647          2147483647
RLIMIT_DATA            134217728          2147483647
RLIMIT_FSIZE          1073741312          1073741312
RLIMIT_NOFILE               2000          2147483647
RLIMIT_STACK            33554432          2147483647
RLIMIT_RSS              33554432          2147483647

You will find that this output resembles Example 3-6 on page 125.

On AIX, all hard resource limit values are set to unlimited by default, except for the file resource limit. The value unlimited is defined as 0x7FFFFFFF in the /usr/include/sys/resource.h include file when the program is running in the 32-bit user process model (see Example 3-8).

Example 3-8. RLIM_INFINITY definition
#if defined(__64BIT__) && !defined(__64BIT_KERNEL)
#define RLIM_INFINITY   0x7fffffffffffffffL
#else
#define RLIM_INFINITY   0x7FFFFFFF
#endif /* __64BIT__ */

When we have executed this program in the large memory model, it prints the values shown in Example 3-10 on page 128. As shown in this example, the soft data limit value is set to RLIM_INFINITY without using either the ulimit command or the setrlimit() sub-routine.

Example 3-9. Verifying resource limits in large memory model without DSA
$ LDR_CNTRL=MAXDATA=0x80000000 a.out
Resource name                   Soft                   Hard
RLIMIT_CORE               1073741312             2147483647
RLIMIT_CPU                2147483647             2147483647
RLIMIT_DATA               2147483645             2147483647
RLIMIT_FSIZE              1073741312             1073741312
RLIMIT_NOFILE                   2000             2147483647
RLIMIT_STACK                33554432             2147483647
RLIMIT_RSS                  33554432             2147483647

In fact, when we executed the program shown in Example 3-3 on page 121 using the large and very large memory models, we did not increase the soft data limit value.

Example 3-10 is a program that calls the getrlimit() routine to print current soft and hard resource limit values.

Example 3-10. printlimits.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>

#define pr_limit(XXX)  print_limit(#XXX, XXX)

void
print_limit(const char *name, int resource)
{
    int rc;
    char    buf[BUFSIZ];
    struct  rlimit  rlimit;

    if ((rc = getrlimit(resource, &rlimit)) < 0) {
        sprintf(buf, "getrlimit() failed with errno = %d, at %d in %s"
            , errno, __LINE__,__FILE__);
        perror(buf);
    } else {
        printf("%-14s	%20ld	%20ld
"
            , name, rlimit.rlim_cur, rlimit.rlim_max);
    }
}

int
main(int argc, char *argv[])
{
    printf("%-14s	%20s	%20s
", "Resource name", "Soft", "Hard");
    pr_limit(RLIMIT_CORE);
    pr_limit(RLIMIT_CPU);
    pr_limit(RLIMIT_DATA);
    pr_limit(RLIMIT_FSIZE);
    pr_limit(RLIMIT_NOFILE);
    pr_limit(RLIMIT_STACK);
    pr_limit(RLIMIT_RSS);
}

3.2.7. Large file support in a 32-bit model

In the computer industry, the term large file is generally considered to refer to a file larger than 2 GB. In the 32-bit user process model, the data type off_t is defined as signed long type. Therefore, by default, 32-bit processes can handle files up to 2 GB -1 byte, which is addressable by the off_t type. If a 32-bit process attempts to seek a file pointer more than 2 GB, then the system call fails with errno EOVERFLOW. This limitation exists on all UNIX operating systems that conform to the POSIX standards.

Beginning with AIX Version 4.2.1, there are two methods to work around the addressability of large files in the 32-bit user process model:

  • If the -D_LARGE_FILE option is specified when compiling the program, the off_t type is redefined as long long (64-bit signed integer). Also, most system calls and library routines are redefined to support large files.

  • In some circumstances, your existing 32-bit user programs might be corrupted by defining the _LARGE_FILE macro, especially if off_t is interchangeably used with the int or long type within your source codes. In this case, you can modify your source codes to explicitly call 64-bit versions of file I/O related system calls and library routines, such as fopen64(), lseek64(), and so on. Also, variables defined as the off_t type must be carefully converted to off64_t.

Using one of the above methods, 32-bit processes can handle large files as long as the following conditions are met:

  • The file hard and soft limits have been relaxed. The default value of file limit is 2,097,151 disk blocks = 1 GB (see Example 3-6 on page 125).

  • JFS2 or large file enabled JFS is used.

For further information about large file support of the 32-bit user process, please refer to the “Writing Programs That Access Large Files” section in AIX 5L Version 5.2 General Programming Concepts: Writing and Debugging Programs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset