The AIX memory subsystem (malloc(), calloc(), realloc(), free(), mallopt() and mallinfo()) has been modified to allow users to replace it with one of their own design.
NOTE: Replacement Memory Subsystems written in C++ are not supported due to the use of the libc.a memory subsystem in the C++ library libC.a.
The existing memory subsystem works for both threaded and non-threaded applications. The user defined memory subsystem should be thread-safe so that it works in both threaded and non-threaded processes, however, there are no checks to verify that it is. So, if a non-thread safe memory module is loaded in a threaded application, memory and data may be corrupted.
The user defined memory subsystem 32 and 64 bit objects must be placed in an archive with the 32bit shared object named mem32.o and the 64bit shared object named mem64.o.
The user shared objects must export the following symbols :
The functions are defined as follows:
The following interfaces are used by the thread subsystem to manage the user defined memory subsystem in a multi-threaded environment. The are only called if the application and/or the user defined module are bound with libpthreads.a. Even if the the user defined subsystem is not thread-safe and not bound with libpthreads.a these symbols must be defined and exported or the object will not be loaded.
All of the functions must be exported from a shared module. There must be separate modules for 32 and 64 bit implementations place in an archive. For example:
__malloc__ __free__ __realloc__ __calloc__ __mallopt__ __mallinfo__ __malloc_init__ __malloc_prefork_lock__ __malloc_postfork_unlock__
Contains all of the required 32 bit functions
Contains all of the required 64 bit functions
ld -b32 -m -o mem32.o mem_functions32.o \ -bE:mem.exp \ -bM:SRE -lpthreads -lc
ld -b64 -m -o mem64.o mem_functions64.o \ -bE:mem.exp \ -bM:SRE -lpthreads -lc
Creating the archive (the shared objects name must be mem32.o for the 32bit object and mem64.o for the 64bit object):
ar -X32_64 -r <archive_name> mem32.o mem64.o
NOTE: In the above examples for creating the shared objects -lpthreads is only needed if the object uses pthread functions.
The user defined memory subsystem is enable by using the MALLOCTYPE environment variable. The archive containing the user defined memory subsystem is specified by setting MALLOCTYPE to user:<archive_name> where <archive_name> is in the application's libpath or the path is specified in the LIBPATH environment variable.
NOTES:
- When a setuid application is exec'd, the LIBPATH environment variable is ignored so the archive must be in the applications libpath.
- <archive_name> cannot contain path information.
If the archive does not contain both the 32 and 64 bit shared objects and the user defined memory subsystem was enabled using the MALLOCTYPE environment variable, there will be problems exec'ing 64bit processes from 32bit applications and 32bit processes from 64bit applications. When an new process is created using exec(), it inherits the environment of the calling application. This means that MALLOCTYPE will be inherited and the new process will attempt to load the user defined memory subsystem. If the archive member does not exist for this type of executable, the load will fail and the new process will exit.
All of the provided memory functions must work in a multi-threaded environment. Even if the module is linked with libpthreads.a, at least __malloc__() MUST work before __malloc_init__() is called and pthreads is initialized. This is required because the pthread initialization requires malloc() before __malloc_init__() is called.
All provided memory functions must work in both threaded and non-threaded environments. The __malloc__() function should be able to run to completion without having any dependencies on __malloc_init__() (i.e. __malloc__() should initially assume that __malloc_init__() has NOT yes run.) Once __malloc_init__() has completed, then __malloc__() can rely on any work done by __malloc_init__(). This is required because the pthread initialization uses malloc() before __malloc_init__() is called.
There are two variables provided to keep from calling thread related routines when they are not needed. The first, __multi_threaded, is zero until a thread is created when it becomes non-zero and for that process will not be reset to zero. The other variable, __n_pthreads, is -1 until pthreads has been initialized when it is set to 1. From that point on it is a count of the number of active threads.
Example:
If __malloc__() uses pthread_mutex_lock() the code may look something like this:if (__multi_threaded) pthread_mutex_lock(mutexptr); /* ..... work ....... */ if (__multi_threaded) pthread_mutex_unlock(mutexptr);
Not only does this keep __malloc__() from executing pthread functions before pthreads is fully initialized, it also speeds up single threaded applications because locking is not done until a second thread is started.
Memory subsystems written in C++ are not supported due to initialization and the dependencies of libC.a and the libc.a memory subsystem.
Error messages are not translated due to setlocale() using malloc() to initialize the locales. If malloc() fails then setlocale() cannot finish and the application is still in the POSIX locale so only the default English messages will be displayed.
Existing statically built executables will not be able to use the user defined memory subsystem without recompiling.
The first time malloc() is called, the 32 or 64 bit object in the archive specified by the MALLOCTYPE environment variable is loaded. If the load fails, a message will be displayed and the application will exit. If the load is successful, an attempt is made to verify that all of the required symbols are present. If any symbols are missing the application will be terminated and the list of missing symbols will displayed.
Chapter 11. Threads Programming Guidelines
The malloc, free, realloc, calloc, mallopt, mallinfo, alloca, or valloc subroutine.