Tutaj można by uznać, że mamy do czynienia z nieco prosztszą sytuacją, gdyż jedyne co funkcja musi zrobić, to dokonać niezbędne zmiany w strukturach, których wymaga algorytm bliźniaków, a które zostały wcześniej omówione. Niestety kilka trick'ów stosowanych przez autorów i arytmetyka na wskaźnikach sprawiają, że wcale nie jest tak łatwo zorientować się co tutaj właściwie się dzieje 1. Pozwolę sobie tutaj pominąć serię testów na błędy jakie występują w orginalnych źródłach, w celu zwiększenia czytelności i zmniejszenia długości listingu.
static void __free_pages_ok (struct page *page, unsigned long order)
{
unsigned long index, page_idx, mask, flags;
free_area_t *area;
struct page *base;
zone_t *zone; // strefa pamięci
-- dokonanie serii testów i ustawień powyższych zmiennych.
-- założenie spinlock'a
while (mask + (1 << (MAX_ORDER - 1))) { // Aż przejrzymy wszystkie listy
struct page *buddy1, *buddy2;
if (!test_and_change_bit(index, area->map)) // bilźniak wciąż zaalokowany
break; // koniec pracy
// łączymy bliźniaków
// najpierw znajdujemy ramki, w których zaczynają się obaj bliźniacy
buddy1 = base + (page_idx ^ -mask); // Huh... -mask == 1 + ~mask
buddy2 = base + page_idx;
memlist_del(&buddy1->list); // kasujemy bliźniaka z listy wolnych
// bloków - łączymy się z nim
mask <<= 1; // maska na dany rozmiar bloku - za
// każdym razem obszar powiększa się
// dwukrotnie
area++; // przejście do kolejnej listy
index >>= 1; // interesująca pozycja w mapie bitowej
page_idx &= mask; // wyliczenie pozycji ramki dla bliźniaka
// na kolejnym poziomie
}
// pozostaje dopisać nowy blok (być może powstały z połączenia)
// do listy wolnych bloków
memlist_add_head(&(base + page_idx)->list, &area->free_list);
-- zdjęcie spinlock'a
}