[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

Программирование: Разработка и отладка программ


Пользовательские аналоги функции Malloc

Теперь у пользователя есть возможность заменить функции подсистемы памяти AIX (malloc, calloc, realloc, free, mallopt и mallinfo) собственными функциями.

Примечание: Пользовательские подсистемы памяти, написанные на языке C++, не поддерживаются, так как в библиотеке C++ libC.a используется подсистема памяти libc.a.

Существующая подсистема памяти может применяться всеми приложениями, независимо от того, используются ли в них нити. Пользовательская подсистема памяти должна быть подсистемой с защитой нитей, то есть подсистемой, поддерживающей процессы с нитями и без нитей. Ответственность за выполнение этого требования ложиться на пользователя. Загрузка модуля памяти без защиты нитей в приложение с нитями может привести к повреждению памяти и данных.

32- и 64-разрядные объекты пользовательской подсистемы памяти должны размещаться в архиве вместе с 32-разрядным общим объектом mem32.o и 64-разрядным общим объектом mem64.o.

Пользовательские общие объекты должны экспортировать следующие идентификаторы:

Ниже приведены определения пользовательских функций:

void *__malloc__(size_t) :
Пользовательский эквивалент функции malloc(), описание которой приведено в документации по AIX.

void __free__(void *) :
Пользовательский эквивалент функции free(), описание которой приведено в документации по AIX.

void *__realloc__(void *, size_t) :
Пользовательский эквивалент функции realloc(), описание которой приведено в документации по AIX.

void *__calloc__(size_t, size_t) :
Пользовательский эквивалент функции calloc(), описание которой приведено в документации по AIX.

int __mallopt__(int, int) :
Пользовательский эквивалент функции mallopt(), описание которой приведено в документации по AIX.

struct mallinfo __mallinfo__() :
Пользовательский эквивалент функции mallinfo(), описание которой приведено в документации по AIX.

Ниже перечислены интерфейсы, применяемые подсистемой с нитями для управления пользовательской подсистемой памяти в среде с несколькими нитями. Они вызываются только в том случае, если приложение и/или пользовательский модуль связаны с libpthreads.a. Эти идентификаторы должны быть определены и экспортированы, даже если в пользовательской системе нет защиты нитей, и она не связана с libpthreads.a; в противном случае объект не будет загружен.

void __malloc_init__(void)
Вызывается процедурой инициализации API нитей. Данная функция применяется для инициализации пользовательской подсистемы памяти с защитой нитей. В большинстве случаев данная функция создает и инициализирует некоторые типы блокировки данных. Даже если модуль пользовательской подсистемы памяти связан с libpthreads.a, пользовательская подсистема памяти должна быть запущена перед вызовом __malloc_init__().

void __malloc_prefork_lock__(void)
Вызывается процедурами API нитей при обращении к fork(). Данная функция контролирует, что перед вызовом fork() подсистема находится в допустимом состоянии и остается в нем до завершения функции fork(). В большинстве случаев эта функция устанавливает блокировки подсистемы памяти.

void __malloc_postfork_unlock__(void)
Вызывается процедурами API нитей при обращении к fork(). Данная функция снимает блокировки подсистемы памяти в родительском и дочернем процессе после завершения процедуры fork(). Она отменяет действие функции __malloc_prefork_lock__(). В большинстве случаев эта функция отменяет блокировки подсистемы памяти.

Все эти функции должны быть экспортированы из общего модуля. Для 32- и 64-разрядных реализаций в архиве должны быть созданы разные модули. Например:

Подключение

Пользовательскую подсистему управления памятью можно подключить различными способами:

Для применения переменной среды MALLOCTYPE нужно задать архив, содержащий пользовательскую подсистему памяти, присвоив переменной MALLOCTYPE значение user:имя-архива, где имя-архива - это значение переменной приложения libpath или значение переменной среды LIBPATH.

Для применения глобальной переменной _malloc_user_defined_name она должна быть объявлена в программе следующим образом:

char *_malloc_user_defined_name="архив"

архив должен быть указан в переменной libpath программы или в переменной среды LIBPATH.

Примечания:
  1. При выполнении приложения setuid переменная среды LIBPATH игнорируется, поэтому имя архива должно быть определено в libpath приложения.
  2. Имя-архива не должно содержать информацию о пути.
  3. Если архив указан и в переменной среды MALLOCTYPE, и в глобальной переменной _malloc_user_defined_name, то будет применяться архив, указанный в переменной MALLOCTYPE.

Рекомендации по работе с 32- и 64-разрядными функциями

Если архив не содержит ни 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.


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]