**Аннотация:** В этой статье анализируется исходный код алгоритма наилучшего соответствия модуля динамической памяти LiteOS, включая структуру динамической памяти, инициализацию пула динамической памяти, применение динамической памяти, выпуск и т. д.
Эта статья опубликована в сообществе Huawei Cloud Community "Анализ исходного кода ядра LiteOS. Серия 13. Алгоритм оптимального распределения динамической памяти.", автор оригинала: zhushy.
Модуль управления памятью управляет ресурсами памяти системы.Это один из основных модулей операционной системы, в основном включающий инициализацию, выделение и освобождение памяти.
Во время работы системы модуль управления памятью управляет использованием памяти пользователями и ОС посредством приложения/освобождения памяти, чтобы оптимизировать использование и эффективность памяти и максимально решить проблему фрагментации памяти в системе. степень.
Управление памятью Huawei LiteOS разделено на управление статической памятью и управление динамической памятью, предоставляя такие функции, как инициализация, выделение и освобождение памяти.
-
**Динамическая память:** выделение блоков памяти заданного пользователем размера в пуле динамической памяти.
-
Плюсы: Распространяется по требованию.
-
Недостаток: в пуле памяти может произойти фрагментация.
-
**Статическая память:** выделять блоки памяти заданного (фиксированного) размера при инициализации пользователя в пуле статической памяти.
-
Преимущества: высокая эффективность выделения и освобождения, отсутствие фрагментации в пуле статической памяти.
-
Недостатки: Вы можете подать заявку только на блок памяти заданного размера для инициализации и не можете подать заявку на него по требованию.
Проанализировав статическую память в предыдущей серии, приступим к анализу динамической памяти. Динамическое управление памятью в основном используется в сценариях, когда пользователям необходимо использовать блоки памяти разного размера. Когда пользователю нужно использовать память, он может запросить блок памяти определенного размера через функцию приложения динамической памяти операционной системы.После использования занятая память возвращается через функцию динамического освобождения памяти, чтобы ее можно было использовать повторно. .
Динамическая память LiteOS поддерживает два алгоритма управления памятью: bestfit (также известный как dlink) и bestfit_little. В этой статье в основном анализируется алгоритм наилучшего соответствия динамической памяти LiteOS, а в последующих сериях будет продолжен анализ алгоритма наилучшего соответствия динамической памяти.
Эта статья помогает читателям освоить использование динамической памяти, анализируя исходный код модуля динамической памяти LiteOS. Исходный код модуля динамической памяти LiteOS можно найти по адресуLiteOS
сайт с открытым исходным кодомgit ee.com/l IT EOS/lite…Получать. Исходный код и документ разработки алгоритма наилучшего соответствия динамической памяти, пример кода программы выглядит следующим образом:
- Исходный код динамической памяти ядра LiteOS
Включая частный заголовочный файл алгоритма наилучшего соответствия динамической памяти kernel\base\mem\bestfit\los_memory_internal.h, частный заголовочный файл динамической памяти kernel\base\include\los_memory_pri.h, файл заголовка памяти kernel\include\los_memory.h, многосвязный список Файл заголовка kernel\base\include\los_multipledlinkhead_pri.h, файл исходного кода C kernel\base\mem\bestfit\los_memory.c, файл исходного кода C kernel\base\mem\bestfit\los_multipledlinkhead.c.
- Руководство для разработчиков Документация — Память
онлайн-документацияgit ee.com/l IT EOS/lite…
Далее давайте посмотрим на структуру динамической памяти, инициализацию динамической памяти и исходный код общих операций динамической памяти.
1. Определение структуры динамической памяти и определение общего макроса
1.1 Определение структуры динамической памяти
Структура алгоритма наилучшего соответствия динамической памяти включает в себя информационную структуру пула динамической памяти LosMemPoolInfo, структуру заголовка многократно связанного списка LosMultipleDlinkHead, структуру узла связанного списка динамической памяти LosMemDynNode и структуру узла управления связанным списком памяти LosMemCtlNode.
На следующей диаграмме показано использование динамической памяти.Для области динамической памяти первая часть представляет собой информационную структуру пула памяти LosMemPoolInfo, за которой следует вторая часть структуры заголовка двусвязного списка LosMultipleDlinkHead, а третья часть представляет собой динамическую структуру. структура узла связанного списка памяти LosMemDynNode , структура узла управления связным списком памяти LosMemCtlNode. После инициализации с использованием алгоритма наилучшего соответствия динамической памяти третья часть содержит 2 блока памяти, первый блок памяти содержит структуру узла управления связным списком памяти LosMemCtlNode и область данных блока памяти, хвостовой узел содержит только структуру узла управления связным списком памяти LosMemCtlNode, нет области данных. Структура управляющего узла LosMemCtlNode содержит указатель на предыдущий блок памяти. Блоки памяти с областями данных монтируются в связанный список во второй части. При подаче заявки на память, в соответствии с размером требуемой памяти, получить подходящий блок памяти из связанного списка во второй части.Если блок памяти превышает потребность, он будет вырезан, а оставшаяся часть будет объединена с последующие свободные узлы и повторно монтируются во вторую часть связанного списка.
1.1.1 Информационная структура пула динамической памяти LosMemPoolInfo
В файле kernel\base\include\los_memory_pri.h определена информационная структура пула памяти LosMemPoolInfo. Это первая часть динамического пула памяти, в которой хранится информация о начальном адресе и размере пула памяти. Эта структура определена как в алгоритме наилучшего соответствия динамической памяти, так и в алгоритме наилучшего соответствия_little.Имя структуры такое же, но члены разные.Давайте сначала посмотрим на структуру алгоритма наилучшего соответствия.Исходный код выглядит следующим образом. Двумя основными элементами являются начальный адрес пула памяти.pool и размер пула памяти.poolSize. Другие структуры должны открывать соответствующие макросы, чтобы они вступили в силу, и характеристики, связанные с этими макросами, пока не обсуждаются.
typedef struct {
VOID *pool; /* 内存池的内存开始地址 */
UINT32 poolSize; /* 内存池大小 */
#ifdef LOSCFG_MEM_TASK_STAT
Memstat stat;
#endif
#ifdef LOSCFG_MEM_MUL_POOL
VOID *nextPool;
#endif
#ifdef LOSCFG_KERNEL_MEM_SLAB_EXTENTION
struct LosSlabControlHeader slabCtrlHdr;
#endif
} LosMemPoolInfo;
1.1.2 Структура заголовка множественного двусвязного списка LosMultipleDlinkHead
В файле kernel\base\include\los_multipledlinkhead_pri.h определена структура заголовка двусвязного списка пула памяти LosMultipleDlinkHead. Это вторая часть динамического пула памяти, сама структура представляет собой массив, каждый элемент которого представляет собой двусвязный список, а управляющие заголовки всех свободных узлов будут классифицированы и подвешены в двусвязном списке этого массива.
Предполагая, что минимальное количество узлов, разрешенное памятью, равно 2^min байт, первый двусвязный список массива хранит все свободные узлы, размер которых равен 2^min Исходный код структуры выглядит очень просто и представляет собой массив двусвязных списков длиной OS_MULTI_DLNK_NUM. Давайте посмотрим на определения макросов, относящиеся к структуре LosMultipleDlinkHead.OS_MIN_MULTI_DLNK_LOG2 и OS_MAX_MULTI_DLNK_LOG2 определяют доступ к размеру узлов памяти, хранящихся в двусвязном списке.Первый свободный узел памяти с размером хранилища [2^4, 2^5), в свою очередь. По аналогии, 26-й OS_MULTI_DLNK_NUM — это свободный узел памяти, размер хранилища которого равен [2^29, 2^30). Размер памяти, занимаемой структурой заголовка многосвязного списка, равен OS_DLNK_HEAD_SIZE. 1.1.3 Структура узла связанного списка динамической памяти LosMemDynNode и структура узла управления связанным списком LosMemCtlNode В файле kernel\base\mem\bestfit\los_memory_internal.h определены две структуры: структура узла связанного списка динамической памяти LosMemDynNode и структура узла управления связанным списком LosMemCtlNode. Это третья часть пула динамической памяти, которая занимает большую часть пула памяти и является фактической областью, используемой для хранения каждого узла. Причиной создания двух структур является удовлетворение потребностей в резервном копировании узлов списка, связанного с памятью. Видно, что когда макрос LOSCFG_MEM_HEAD_BACKUP узла резервного связанного списка включен, структура LosMemDynNode содержит 2 узла LosMemCtlNode, один — .backupNode, а другой — .selfNode. Исходный код двух структур выглядит следующим образом, а объяснение важных членов находится в разделе комментариев. Файл заголовка динамической памяти kernel\base\mem\bestfit\los_memory_internal.h также содержит некоторые важные определения макросов. Эти макросы очень важны. Вам необходимо ознакомиться с определениями этих макросов, прежде чем анализировать исходный код. (1) OS_MEM_ALIGN(p, alignSize) используется для выравнивания адресов памяти, (2) OS_MEM_NODE_HEAD_SIZE представляет размер узла связанного списка памяти, OS_MEM_MIN_POOL_SIZE представляет минимальный размер пула динамической памяти, включая размер информационной структуры пула памяти, 1 таблица многосвязного списка Размер структуры заголовка и размер двух узлов связанного списка. (3) IS_POW_TWO(значение) определяет, является ли значение степенью числа 2. ⑷ определяет значение выравнивания адреса пула памяти и значение выравнивания узла памяти. ⑸ определяет, следует ли использовать и выравнивать 2 бита маркера, которые являются старшими 31 битами и старшими 30 битами. Затем определите 3 макрофункции соответственно, чтобы узнать, была ли она использована/выровнена, установите метку как использованную/выровненную и получите используемый размер после удаления метки. ⑹ OS_MEM_HEAD_ADDR(pool) представляет собой начальный адрес структуры заголовка многосвязного списка во второй части пула динамической памяти. Макрофункция OS_MEM_HEAD(pool,size) используется для вычисления адреса заголовка многосвязного списка, соответствующего блоку памяти размера size, по сути, это отображение размера блока памяти в третьей части пул памяти в позицию связанного списка во второй части. Функция под названием OsDLnkMultiHead() будет проанализирована позже. ⑺ Определите макросы, связанные с операциями узла памяти. OS_MEM_NEXT_NODE(узел) получает следующий узел памяти узла памяти, OS_MEM_FIRST_NODE(пул) получает первый узел памяти в пуле памяти, OS_MEM_END_NODE(пул, размер) получает последний узел памяти в пуле памяти. ⑻ определяет два макроса, чтобы определить, находится ли адрес памяти в указанном диапазоне, и разница между ними заключается в том, является ли диапазон открытым или закрытым. Два макроса в ⑼ устанавливают волшебное слово и проверку волшебного слова для граничного узла памяти. Давайте посмотрим на функцию OsDLnkMultiHead(), вызываемую в макросе, который определен в файле kernel\base\mem\bestfit\los_multipledlinkhead.c. Эта функция требует 2 параметра, VOID *headAddr — начальный адрес массива многосвязного списка во второй части, а размер UINT32 — размер блока памяти. Эта функция сопоставляет размер блока памяти в третьей части пула памяти с позицией связанного списка во второй части Давайте проанализируем код. Лог в названии функции OsLog2() в (1) — сокращение от logarithm на английском языке Функция используется для вычисления целой части логарифма по основанию 2. Входным параметром является размер блока памяти в третья часть пула памяти, а на выходе — индекс массива второй части массива многосвязного списка, см. фрагмент кода (2). (3) Если индекс больше, чем OS_MAX_MULTI_DLNK_LOG2, такой большой блок памяти не может быть выделен, и возвращается NULL. ⑷ Если индекс меньше или равен OS_MIN_MULTI_DLNK_LOG2, в качестве индекса используется минимальное значение. ⑸ возвращает узел заголовка связанного списка в заголовке многосвязного списка. Модуль управления динамической памятью в системе Huawei LiteOS предоставляет пользователям такие операции, как инициализация и удаление пулов памяти, запрос и освобождение динамической памяти.Проанализируем исходный код интерфейса. Прежде чем анализировать интерфейс работы с памятью, рассмотрим часто используемые внутренние интерфейсы. 2.1.1 Очистить содержимое узла памяти Функция VOID OsMemClearNode(LosMemDynNode *node) используется для очистки содержимого данного узла памяти и установки содержимого данных памяти равным 0. Код относительно прост, и функция memset_s() вызывается непосредственно для завершения операции. 2.1.2 Объединение узлов памяти Функция VOID OsMemMergeNode(LosMemDynNode *node) используется для объединения данного узла LosMemDynNode *node с его предыдущим свободным узлом, а затем очистки содержимого данного узла. (1) Добавьте размер предыдущего узла к размеру объединяемого узла. (2) Получить следующий узел данного узла, а затем указать его предыдущий узел на предыдущий узел данного узла. (3) Очистить содержимое данного узла и завершить объединение узлов. 2.1.3 Разделение узлов памяти Функция VOID OsMemSplitNode(VOID *pool, LosMemDynNode *allocNode, UINT32 allocSize) используется для разделения узлов памяти и требует трех параметров. VOID *pool — начальный адрес пула памяти, LosMemDynNode *allocNode указывает, что необходимая память выделена из узла памяти, а UINT32 allocSize — размер выделяемой памяти. Оставшиеся части после разделения, если следующий узел является свободным узлом, объединяются вместе. Остальные узлы разбиения будут смонтированы в многосвязном списке во второй части памяти. (1) Получить первый узел управления памятью динамического пула памяти, (2) указывает, что newFreeNode является оставшимся узлом свободной памяти после выделения, устанавливает его предыдущий узел в качестве выделенного узла и устанавливает оставшийся размер памяти. (3) Получить следующий узел, и предыдущий узел следующего узла устанавливается как новый свободный узел newFreeNode. В ⑷ оцените, используется ли следующий узел, если нет, удалите следующий узел из связанного списка, а затем объедините его со свободным узлом newFreeNode. В ⑸ получите соответствующий головной узел связанного списка в соответствии с размером свободного узла newFreeNode, а затем выполните ⑹, чтобы смонтировать свободный узел памяти в связанном списке. 2.1.4 Повторно подать заявку на память Функция OsMemReAllocSmaller() используется для повторного применения меньшей памяти из большого блока памяти.Ей необходимы четыре параметра: LosMemPoolInfo *pool — начальный адрес пула памяти, UINT32 allocSize — размер повторно примененного memory, LosMemDynNode *node — это узел памяти, которому в данный момент необходимо перераспределить память, а UINT32 nodeSize — это размер текущего узла. (1) Установите для узла памяти selfNode.sizeAndFlag фактический размер после удаления метки (2) Разделите узел по мере необходимости (3) Установите используемую метку для разделенного узла и завершите заявку на память. 2.1.5 Узел слияния повторно обращается за памятью Наконец, давайте посмотрим на функциональную функцию OsMemMergeNodeForReAllocBigger(), которая используется для объединения узлов памяти и перераспределения большего объема памяти. Требуется 5 параметров, LosMemPoolInfo *pool — начальный адрес пула памяти, UINT32 allocSize — размер повторно примененной памяти, LosMemDynNode *node — узел памяти, которому в данный момент необходимо перераспределить память, UINT32 nodeSize — размер текущий узел, LosMemDynNode *nextNode — следующий узел памяти. (1) Получить первый узел памяти в пуле памяти, (2) установить для узла памяти selfNode.sizeAndFlag фактический размер после снятия метки, (3) удалить следующий узел из связанного списка, а затем объединить узлы. В ⑷, если размер объединенного узла превышает размер, который необходимо перераспределить, узел разделяется. Давайте проанализируем код для инициализации функции динамического пула памяти UINT32 LOS_MemInit(VOID *pool, размер UINT32). Давайте сначала посмотрим на параметры функции, VOID *pool — это начальный адрес пула динамической памяти, размер UINT32 — это общий размер инициализированного пула динамической памяти, и размер должен быть меньше или равен размеру памяти. область, начинающаяся с *pool, иначе это повлияет на следующую память. Область также должна быть больше, чем минимальный OS_MEM_MIN_POOL_SIZE динамического пула памяти. [пул, пул + размер] не может конфликтовать с другими пулами памяти. Давайте посмотрим на код ⑴ Проверьте входящие параметры Входящие параметры требуют выравнивания памяти. (2) Макрос LOSCFG_MEM_MUL_POOL будет выполняться только в том случае, если включен макрос пула с несколькими памятью. (3) Функция OsMemInit() вызывается для инициализации пула памяти, которая является основной функцией инициализируемой памяти. Он будет выполняться только тогда, когда поддержка макроса LOSCFG_KERNEL_MEM_SLAB_EXTENTION включена в ⑷. Продолжим рассмотрение функции OsMemInit(). (1) Установите начальный адрес и размер информационной структуры пула динамической памяти LosMemPoolInfo. (2) Инициализировать структуру заголовка двусвязного списка LosMultipleDlinkHead второй части. (3) Получить первый узел управления памятью пула памяти, а затем установить его размер в (poolSize - (UINT32)((UINTPTR)newNode - (UINTPTR)pool) - OS_MEM_NODE_HEAD_SIZE), размер этого узла равен третья часть минус одна Память управляет размером узла. Затем установите предыдущий узел узла памяти в качестве последнего узла пула памяти OS_MEM_END_NODE(pool, poolSize). В ⑷ головной узел listNodeHead многосвязного списка получается в соответствии с размером первого узла памяти, а затем узел памяти вставляется в двусвязный список. Получите хвостовой узел пула памяти в ⑸, очистите содержимое, а затем установите его размер и предыдущий узел, а также установите используемый флаг. В ⑹ установите волшебное слово для не-узла и укажите идентификатор задачи, которая использует блок памяти. Если макросы отладки LOSCFG_MEM_TASK_STAT и LOSCFG_MEM_HEAD_BACKUP включены, то будут еще какие-то операции, их вы можете прочитать сами. После инициализации пула динамической памяти мы можем использовать функцию VOID *LOS_MemAlloc(VOID *pool, размер UINT32) для применения динамической памяти и проанализировать приведенный ниже исходный код. Проверьте параметры в (1), адрес пула памяти не может быть пустым, а запрошенный размер памяти не может быть равен 0. (2) Определите, был ли запрошенный объем памяти помечен как использованный или выровненный. Назначьте следующий доступный узел для nodeTmp. (3) Если SLAB поддерживается, попробуйте сначала получить память из SLAB, в противном случае выполните (4), чтобы вызвать функцию OsMemAllocWithCheck(pool, size) для применения к блоку памяти. Продолжаем анализировать функцию OsMemAllocWithCheck(pool, size). (1) Получить первый узел памяти в пуле памяти, (2) Рассчитать размер памяти после выравнивания, а затем вызвать функцию OsMemFindSuitableFreeBlock() для получения подходящего блока памяти.Если подходящий блок памяти не найден, функция возвращает NULL . (3) Если найденный блок памяти больше требуемого размера памяти, выполняется операция разделения. В ⑷ удалите выделенный узел памяти из связанного списка, затем установите волшебное слово и идентификатор задачи, которая использует блок памяти, а затем пометьте блок памяти как используемый. ⑸ Если макрос LOSCFG_MEM_TASK_STAT включен, вам необходимо выполнить некоторые операции записи и проанализировать его самостоятельно. ⑹ возвращает адрес области данных блока памяти, что реализуется путем размещения узла управления памятью +1 по адресу памяти области данных. Приложение памяти завершено, и запрошенная память может быть использована в функции, которая вызывает память приложения. Мы также можем использовать функцию VOID *LOS_MemAllocAlign(VOID *pool, размер UINT32, граница UINT32) для обращения к памяти с длиной size и адресом, выровненным по граничным байтам из указанного пула динамической памяти. Для этой функции требуется 3 параметра: VOID *pool — это начальный адрес пула памяти, размер UINT32 — это размер памяти, к которому нужно примениться, и значение выравнивания границ памяти UINT32. Когда адрес памяти VOID *ptr получен после подачи заявки на память, выровненный адрес памяти равен VOID *alignedPtr, а значение смещения двух сохраняется с использованием UINT32 gapSize. Поскольку память выравнивается в соответствии с OS_MEM_ALIGN_SIZE, максимальное значение смещения является граничным — OS_MEM_ALIGN_SIZE. Проанализируйте исходный код ниже. Проверьте параметры в (1), адрес пула памяти не может быть пустым, запрошенный размер памяти не может быть равен 0, граница байта выравнивания не может быть равна 0, и она должна быть степенью 2. (2) Проверьте, не будет ли переполнения данных после выравнивания памяти. (3) Рассчитайте размер памяти, который необходимо применить после выравнивания, а затем оцените, что значение размера памяти не имеет использованных или выровненных меток. ⑷ Вызовите функцию для применения к памяти VOID *ptr, а затем вычислите выровненный адрес памяти VOID *alignedPtr и верните, если они равны. В ⑸ вычисляется значение смещения выровненной памяти, а в ⑹ получается контрольный узел примененной памяти и устанавливается выровненная метка. ⑺ Установите метку выравнивания на значение смещения, а затем сохраните значение смещения в первых 4 байтах памяти VOID *alignedPtr. В ⑻ перенаправьте возвращаемый указатель, чтобы завершить приложение для выровненной памяти. После использования запрошенного блока памяти мы можем использовать функцию UINT32 LOS_MemFree(VOID *pool, VOID *ptr) для освобождения динамической памяти, для чего требуются 2 параметра: VOID *pool — это адрес инициализированного пула динамической памяти. VOID *ptr — начальный адрес области данных освобождаемого блока динамической памяти.Обратите внимание, что это не адрес узла управления памятью. Проанализируйте исходный код ниже. ⑴ Сначала проверьте входящие параметры. (2) Если память представляет собой память, применяемую из SLAB, ее необходимо освободить в область памяти SLAB. ⑶ вызвать функцию OsMemFree (pool, ptr) для завершения освобождения памяти. Продолжаем анализировать функцию OsMemFree(pool, ptr). (1) Получить на месте gapSize.Для памяти, применяемой функцией LOS_MemAlloc(), gapSize соответствует переменной-члену sizeAndFlag управляющего узла LosMemCtlNode, для памяти, применяемой функцией LOS_MemAllocAlign(), gapSize соответствует значение смещения выравнивания памяти. В первом случае используется только метка, во втором случае выравнивается только метка. ⑵ указывает, что если и метка используется, и метка выровнена, будет возвращена ошибка. Получение узла управления памятью в (3) неверно для второго случая. ⑷ Второй случай калибровки кода, если gapSize помечен как выровненный, удалите метку выравнивания в gapSize, чтобы получить значение смещения. Проверьте значение смещения в ⑸, а затем выполните ⑹ Get, чтобы получить узел управления памятью. ⑺ далее вызовите функцию, чтобы завершить освобождение памяти. Продолжим рассмотрение функции OsDoMemFree(), которая далее вызывает функцию OsMemFreeNode(node, pool) для завершения освобождения памяти. Функция OsMemFreeNode(node, pool) выглядит следующим образом, продолжаем анализ. Первый узел управления памятью пула динамической памяти получается в (1), а использованный флаг снимается в (2). (3) Предыдущий узел не пуст и не используется. Выполните объединение узлов памяти в ⑷, а затем получите следующий узел nextNode.Если следующий узел также является неиспользуемым узлом, удалите следующий узел из связанного списка и объедините неиспользуемые узлы. В ⑸ удалите предыдущий узел из связанного списка и перемонтируйте его в связанный список в зависимости от размера объединенного узла памяти. Если предыдущий узел был использован и не может быть объединен с предыдущим узлом, выполните ⑹, чтобы получить следующий узел. Если следующий узел также является неиспользуемым узлом, удалите следующий узел из связанного списка и объедините свободные узлы. ⑺ Получите узел связанного списка в соответствии с размером узла памяти, а затем подключите освобожденный узел памяти к связанному списку, чтобы завершить освобождение узла памяти. Мы также можем использовать функцию VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, размер UINT32) для перераспределения блока памяти в соответствии с размером и копирования содержимого исходного блока памяти в новый блок памяти. Если применение нового блока памяти прошло успешно, исходный блок памяти освобождается. Эта функция требует 3 параметра: VOID *pool — это начальный адрес пула памяти, VOID *ptr — ранее примененный адрес памяти, а размер UINT32 — повторно примененный размер памяти. Проанализируйте исходный код ниже. ⑴ Проверьте параметры, адрес пула памяти не может быть пустым, а размер памяти не может содержать использованные или выровненные метки. (2) Если входящий адрес памяти пуст, это эквивалентно функции LOS_MemAlloc(). (3) Если входящий размер равен 0, это эквивалентно функции LOS_MemFree(). ⑷ Если включена поддержка SLAB, вам нужно вызвать функцию OsMemReallocSlab(), чтобы повторно подать заявку на память SLAB. ⑸ вызовите функцию OsMemRealloc (), чтобы повторно подать заявку на память. Посмотрите дальше на функцию OsMemRealloc(). (1) Получить размер allocSize после выравнивания памяти, (2) Получить адрес до выравнивания памяти, функция OsGetRealPtr() будет проанализирована позже. (3) Получите узел узла управления памятью, а затем получите размер nodeSize узла. ⑷ Чтобы справиться с ситуацией, когда повторно примененная память меньше или равна существующей памяти, вам нужно вызвать функцию OsMemReAllocSmaller() для разделения и вернуть (VOID *)ptr после разделения. Если вы повторно подаете заявку на больший объем памяти, выполните (5), чтобы получить следующий узел, а затем (6) обработайте, что следующий узел доступен, а сумма размера двух узлов больше или равна размеру allocSize вновь примененной памяти. Выполните функцию в ⑺, объедините узлы, чтобы перераспределить память. Если размер последовательных узлов не соответствует размеру повторно применяемой памяти, выполните функцию ⑻, чтобы повторно применить память. Затем выполните ⑼, чтобы скопировать данные из предыдущей памяти во вновь примененную область памяти.Если копирование не удается, вновь примененная память освобождается, и возвращается функция выхода. Если репликация прошла успешно, продолжайте выполнять ⑽, чтобы освободить предыдущий узел. Вернемся назад и продолжим рассмотрение функции OsGetRealPtr(). (1) Получить значение смещения для выравнивания памяти. (2) Если значение смещения помечено как используемое и выровнено одновременно, возвращается ошибка. (3) Если значение смещения помечено как выровненное, выполните (4), чтобы удалить метку совмещения и получить простое значение смещения. Затем выполните ⑸, чтобы получить адрес памяти области данных до выравнивания памяти. В этой статье вы проанализируете исходный код алгоритма наилучшего соответствия модуля динамической памяти LiteOS, включая структуру динамической памяти, инициализацию пула динамической памяти, применение динамической памяти, выпуск и т. д. Спасибо за прочтение. Если у вас есть какие-либо вопросы или предложения, вы можете оставить нам сообщение: git ee.com/l IT EOS/lite…. чтобы легче было найти Нажмите «Подписаться», чтобы впервые узнать о новых технологиях HUAWEI CLOUD~typedef struct {
LOS_DL_LIST listHead[OS_MULTI_DLNK_NUM];
} LosMultipleDlinkHead;
#define OS_MAX_MULTI_DLNK_LOG2 29
#define OS_MIN_MULTI_DLNK_LOG2 4
#define OS_MULTI_DLNK_NUM ((OS_MAX_MULTI_DLNK_LOG2 - OS_MIN_MULTI_DLNK_LOG2) + 1)
#define OS_DLNK_HEAD_SIZE OS_MULTI_DLNK_HEAD_SIZE
#define OS_MULTI_DLNK_HEAD_SIZE sizeof(LosMultipleDlinkHead)
/* 内存链表控制节点结构体 */
typedef struct {
union {
LOS_DL_LIST freeNodeInfo; /* 空闲内存链表节点 */
struct {
UINT32 magic; /* 魔术字 */
UINT32 taskId : 16; /* 使用内存的任务Id */
#ifdef LOSCFG_MEM_MUL_MODULE
UINT32 moduleId : 16;
#endif
};
};
struct tagLosMemDynNode *preNode; /* 指针,指针前一个内存节点 */
#ifdef LOSCFG_MEM_HEAD_BACKUP
UINT32 gapSize;
UINTPTR checksum; /* magic = xor checksum */
#endif
#ifdef LOSCFG_MEM_RECORDINFO
UINT32 originSize;
#ifdef LOSCFG_AARCH64
UINT32 reserve1; /* 64-bit alignment */
#endif
#endif
#ifdef LOSCFG_MEM_LEAKCHECK
UINTPTR linkReg[LOS_RECORD_LR_CNT];
#endif
#ifdef LOSCFG_AARCH64
UINT32 reserve2; /* 64-bit alignment */
#endif
UINT32 sizeAndFlag; /* 大小和标志,高2位用作标记,其余位表示大小 */
} LosMemCtlNode;
/* 内存链表节点结构体 */
typedef struct tagLosMemDynNode {
#ifdef LOSCFG_MEM_HEAD_BACKUP
LosMemCtlNode backupNode;
#endif
LosMemCtlNode selfNode;
} LosMemDynNode;
1.2 Общие макроопределения динамической памяти
⑴ #define OS_MEM_ALIGN(p, alignSize) (((UINTPTR)(p) + (alignSize) - 1) & ~((UINTPTR)((alignSize) - 1)))
⑵ #define OS_MEM_NODE_HEAD_SIZE sizeof(LosMemDynNode)
#define OS_MEM_MIN_POOL_SIZE (OS_DLNK_HEAD_SIZE + (2 * OS_MEM_NODE_HEAD_SIZE) + sizeof(LosMemPoolInfo))
⑶ #define IS_POW_TWO(value) ((((UINTPTR)(value)) & ((UINTPTR)(value) - 1)) == 0)
⑷ #define POOL_ADDR_ALIGNSIZE 64
#ifdef LOSCFG_AARCH64
#define OS_MEM_ALIGN_SIZE 8
#else
#define OS_MEM_ALIGN_SIZE 4
#endif
⑸ #define OS_MEM_NODE_USED_FLAG 0x80000000U
#define OS_MEM_NODE_ALIGNED_FLAG 0x40000000U
#define OS_MEM_NODE_ALIGNED_AND_USED_FLAG (OS_MEM_NODE_USED_FLAG | OS_MEM_NODE_ALIGNED_FLAG)
#define OS_MEM_NODE_GET_ALIGNED_FLAG(sizeAndFlag) \
((sizeAndFlag) & OS_MEM_NODE_ALIGNED_FLAG)
#define OS_MEM_NODE_SET_ALIGNED_FLAG(sizeAndFlag) \
((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_ALIGNED_FLAG))
#define OS_MEM_NODE_GET_ALIGNED_GAPSIZE(sizeAndFlag) \
((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_FLAG)
#define OS_MEM_NODE_GET_USED_FLAG(sizeAndFlag) \
((sizeAndFlag) & OS_MEM_NODE_USED_FLAG)
#define OS_MEM_NODE_SET_USED_FLAG(sizeAndFlag) \
((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_USED_FLAG))
#define OS_MEM_NODE_GET_SIZE(sizeAndFlag) \
((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_AND_USED_FLAG)
⑹ #define OS_MEM_HEAD(pool, size) \
OsDLnkMultiHead(OS_MEM_HEAD_ADDR(pool), size)
#define OS_MEM_HEAD_ADDR(pool) \
((VOID *)((UINTPTR)(pool) + sizeof(LosMemPoolInfo)))
⑺ #define OS_MEM_NEXT_NODE(node) \
((LosMemDynNode *)(VOID *)((UINT8 *)(node) + OS_MEM_NODE_GET_SIZE((node)->selfNode.sizeAndFlag)))
#define OS_MEM_FIRST_NODE(pool) \
((LosMemDynNode *)(VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE))
#define OS_MEM_END_NODE(pool, size) \
((LosMemDynNode *)(VOID *)(((UINT8 *)(pool) + (size)) - OS_MEM_NODE_HEAD_SIZE))
⑻ #define OS_MEM_MIDDLE_ADDR_OPEN_END(startAddr, middleAddr, endAddr) \
(((UINT8 *)(startAddr) <= (UINT8 *)(middleAddr)) && ((UINT8 *)(middleAddr) < (UINT8 *)(endAddr)))
#define OS_MEM_MIDDLE_ADDR(startAddr, middleAddr, endAddr) \
(((UINT8 *)(startAddr) <= (UINT8 *)(middleAddr)) && ((UINT8 *)(middleAddr) <= (UINT8 *)(endAddr)))
⑼ #define OS_MEM_SET_MAGIC(value) \
(value) = (UINT32)((UINTPTR)&(value) ^ (UINTPTR)(-1))
#define OS_MEM_MAGIC_VALID(value) \
(((UINTPTR)(value) ^ (UINTPTR)&(value)) == (UINTPTR)(-1))
STATIC INLINE UINT32 OsLog2(UINT32 size)
{
⑴ return (size > 0) ? (UINT32)LOS_HighBitGet(size) : 0;
}
LITE_OS_SEC_TEXT_MINOR LOS_DL_LIST *OsDLnkMultiHead(VOID *headAddr, UINT32 size)
{
LosMultipleDlinkHead *dlinkHead = (LosMultipleDlinkHead *)headAddr;
⑵ UINT32 index = OsLog2(size);
if (index > OS_MAX_MULTI_DLNK_LOG2) {
⑶ return NULL;
} else if (index <= OS_MIN_MULTI_DLNK_LOG2) {
⑷ index = OS_MIN_MULTI_DLNK_LOG2;
}
⑸ return dlinkHead->listHead + (index - OS_MIN_MULTI_DLNK_LOG2);
}
2. Общие операции с динамической памятью
2.1 Внутренний интерфейс динамической памяти
STATIC INLINE VOID OsMemClearNode(LosMemDynNode *node)
{
(VOID)memset_s((VOID *)node, sizeof(LosMemDynNode), 0, sizeof(LosMemDynNode));
}
STATIC INLINE VOID OsMemMergeNode(LosMemDynNode *node)
{
LosMemDynNode *nextNode = NULL;
⑴ node->selfNode.preNode->selfNode.sizeAndFlag += node->selfNode.sizeAndFlag;
⑵ nextNode = (LosMemDynNode *)((UINTPTR)node + node->selfNode.sizeAndFlag);
nextNode->selfNode.preNode = node->selfNode.preNode;
#ifdef LOSCFG_MEM_HEAD_BACKUP
OsMemNodeSave(node->selfNode.preNode);
OsMemNodeSave(nextNode);
#endif
⑶ OsMemClearNode(node);
}
STATIC INLINE VOID OsMemSplitNode(VOID *pool,
LosMemDynNode *allocNode, UINT32 allocSize)
{
LosMemDynNode *newFreeNode = NULL;
LosMemDynNode *nextNode = NULL;
LOS_DL_LIST *listNodeHead = NULL;
⑴ const VOID *firstNode = (const VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE);
⑵ newFreeNode = (LosMemDynNode *)(VOID *)((UINT8 *)allocNode + allocSize);
newFreeNode->selfNode.preNode = allocNode;
newFreeNode->selfNode.sizeAndFlag = allocNode->selfNode.sizeAndFlag - allocSize;
allocNode->selfNode.sizeAndFlag = allocSize;
⑶ nextNode = OS_MEM_NEXT_NODE(newFreeNode);
nextNode->selfNode.preNode = newFreeNode;
⑷ if (!OS_MEM_NODE_GET_USED_FLAG(nextNode->selfNode.sizeAndFlag)) {
OsMemListDelete(&nextNode->selfNode.freeNodeInfo, firstNode);
OsMemMergeNode(nextNode);
}
#ifdef LOSCFG_MEM_HEAD_BACKUP
else {
OsMemNodeSave(nextNode);
}
#endif
⑸ listNodeHead = OS_MEM_HEAD(pool, newFreeNode->selfNode.sizeAndFlag);
OS_CHECK_NULL_RETURN(listNodeHead);
⑹ OsMemListAdd(listNodeHead, &newFreeNode->selfNode.freeNodeInfo, firstNode);
#ifdef LOSCFG_MEM_HEAD_BACKUP
OsMemNodeSave(newFreeNode);
#endif
}
STATIC INLINE VOID OsMemReAllocSmaller(LosMemPoolInfo *pool, UINT32 allocSize, LosMemDynNode *node, UINT32 nodeSize)
{
if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_ALIGN_SIZE) <= nodeSize) {
⑴ node->selfNode.sizeAndFlag = nodeSize;
⑵ OsMemSplitNode(pool, node, allocSize);
⑶ OS_MEM_NODE_SET_USED_FLAG(node->selfNode.sizeAndFlag);
#ifdef LOSCFG_MEM_HEAD_BACKUP
OsMemNodeSave(node);
#endif
OS_MEM_REDUCE_USED(&pool->stat, nodeSize - allocSize, OS_MEM_TASKID_GET(node));
}
#ifdef LOSCFG_MEM_LEAKCHECK
OsMemLinkRegisterRecord(node);
#endif
}
STATIC INLINE VOID OsMemMergeNodeForReAllocBigger(LosMemPoolInfo *pool, UINT32 allocSize, LosMemDynNode *node,
UINT32 nodeSize, LosMemDynNode *nextNode)
{
⑴ const VOID *firstNode = (const VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE);
⑵ node->selfNode.sizeAndFlag = nodeSize;
⑶ OsMemListDelete(&nextNode->selfNode.freeNodeInfo, firstNode);
OsMemMergeNode(nextNode);
if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_ALIGN_SIZE) <= node->selfNode.sizeAndFlag) {
⑷ OsMemSplitNode(pool, node, allocSize);
}
OS_MEM_ADD_USED(&pool->stat, node->selfNode.sizeAndFlag - nodeSize, OS_MEM_TASKID_GET(node));
OS_MEM_NODE_SET_USED_FLAG(node->selfNode.sizeAndFlag);
#ifdef LOSCFG_MEM_HEAD_BACKUP
OsMemNodeSave(node);
#endif
#ifdef LOSCFG_MEM_LEAKCHECK
OsMemLinkRegisterRecord(node);
#endif
}
2.2 Инициализация пула динамической памяти
LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemInit(VOID *pool, UINT32 size)
{
UINT32 intSave;
⑴ if ((pool == NULL) || (size < OS_MEM_MIN_POOL_SIZE)) {
return LOS_NOK;
}
if (!IS_ALIGNED(size, OS_MEM_ALIGN_SIZE) || !IS_ALIGNED(pool, OS_MEM_ALIGN_SIZE)) {
PRINT_WARN("pool [%p, %p) size 0x%x should be aligned with OS_MEM_ALIGN_SIZE\n",
pool, (UINTPTR)pool + size, size);
size = OS_MEM_ALIGN(size, OS_MEM_ALIGN_SIZE) - OS_MEM_ALIGN_SIZE;
}
MEM_LOCK(intSave);
⑵ if (OsMemMulPoolInit(pool, size)) {
MEM_UNLOCK(intSave);
return LOS_NOK;
}
⑶ if (OsMemInit(pool, size) != LOS_OK) {
(VOID)OsMemMulPoolDeinit(pool);
MEM_UNLOCK(intSave);
return LOS_NOK;
}
⑷ OsSlabMemInit(pool, size);
MEM_UNLOCK(intSave);
LOS_TRACE(MEM_INFO_REQ, pool);
return LOS_OK;
}
STATIC UINT32 OsMemInit(VOID *pool, UINT32 size)
{
LosMemPoolInfo *poolInfo = (LosMemPoolInfo *)pool;
LosMemDynNode *newNode = NULL;
LosMemDynNode *endNode = NULL;
LOS_DL_LIST *listNodeHead = NULL;
UINT32 poolSize = OsLmsMemInit(pool, size);
if (poolSize == 0) {
poolSize = size;
}
⑴ poolInfo->pool = pool;
poolInfo->poolSize = poolSize;
⑵ OsDLnkInitMultiHead(OS_MEM_HEAD_ADDR(pool));
⑶ newNode = OS_MEM_FIRST_NODE(pool);
newNode->selfNode.sizeAndFlag = (poolSize - (UINT32)((UINTPTR)newNode - (UINTPTR)pool) - OS_MEM_NODE_HEAD_SIZE);
newNode->selfNode.preNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, poolSize);
⑷ listNodeHead = OS_MEM_HEAD(pool, newNode->selfNode.sizeAndFlag);
if (listNodeHead == NULL) {
return LOS_NOK;
}
LOS_ListTailInsert(listNodeHead, &(newNode->selfNode.freeNodeInfo));
⑸ endNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, poolSize);
(VOID)memset_s(endNode, sizeof(*endNode), 0, sizeof(*endNode));
endNode->selfNode.preNode = newNode;
endNode->selfNode.sizeAndFlag = OS_MEM_NODE_HEAD_SIZE;
OS_MEM_NODE_SET_USED_FLAG(endNode->selfNode.sizeAndFlag);
⑹ OsMemSetMagicNumAndTaskID(endNode);
#ifdef LOSCFG_MEM_TASK_STAT
UINT32 statSize = sizeof(poolInfo->stat);
(VOID)memset_s(&poolInfo->stat, statSize, 0, statSize);
poolInfo->stat.memTotalUsed = sizeof(LosMemPoolInfo) + OS_MULTI_DLNK_HEAD_SIZE +
OS_MEM_NODE_GET_SIZE(endNode->selfNode.sizeAndFlag);
poolInfo->stat.memTotalPeak = poolInfo->stat.memTotalUsed;
#endif
#ifdef LOSCFG_MEM_HEAD_BACKUP
OsMemNodeSave(newNode);
OsMemNodeSave(endNode);
#endif
return LOS_OK;
}
2.3 Подать заявку на динамическую память
LITE_OS_SEC_TEXT VOID *LOS_MemAlloc(VOID *pool, UINT32 size)
{
VOID *ptr = NULL;
UINT32 intSave;
⑴ if ((pool == NULL) || (size == 0)) {
return NULL;
}
if (g_MALLOC_HOOK != NULL) {
g_MALLOC_HOOK();
}
MEM_LOCK(intSave);
do {
⑵ if (OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size)) {
break;
}
⑶ ptr = OsSlabMemAlloc(pool, size);
if (ptr == NULL) {
⑷ ptr = OsMemAllocWithCheck(pool, size);
}
} while (0);
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordMalloc(ptr, size);
#endif
OsLmsSetAfterMalloc(ptr);
MEM_UNLOCK(intSave);
LOS_TRACE(MEM_ALLOC, pool, (UINTPTR)ptr, size);
return ptr;
}
STATIC VOID *OsMemAllocWithCheck(LosMemPoolInfo *pool, UINT32 size)
{
LosMemDynNode *allocNode = NULL;
UINT32 allocSize;
#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK
LosMemDynNode *tmpNode = NULL;
LosMemDynNode *preNode = NULL;
#endif
⑴ const VOID *firstNode = (const VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE);
#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK
if (OsMemIntegrityCheck(pool, &tmpNode, &preNode)) {
OsMemIntegrityCheckError(tmpNode, preNode);
return NULL;
}
#endif
⑵ allocSize = OS_MEM_ALIGN(size + OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE);
allocNode = OsMemFindSuitableFreeBlock(pool, allocSize);
if (allocNode == NULL) {
OsMemInfoAlert(pool, allocSize);
return NULL;
}
⑶ if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_ALIGN_SIZE) <= allocNode->selfNode.sizeAndFlag) {
OsMemSplitNode(pool, allocNode, allocSize);
}
⑷ OsMemListDelete(&allocNode->selfNode.freeNodeInfo, firstNode);
OsMemSetMagicNumAndTaskID(allocNode);
OS_MEM_NODE_SET_USED_FLAG(allocNode->selfNode.sizeAndFlag);
⑸ OS_MEM_ADD_USED(&pool->stat, OS_MEM_NODE_GET_SIZE(allocNode->selfNode.sizeAndFlag),
OS_MEM_TASKID_GET(allocNode));
OsMemNodeDebugOperate(pool, allocNode, size);
⑹ return (allocNode + 1);
}
2.4 Подать заявку на динамическую память в соответствии с указанным выравниванием байтов
LITE_OS_SEC_TEXT VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
{
UINT32 useSize;
UINT32 gapSize;
VOID *ptr = NULL;
VOID *alignedPtr = NULL;
LosMemDynNode *allocNode = NULL;
UINT32 intSave;
⑴ if ((pool == NULL) || (size == 0) || (boundary == 0) || !IS_POW_TWO(boundary) ||
!IS_ALIGNED(boundary, sizeof(VOID *))) {
return NULL;
}
MEM_LOCK(intSave);
do {
⑵ if ((boundary - sizeof(gapSize)) > ((UINT32)(-1) - size)) {
break;
}
⑶ useSize = (size + boundary) - sizeof(gapSize);
if (OS_MEM_NODE_GET_USED_FLAG(useSize) || OS_MEM_NODE_GET_ALIGNED_FLAG(useSize)) {
break;
}
⑷ ptr = OsMemAllocWithCheck(pool, useSize);
alignedPtr = (VOID *)OS_MEM_ALIGN(ptr, boundary);
if (ptr == alignedPtr) {
break;
}
⑸ gapSize = (UINT32)((UINTPTR)alignedPtr - (UINTPTR)ptr);
⑹ allocNode = (LosMemDynNode *)ptr - 1;
OS_MEM_NODE_SET_ALIGNED_FLAG(allocNode->selfNode.sizeAndFlag);
#ifdef LOSCFG_MEM_RECORDINFO
allocNode->selfNode.originSize = size;
#endif
#ifdef LOSCFG_MEM_HEAD_BACKUP
OsMemNodeSaveWithGapSize(allocNode, gapSize);
#endif
⑺ OS_MEM_NODE_SET_ALIGNED_FLAG(gapSize);
*(UINT32 *)((UINTPTR)alignedPtr - sizeof(gapSize)) = gapSize;
⑻ ptr = alignedPtr;
} while (0);
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordMalloc(ptr, size);
#endif
OsLmsSetAfterMalloc(ptr);
MEM_UNLOCK(intSave);
LOS_TRACE(MEM_ALLOC_ALIGN, pool, (UINTPTR)ptr, size, boundary);
return ptr;
}
2.5 Освобождение динамической памяти
LITE_OS_SEC_TEXT UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
{
UINT32 ret;
UINT32 intSave;
⑴ if ((pool == NULL) || (ptr == NULL) ||
!IS_ALIGNED(pool, sizeof(VOID *)) || !IS_ALIGNED(ptr, sizeof(VOID *))) {
return LOS_NOK;
}
MEM_LOCK(intSave);
⑵ if (OsSlabMemFree(pool, ptr)) {
ret = LOS_OK;
goto OUT;
}
⑶ ret = OsMemFree(pool, ptr);
OUT:
OsLmsSetAfterFree(ptr);
MEM_UNLOCK(intSave);
LOS_TRACE(MEM_FREE, pool, (UINTPTR)ptr);
return ret;
}
UINT32 OsMemFree(VOID *pool, VOID *ptr)
{
UINT32 ret = LOS_NOK;
UINT32 gapSize;
LosMemDynNode *node = NULL;
do {
⑴ gapSize = *(UINT32 *)((UINTPTR)ptr - sizeof(UINT32));
⑵ if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize) && OS_MEM_NODE_GET_USED_FLAG(gapSize)) {
PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize);
goto OUT;
}
⑶ node = (LosMemDynNode *)((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE);
⑷ if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize)) {
gapSize = OS_MEM_NODE_GET_ALIGNED_GAPSIZE(gapSize);
⑸ if ((gapSize & (OS_MEM_ALIGN_SIZE - 1)) || (gapSize > ((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE))) {
PRINT_ERR("illegal gapSize: 0x%x\n", gapSize);
break;
}
⑹ node = (LosMemDynNode *)((UINTPTR)ptr - gapSize - OS_MEM_NODE_HEAD_SIZE);
}
#ifndef LOSCFG_MEM_HEAD_BACKUP
⑺ ret = OsDoMemFree(pool, ptr, node);
#endif
} while (0);
#ifdef LOSCFG_MEM_HEAD_BACKUP
ret = OsMemBackupCheckAndRetore(pool, ptr, node);
if (!ret) {
ret = OsDoMemFree(pool, ptr, node);
}
#endif
OUT:
#ifdef LOSCFG_MEM_RECORDINFO
if (ret == LOS_NOK) {
OsMemRecordFree(ptr, 0);
}
#endif
return ret;
}
LITE_OS_SEC_TEXT STATIC INLINE UINT32 OsDoMemFree(VOID *pool, const VOID *ptr, LosMemDynNode *node)
{
UINT32 ret = OsMemCheckUsedNode(pool, node);
if (ret == LOS_OK) {
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordFree(ptr, node->selfNode.originSize);
#endif
OsMemFreeNode(node, pool);
}
return ret;
}
STATIC INLINE VOID OsMemFreeNode(LosMemDynNode *node, LosMemPoolInfo *pool)
{
LosMemDynNode *nextNode = NULL;
LOS_DL_LIST *listNodeHead = NULL;
⑴ const VOID *firstNode = (const VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE);
OS_MEM_REDUCE_USED(&pool->stat, OS_MEM_NODE_GET_SIZE(node->selfNode.sizeAndFlag), OS_MEM_TASKID_GET(node));
⑵ node->selfNode.sizeAndFlag = OS_MEM_NODE_GET_SIZE(node->selfNode.sizeAndFlag);
#ifdef LOSCFG_MEM_HEAD_BACKUP
OsMemNodeSave(node);
#endif
#ifdef LOSCFG_MEM_LEAKCHECK
OsMemLinkRegisterRecord(node);
#endif
⑶ if ((node->selfNode.preNode != NULL) &&
!OS_MEM_NODE_GET_USED_FLAG(node->selfNode.preNode->selfNode.sizeAndFlag)) {
LosMemDynNode *preNode = node->selfNode.preNode;
⑷ OsMemMergeNode(node);
nextNode = OS_MEM_NEXT_NODE(preNode);
if (!OS_MEM_NODE_GET_USED_FLAG(nextNode->selfNode.sizeAndFlag)) {
OsMemListDelete(&nextNode->selfNode.freeNodeInfo, firstNode);
OsMemMergeNode(nextNode);
}
⑸ OsMemListDelete(&(preNode->selfNode.freeNodeInfo), firstNode);
listNodeHead = OS_MEM_HEAD(pool, preNode->selfNode.sizeAndFlag);
OS_CHECK_NULL_RETURN(listNodeHead);
OsMemListAdd(listNodeHead, &preNode->selfNode.freeNodeInfo, firstNode);
} else {
⑹ nextNode = OS_MEM_NEXT_NODE(node);
if (!OS_MEM_NODE_GET_USED_FLAG(nextNode->selfNode.sizeAndFlag)) {
OsMemListDelete(&nextNode->selfNode.freeNodeInfo, firstNode);
OsMemMergeNode(nextNode);
}
⑺ listNodeHead = OS_MEM_HEAD(pool, node->selfNode.sizeAndFlag);
OS_CHECK_NULL_RETURN(listNodeHead);
OsMemListAdd(listNodeHead, &node->selfNode.freeNodeInfo, firstNode);
}
}
2.6 Повторно подать заявку на динамическую память
LITE_OS_SEC_TEXT_MINOR VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size)
{
UINT32 intSave;
VOID *newPtr = NULL;
BOOL isSlabMem = FALSE;
⑴ if (OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size) || (pool == NULL)) {
return NULL;
}
⑵ if (ptr == NULL) {
newPtr = LOS_MemAlloc(pool, size);
goto OUT;
}
⑶ if (size == 0) {
(VOID)LOS_MemFree(pool, ptr);
goto OUT;
}
MEM_LOCK(intSave);
⑷ newPtr = OsMemReallocSlab(pool, ptr, &isSlabMem, size);
if (isSlabMem == TRUE) {
goto OUT_UNLOCK;
}
⑸ newPtr = OsMemRealloc(pool, ptr, size);
OUT_UNLOCK:
MEM_UNLOCK(intSave);
OUT:
LOS_TRACE(MEM_REALLOC, pool, (UINTPTR)ptr, size);
return newPtr;
}
STATIC VOID *OsMemRealloc(VOID *pool, VOID *ptr, UINT32 size)
{
LosMemDynNode *node = NULL;
LosMemDynNode *nextNode = NULL;
VOID *tmpPtr = NULL;
VOID *realPtr = NULL;
UINT32 nodeSize;
⑴ UINT32 allocSize = OS_MEM_ALIGN(size + OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE);
#ifdef LOSCFG_MEM_RECORDINFO
const VOID *originPtr = ptr;
#endif
⑵ realPtr = OsGetRealPtr(pool, ptr);
if (realPtr == NULL) {
return NULL;
}
⑶ node = (LosMemDynNode *)((UINTPTR)realPtr - OS_MEM_NODE_HEAD_SIZE);
if (OsMemCheckUsedNode(pool, node) != LOS_OK) {
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordFree(originPtr, 0);
#endif
return NULL;
}
nodeSize = OS_MEM_NODE_GET_SIZE(node->selfNode.sizeAndFlag);
⑷ if (nodeSize >= allocSize) {
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordFree(originPtr, node->selfNode.originSize);
#endif
OsMemReAllocSmaller(pool, allocSize, node, nodeSize);
#ifdef LOSCFG_MEM_RECORDINFO
OsMemReallocNodeRecord(node, size, ptr);
#endif
return (VOID *)ptr;
}
⑸ nextNode = OS_MEM_NEXT_NODE(node);
⑹ if (!OS_MEM_NODE_GET_USED_FLAG(nextNode->selfNode.sizeAndFlag) &&
((nextNode->selfNode.sizeAndFlag + nodeSize) >= allocSize)) {
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordFree(originPtr, node->selfNode.originSize);
#endif
⑺ OsMemMergeNodeForReAllocBigger(pool, allocSize, node, nodeSize, nextNode);
#ifdef LOSCFG_MEM_RECORDINFO
OsMemReallocNodeRecord(node, size, ptr);
#endif
return (VOID *)ptr;
}
⑻ tmpPtr = OsMemAllocWithCheck(pool, size);
if (tmpPtr != NULL) {
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordMalloc(tmpPtr, size);
#endif
UINT32 gapSize = (UINT32)((UINTPTR)ptr - (UINTPTR)realPtr);
⑼ if (memcpy_s(tmpPtr, size, ptr, (nodeSize - OS_MEM_NODE_HEAD_SIZE - gapSize)) != EOK) {
(VOID)OsMemFree((VOID *)pool, (VOID *)tmpPtr);
return NULL;
}
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordFree(originPtr, node->selfNode.originSize);
#endif
⑽ OsMemFreeNode(node, pool);
}
return tmpPtr;
}
STATIC VOID *OsGetRealPtr(const VOID *pool, VOID *ptr)
{
VOID *realPtr = ptr;
⑴ UINT32 gapSize = *((UINT32 *)((UINTPTR)ptr - sizeof(UINT32)));
⑵ if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize) && OS_MEM_NODE_GET_USED_FLAG(gapSize)) {
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordFree(ptr, 0);
#endif
PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize);
return NULL;
}
⑶ if (OS_MEM_NODE_GET_ALIGNED_FLAG(gapSize)) {
⑷ gapSize = OS_MEM_NODE_GET_ALIGNED_GAPSIZE(gapSize);
if ((gapSize & (OS_MEM_ALIGN_SIZE - 1)) ||
(gapSize > ((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE - (UINTPTR)pool))) {
PRINT_ERR("[%s:%d]gapSize:0x%x error\n", __FUNCTION__, __LINE__, gapSize);
#ifdef LOSCFG_MEM_RECORDINFO
OsMemRecordFree(ptr, 0);
#endif
return NULL;
}
⑸ realPtr = (VOID *)((UINTPTR)ptr - (UINTPTR)gapSize);
}
return realPtr;
}
резюме
LiteOS
Кодовый склад, рекомендуется посетитьgit ee.com/l IT EOS/lite…,обрати внимание наWatch
,какStar
,иFork
на ваш счет, спасибо.