Пользовательские аналоги функций из подсистемы памяти
Пользователи могут заменить функции подсистемы памяти (функции malloc, calloc, realloc, free, mallopt и mallinfo subroutines ) собственными функциями.
Существующая подсистема памяти может применяться всеми приложениями, независимо от того, используются ли в них нити. Пользовательская подсистема памяти должна обеспечивать поддержку нитей, для того чтобы она могла применяться как в процессах с нитями, так и в процессах без нитей. Наличие такой поддержки не проверяется, однако загрузка модуля памяти без поддержки нитей в приложение с нитями может привести к повреждению памяти и данных.
32- и 64-разрядные объекты пользовательской подсистемы памяти должны размещаться в архиве вместе с 32-разрядным общим объектом mem32.o и 64-разрядным общим объектом mem64.o.
- __malloc__
- __free__
- __realloc__
- __calloc__
- __mallinfo__
- __mallopt__
- __malloc_init__
- __malloc_prefork_lock__
- __malloc_postfork_unlock__
- __malloc_start__
- __posix_memalign__
Если данные символы не выйдут, выполнение программы продолжится.
- void *__malloc__(size_t) :
- Пользовательский эквивалент функции malloc.
- void __free__(void *) :
- Пользовательский эквивалент функции free.
- void *__realloc__(void *, size_t) :
- Пользовательский эквивалент функции realloc.
- void *__calloc__(size_t, size_t) :
- Пользовательский эквивалент функции calloc.
- int __mallopt__(int, int) :
- Пользовательский эквивалент функции mallopt.
- struct mallinfo __mallinfo__() :
- Пользовательский эквивалент функции mallinfo.
void __malloc_start__()- Эта функция вызывается один раз перед вызовом любой другой пользовательской функции malloc.
void __posix_memalign__()- Пользовательский эквивалент функции posix_memalign. Если данный символ не выйдет, программа будет продолжаться, но вызов процедуры posix_memalign может вызвать ошибку.
- 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__. В большинстве случаев, эта функция снимает блокировки подсистемы памяти.
- Модуль mem.exp:
__malloc__ __free__ __realloc__ __calloc__ __mallopt__ __mallinfo__ __malloc_init__ __malloc_prefork_lock__ __malloc_postfork_unlock__ __malloc_start__ - Модуль mem_functions32.o:
Содержит все необходимые 32-разрядные функции
- Модуль mem_functions64.o:
Содержит все необходимые 64-разрядные функции
- Создание 32-разрядного общего объекта:
ld -b32 -m -o mem32.o mem_functions32.o \ -bE:mem.exp \ -bM:SRE -lpthreads -lc - Создание 64-разрядного общего объекта:
ld -b64 -m -o mem64.o mem_functions64.o \ -bE:mem.exp \ -bM:SRE -lpthreads -lc - Создание архива (32-разрядный общий объект должен называться
mem32.o, а 64-разрядный -
mem64.o):
ar -X32_64 -r архив mem32.o mem64.o
Применение пользовательской подсистемы памяти
- С помощью переменной среды MALLOCTYPE
- С помощью глобальной переменной _malloc_user_defined_name в пользовательском приложении
Для применения переменной среды MALLOCTYPE нужно задать архив, содержащий пользовательскую подсистему памяти, присвоив переменной MALLOCTYPE значение user:имя-архива. При этом имя-архива должно быть указано в параметре libpath приложения или в переменной среды LIBPATH.
char *_malloc_user_defined_name="архив"архив должен быть указан в переменной libpath программы или в переменной среды LIBPATH.
- При выполнении приложения setuid переменная среды LIBPATH игнорируется, поэтому имя архива должно быть определено в параметре libpath приложения.
- Имя-архива не должно содержать информацию о пути.
- Если архив указан и в переменной среды MALLOCTYPE, и в глобальной переменной _malloc_user_defined_name, то будет применяться архив, указанный в переменной MALLOCTYPE.
Информация о 32-разрядных и 64-разрядных функциях
Если архив не содержит и 32-разрядный, и 64-разрядный общий объект, и пользовательская подсистема памяти была подключена с помощью переменной среды MALLOCTYPE, то при выполнении 64-разрядных процессов в 32-разрядных приложениях или 32-разрядных процессов в 64-разрядных приложениях может возникнуть сбой. При вызове функции exec создается новый процесс, который наследует среду родительского приложения. Это означает, что будет унаследована переменная среды MALLOCTYPE, и новый процесс попытается загрузить пользовательскую подсистему памяти. Если в архиве нет объекта для программы данного типа, то подсистема не будет загружена, и работа процесса будет завершена.
Рекомендации по работе с нитями
Все пользовательские функции должны правильно работать в среде с несколькими нитями. Даже если модуль подключен с помощью libpthreads.a, функция __malloc__() должна правильно работать до того, как будет вызвана функция __malloc_init__() и выполнена инициализация библиотеки pthread. Это требование связано с тем, что при инициализации API нитей функция malloc() вызывается раньше, чем функция __malloc_init__().
Все подключаемые функции управления памятью должны поддерживать как приложения с нитями, так и приложения без нитей. Функция __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. Если во время загрузки возникает ошибка, то выводится соответствующее сообщение, и работа приложения завершается. В противном случае проверяется наличие всех необходимых идентификаторов. Если какие-либо идентификаторы отсутствуют, работа приложения завершается, и выводится сообщение со списком недостающих идентификаторов.