Struktura Kobject pojawiła się po raz pierwszy w jądrze linuxa w wersji 2.5.45. Początkowo miał być to zunifikowany sposób na (prawie) automatyczne liczenie referencji do dowolnych obiektów. Jednak z czasem Kobject'y doczekały się dodatkowych funkcjonalności, takich jak reprezentowanie posiadanych w sobie obiektów w systemie sysfs. Generalnie w kodzie jądra linuxa nie spotyka się samych Kobject'ów, tylko złożone struktury, w skład których wchodzi Kobject.
Kobject'y stosuje się przede wszystkim jako:
Kobject jest tak naprawdę typu struct kobject
i jest zdefiniowany w pliku <linux/kobject.h> wraz ze wszystkimi pomocnymi funkcjami.
Aby dołączyć Kobject do naszej struktury dodajemy do niej dodatkowe pole typu struct kobject
. Przykładowa struktura z dołączonym do niej Kobject'em reprezentująca urządzenie znakowe w jądrze:
struct cdev {
struct kobject kobj;
struct module *owner;
struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
kobject
jest analogiczny do dołączania pola list_head
i w analogiczny sposób możemy konwertować wskaźniki typu struct kobject*
do interesującej nas struktury. Makro za to odpowiedzialne ma następującą składnię:
container_of(pointer, type, member)
cdev
jego wykorzystanie wygląda następująco:
struct cdev *device = container_of(kp, struct cdev, kobj);
Kobject przed pierwszym musi zostać zaincjalizowany. Realizuje się to używając poniższej funkcji:
void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
kobject_init
jest ustawienie licznika referencji na 1.
Kolejnym krokiem koniecznym do pełnego zainicjalizowania Kobjecta jest ustawienie mu nazwy używanej w systemie sysfs. Realizuje się to w sposób następujący:
int kobject_set_name(struct kobject *kobj, const char *format, ...);
format
jest listą argumentów analogiczną do tej występującej w funkcji printf
.
W języku C nie da się automatycznie zliczać referencji, poniewąż nie jesteśmy w stanie automatycznie wychwycić momentu, w którym dany obiekt przestaje być używany, bądź też zaczyna być używany w innym miejscu. W związku z tym musimy zliczać referencje ręcznie. W przypadku mechanizmu Kobject wykonuje się to w sposób następujący:
struct kobject *kobject_get(struct kobject *kobj);
NULL
void kobject_put(struct kobject *kobj);
Ponieważ funkcja kobject_put
przyjmuje argument struct kobject*
, nie jest ona w stanie dowiedzieć się, jakiego typu jest przypisany do niego obiekt, a co za tym idzie nie potrafi go poprawnie zwolnić. Metoda rozwiązywania tego problemu polega na zdefiniowaniu funkcji zwalniającej przypisany obiekt w drugim argumencie typu struct ktype*
przekazywanym podczas inicjalizacji Kobject'a.
Przykładowa realizacja tej metody może wyglądać następująco. Przypuśćmy, że obiekt nad którym pracujemy ma typ struct my_object
. Najbardziej standardowa funkcja wyłuskująca nasz obiekt z Kobject'a, a następnie usuwająca go wygląda następująco:
void my_object_release(struct kobject *kobj)
{
struct my_object *mine = container_of(kobj, struct my_object, kobj);
kfree(mine);
}
release
struktury kobj_type
, która wygląda następująco:
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
};
struct kobj_type*
przekazujemy do kobject_init
jako drugi argument.
struct my_object* mine = kmalloc(sizeof(struct my_object), GFP_KERNEL);
struct kobj_type* ktype = kmalloc(sizeof(struct kobj_type), GFP_KERNEL);
ktype->release = my_object_release;
kobject_init(&mine->kobj, ktype);
// tutaj wykonujemy jakieś operacje z wykorzytaniem mine
kobject_put(mine);
Kset jest po prostu kontenerem na Kobject'y. Kobject'y należące do tego samego Kset'a mogą być różnego typu, jednak fakt, że na zewnątrz są widoczne jako obiektu typu struct kobject*
sprawia, że nie można ich wtedy rozróżnić, co bardzo utrudnia pracę z takim modelem.
Kset dodatkowo po utworzeniu i zarejestrowaniu reprezentuje folder w systemie sysfs, w którym leżą pliki będące Kobject'ami należącymi do tego Kset'a.
Obiekt Kset tworzy się i rejestruje przy pomocy funkcji:
struct kset *kset_create_and_add(char *name, struct kset_uevent_ops *u, struct kobject *parent);
name
będącym podkatalogiem reprezentowanym przez parent
.
Aby usunąć nieużywanego Kset'a należy użyć:
void kset_unregister(struct kset *kset);
Dodawanie Kobject'a do Kset'a odbywa się w dwóch krokach:
kset
wskaźnikiem do Kset'a do jakiego chcemy go dodać.int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...);
parent
równym NULL
.
Dla Kseta istnieją podobne funkcje jak dla Kobject'a:
void kset_init(struct kset *kset);
int kset_add(struct kset *kset);
int kset_register(struct kset *kset);
void kset_unregister(struct kset *kset);
struct kset *kset_get(struct kset *kset);
void kset_put(struct kset *kset);
kobject_set_name(&my_set->kobj, "The name");