Комментарии 2
Спасибо автору. Очень занятный курс, всегда было интересно пройти шаги разработки OS, приближенных к реальности
Однако с приведенной реализацией кучи есть определённые проблемы.
Во-первых в kmalloc есть большие куски лишнего кода, которые никогда не сработают. Дело в том, что в куче никогда не будет 2-х последовательных пустых участков памяти (благодаря функции kfree, которая освобождённый блок сразу же клеит к соседям). По сему ветки
можно спокойно выбрасывать.
В итоге достаточно обработать такие случаи:
1) Найден пустой блок размером <size — пробуем его занять, если он последний в списке
2) Найден пустой блок размером ==size — занимаем его и выходим
3) Найден пустой блок размером >size — занимаем его, а из остатка создаём пустой блок (!!! только если он не последний)
4) Подходящий пустой блок не найден — создаём новый в конце списка
Я проверял — все тесты проходятся без указанного кода, а kmalloc становится проще и читабельней.
Во-вторых, реализация kmalloc_a (в репозитории) выглядит стрёмно. Не похоже, что она будет работать для всех случаев. Например, align==4, а (ptr=kmalloc(size + align))==10, (ptr = ptr + align)==14, маскируем (aligned_ptr = ptr & ~(align — 1))==12 и ((void **) aligned_ptr)[-1]==8 (для 32bit-ого указателя). Т.е. мы вылезли за пределы выделенной памяти. По-моему нужно добавлять (align — 1 + sizeof(void*)) вместо align для гарантии безопасности.
Код не будет выявлять проблем, пока все size для kmalloc кратны 4, align не меньше 8.
Однако с приведенной реализацией кучи есть определённые проблемы.
Во-первых в kmalloc есть большие куски лишнего кода, которые никогда не сработают. Дело в том, что в куче никогда не будет 2-х последовательных пустых участков памяти (благодаря функции kfree, которая освобождённый блок сразу же клеит к соседям). По сему ветки
/* try to ask contribution from free left sibling */
if (current->prev != null) { ... }
...
/* try to contribute free right sibling */
if (current->next != null) { ... }
можно спокойно выбрасывать.
В итоге достаточно обработать такие случаи:
1) Найден пустой блок размером <size — пробуем его занять, если он последний в списке
2) Найден пустой блок размером ==size — занимаем его и выходим
3) Найден пустой блок размером >size — занимаем его, а из остатка создаём пустой блок (!!! только если он не последний)
4) Подходящий пустой блок не найден — создаём новый в конце списка
Я проверял — все тесты проходятся без указанного кода, а kmalloc становится проще и читабельней.
Во-вторых, реализация kmalloc_a (в репозитории) выглядит стрёмно. Не похоже, что она будет работать для всех случаев. Например, align==4, а (ptr=kmalloc(size + align))==10, (ptr = ptr + align)==14, маскируем (aligned_ptr = ptr & ~(align — 1))==12 и ((void **) aligned_ptr)[-1]==8 (для 32bit-ого указателя). Т.е. мы вылезли за пределы выделенной памяти. По-моему нужно добавлять (align — 1 + sizeof(void*)) вместо align для гарантии безопасности.
Код не будет выявлять проблем, пока все size для kmalloc кратны 4, align не меньше 8.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Разработка монолитной Unix подобной OS — Куча (4)