Теперь у пользователя есть возможность заменить функции подсистемы памяти AIX (malloc, calloc, realloc, free, mallopt и mallinfo) собственными функциями.
Примечание: Пользовательские подсистемы памяти, написанные на языке C++, не поддерживаются, так как в библиотеке C++ libC.a используется подсистема памяти libc.a.
Существующая подсистема памяти может применяться всеми приложениями, независимо от того, используются ли в них нити. Пользовательская подсистема памяти должна быть подсистемой с защитой нитей, то есть подсистемой, поддерживающей процессы с нитями и без нитей. Ответственность за выполнение этого требования ложиться на пользователя. Загрузка модуля памяти без защиты нитей в приложение с нитями может привести к повреждению памяти и данных.
32- и 64-разрядные объекты пользовательской подсистемы памяти должны размещаться в архиве вместе с 32-разрядным общим объектом mem32.o и 64-разрядным общим объектом mem64.o.
Пользовательские общие объекты должны экспортировать следующие идентификаторы:
Ниже приведены определения пользовательских функций:
Ниже перечислены интерфейсы, применяемые подсистемой с нитями для управления пользовательской подсистемой памяти в среде с несколькими нитями. Они вызываются только в том случае, если приложение и/или пользовательский модуль связаны с libpthreads.a. Эти идентификаторы должны быть определены и экспортированы, даже если в пользовательской системе нет защиты нитей, и она не связана с libpthreads.a; в противном случае объект не будет загружен.
Все эти функции должны быть экспортированы из общего модуля. Для 32- и 64-разрядных реализаций в архиве должны быть созданы разные модули. Например:
__malloc__ __free__ __realloc__ __calloc__ __mallopt__ __mallinfo__ __malloc_init__ __malloc_prefork_lock__ __malloc_postfork_unlock__
Содержит все необходимые 32-разрядные функции
Содержит все необходимые 64-разрядные функции
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
ar -X32_64 -r архив mem32.o mem64.o
Примечание: В приведенных примерах создания общих объектов нужно указать флаг -lpthreads, если они применяют функции API нитей.
Пользовательскую подсистему управления памятью можно подключить различными способами:
Для применения переменной среды MALLOCTYPE нужно задать архив, содержащий пользовательскую подсистему памяти, присвоив переменной MALLOCTYPE значение user:имя-архива, где имя-архива - это значение переменной приложения libpath или значение переменной среды LIBPATH.
Для применения глобальной переменной _malloc_user_defined_name она должна быть объявлена в программе следующим образом:
char *_malloc_user_defined_name="архив"
архив должен быть указан в переменной libpath программы или в переменной среды LIBPATH.
Примечания:
- При выполнении приложения setuid переменная среды LIBPATH игнорируется, поэтому имя архива должно быть определено в libpath приложения.
- Имя-архива не должно содержать информацию о пути.
- Если архив указан и в переменной среды MALLOCTYPE, и в глобальной переменной _malloc_user_defined_name, то будет применяться архив, указанный в переменной MALLOCTYPE.
Если архив не содержит ни 32-, ни 64-разрядных общих объектов, а пользовательская подсистема памяти была подключена с помощью переменной среды MALLOCTYPE, то при выполнении 64-разрядных процессов в 32-разрядных приложениях или 32-разрядных процессов в 64-разрядных приложениях могут возникать сбои. Если новый процесс создается с помощью функции exec(), он наследует среду родительского приложения. Это значит, что будет унаследовано значение MALLOCTYPE, и новый процесс попытается загрузить пользовательскую подсистему памяти. Если в архиве нет компонента для процесса данного типа, подсистема не будет загружена, и процесс будет завершен.
Все подключаемые функции управления памятью должны работать в среде с несколькими нитями. Даже если модуль связан с libpthreads.a, перед вызовом __malloc_init__() и инициализацией API нитей нужно вызвать как минимум функцию __malloc__(). Это связано с тем, что при инициализации API нитей перед обращением к __malloc_init__() вызывается функция malloc().
Все подключаемые функции управления памятью должны поддерживать как приложения с нитями, так и приложения без нитей. Функция __malloc__() не должна зависеть от функции __malloc_init__() (т.е. при вызове __malloc__() предполагается, что функция __malloc_init__() еще НЕ запущена.) После выполнения функции __malloc_init__() ее результаты могут использоваться функцией __malloc__(). Это связано с тем, что при инициализации API нитей функция malloc() вызывается перед обращением к функции __malloc_init__().
Для предотвращения вызова недопустимых функций, связанных с нитями, существуют две специальные переменные. Значение первой переменной, __multi_threaded, равно нулю до тех пор, пока нить не будет создана; после создания нити значение становится ненулевым и сохраняется до тех пор, пока не будет обнулено. Значение второй переменной, __n_pthreads, равно -1 до тех пор, пока не будет инициализирован API нитей; после инициализации значение становится равным 1. С этого момента данная переменная используется в качестве счетчика активных нитей.
Пример:
Ниже приведен фрагмент кода для случая, когда функция __malloc__() применяет функцию pthread_mutex_lock():
if (__multi_threaded) pthread_mutex_lock(mutexptr); /* ..... операторы ....... */ if (__multi_threaded) pthread_mutex_unlock(mutexptr);
Такой код не только запрещает процедуре __malloc__() выполнять функции API нитей, пока он не будет полностью инициализирован, но и позволяет повысить быстродействие приложений с одной нитью, так как блокировка устанавливается только после запуска второй нити.
Подсистемы памяти, написанные на языке C++, не поддерживаются, так как в них применяются библиотека libC.a и подсистема памяти libc.a.
Сообщения об ошибках не переводятся, поскольку при инициализации локалей с помощью setlocale() применяется функция malloc(). Если при вызове malloc() произойдет сбой, то setlocale() не будет выполнена, и приложение останется в локали POSIX. Это означает, что будут выводиться сообщения на английском языке.
Существующие программы, созданные с помощью статической компоновки, не смогут работать с пользовательской подсистемой памяти без перекомпиляции.
При первом обращении к malloc() загружается 32- или 64-разрядный объект из архива, заданного в переменной среды MALLOCTYPE. Если объект не будет загружен, то появится сообщение об ошибке, и работа приложения будет завершена. В противном случае проверяется наличие всех необходимых идентификаторов. Если какие-то идентификаторы отсутствуют, работа приложения завершается, и выводится сообщение со списком недостающих идентификаторов.
Глава 11, Создание программ с нитями
Функции malloc, free, realloc, calloc, mallopt, mallinfo, alloca и valloc.