Struktura deskryptora pamięci podręcznej (UWAGA! - tylko najwazniejsze pola):
struct kmem_cache_t { struct list_head slabs; // częściowo uporządkowane płyty struct list_head *firstnotfull; // pierwsza niecałkiem pełna płyta unsigned int objsize; // rozmiar obiektu unsigned int flags; // flagi - m.in. CFLGS_OFF_SLAB oznacza, // że deskryptory poza płytą unsigned int num; // ilość obiektów w płycie unsigned int gfporder; // określa rozmiar płyty // przekazywane do get_free_pages unsigned int gfpflags; // flagi dla get_free_pages size_t colour; // wartość maksymalnego koloru płyty unsigned int colour_next; // kolor następnej płyty void (*ctor)(void *, kmem_cache_t *, unsigned long); // konstruktor void (*dtor)(void *, kmem_cache_t *, unsigned long); // destruktor char name[CACHE_NAMELEN]; // nazwa pamięci podręcznej struct list_head next; // następna pamięć podr. };
Struktura deskryptora płyty:
struct slab_t { struct list_head list; // lista deskryptorów płyt unsigned long colouroff; // przesunięcie pierwszego obiektu w płycie // (na skutek kolorowania) void *s_mem; // pierwszy obiekt w płycie (uwzględnione // przesunięcie wynikające z kolorowania) unsigned int inuse; // liczba używanych obiektów w płycie kmem_bufctl_t free; // indeks wolnego obiektu (patrz opis // deskryptora obiektu) };
Wreszcie deskryptor obiektu:
typedef unsigned int kmem_bufctl_t; // deskryptor obiektu w płycie #define slab_bufctl(slabp) \ // makro dające dostęp do deskryptora ((kmem_bufctl_t *)(((slab_t*)slabp)+1)) // pierwszego obiektu #define BUFCTL_END 0xffffFFFF // znacznik końca `listy'Jak widać deskryptor obiektu to po prostu liczba. Jest ona wykorzystywana całkiem sprytnie - przy jej pomocy organizowana jest lista wolnych obiektów w płycie, gdzie indeks obiektu funkcjonuje niejako jako wskaźnik do obiektu. Jest to połączone ze sprytną arytmetyką na wskaźnikach w celu dostępu do obiektu o danym indeksie (wskaźnik do obiektu o indeksie i to po prostu slabd->s_mem + i*cached->objsize). Trochę jaśniej (mam nadzieję): dla obiektu wolnego deskryptor ten jest po prostu numerem kolejnego wolnego obiektu. Dodatkowo pole free w deskryptorze płyty (slab_t) to indeks pierwszego wolnego obiektu w całej płycie, a stała BUFCTL_END jest znacznikiem końca takiej listy.
Przy tworzeniu pustej płyty kolejne deskryptory otrzymują kolejne wartości poczynając od 1, poza ostatnim, w którym wpisane zostaje BUFCTL_END, a pole free w deskryptorze płyty jest ustawiane na 0. Przy poszukiwaniu obiektu do alokacji zagląda się do pola free - będzie to indeks głowy naszej listy i zostanie przydzielony jako obiekt, a do pola free wpisana zostanie wartość, którą przechowywał jego deskryptor (czyli kolejny wolny obiekt) (to ważne) wolnego obiektu. Przy dealokacji natomiast obiekt wstawiany jest na początek listy, czyli free ustawiane jest na niego, a w jego deskryptor wpisywana jest stara wartość free.
Być może na początku zrozumienie funkcjonowania tego może być trochę kłopotliwe, ale kluczowe jest uzmysłowienie sobie, że to nic innego jak lista zorganizowana na indeksach tablicy. Mam nadzieję, że pomocny okaże się ten rysunek: