Linux device Driver Model--brief analysis--turn

Source: Internet
Author: User

1, typeof

typeof is not a keyword for ISO c, but an extension of GCC to C. typeof is a keyword (similar to sizeof) that is used to get the type of an expression.

To give a simple example:

Char tt;

typeof (TT) CC;

The typeof (TT) is equivalent to Char, which is equivalent to declaring a char cc;

2, Offsetof

Position:

Purpose: Gets the member of the struct type member the offset in the structure body

Analysis:

#define OFFSETOF (Type, MEMBER) ((size_t) & ((TYPE *) 0)->member)

Suppose there are structural Uio_mem:

struct UIO_MEM

{

struct Kobject kobj;

unsigned long addr;

unsigned long size;

int memtype;

void __iomem *internal_addr;

};

What do you do if you want to get the memtype of a member in the UIO_MEM?

Very simple, as long as the use of offsetof (struct Uio_mem, memtype) can be.

You can expand the above expression to:

(size_t) & ((struct Uio_mem *) 0), Memtype

(struct Uio_mem *) 0 casts 0 as a pointer to a struct UIO_MEM, as P = (struct Uio_mem *) 0,p is a pointer to a struct UIO_MEM with a value of 0. The P->memtype points to the member memtype of the struct Uio_mem, and then takes the address & (P->memtype), which gives the address of the member Memtype. Since the structure base address P is 0, & (p->memtype) is offset from p. Finally, the member's address is cast to size_t, which is actually converted to int.

typedef __kernel_size_t SIZE_T;
typedef unsigned int __kernel_size_t;

In this example offsetof (struct uio_mem, memtype) = sizeof (struct kobject) + sizeof (unsigned long) + sizeof (unsigned long)

Reference:http://cutebunny.blog.51cto.com/301216/67517

3, Container_of

Position:

Purpose: Gets a pointer to the struct type containing the member member by pointing to PTR, pointer to member

Analysis:

#define CONTAINER_OF (PTR, type, member) ({/

Const typeof (((type *) 0)->member) *__mptr = (PTR); /

(Type *) ((char *) __mptr-offsetof (Type,member));})

Suppose there are structural Uio_mem:

struct UIO_MEM

{

struct Kobject kobj;

unsigned long addr;

unsigned long size;

int memtype;

void __iomem *internal_addr;

};

The pointer p (so the type of P is int *) of the existing member Memtype that points to uio_mem, how do I get a pointer to the struct UIO_MEM? Congratulations, correct, using container_of (p, struct uio_mem, Memtype).

Expand the macro to:

Const typeof ((struct Uio_mem *) 0), memtype) *__mptr = (p);//1

(Struct Uio_mem *) ((char *) __mptr-offsetof (struct Uio_mem, memtype)); 2

According to the previous analysis, it is easy to understand that statement 1 is equivalent to:

const int *__mptr = p;

That is, __mptr points to the member Memtype of Uio_mem, that is, __mptr is the address of UIO_MEM member Memtype. So if we know the memtype in the struct uio_mem, then subtract this offset with the Memtype address, do you know the "first" address of the struct UIO_MEM?

Based on the above analysis, the offsets of memtype in the struct uio_mem are obtained by offsetof (struct Uio_mem, memtype) and then subtracted by the actual address of Memtype (also __mptr). This gets the address of the struct uio_mem, and finally the Uio_mem address is coerced to a struct uio_mem *, the structure of the Uio_mem pointer, which is the above statement 2. It is easy to understand that statement 1 is equivalent to:

const int *__mptr = p;

That is, __mptr points to the member Memtype of Uio_mem, that is, __mptr is the address of UIO_MEM member Memtype. So if we know the memtype in the struct uio_mem, then subtract this offset with the Memtype address, do you know the "first" address of the struct UIO_MEM?

Based on the above analysis, the offsets of memtype in the struct uio_mem are obtained by offsetof (struct Uio_mem, memtype) and then subtracted by the actual address of Memtype (also __mptr). This gets the address of the struct uio_mem, and finally the Uio_mem address is coerced to a struct uio_mem *, the structure of the Uio_mem pointer, which is the above statement 2.

=======================================================================================

The driving model and the abstractions built on Kobject are difficult to understand, in part because there is no obvious entry point. Dealing with kobjects requires understanding some of the different types of mutual references to each other. In order to make things simple, we will use the "multi-pass" approach, starting with a vague concept and gradually adding details. For this purpose, here are some of the concepts we are going to use.

L A Kboject is an object of type struct Kobject

Kobject has a name (name) and a reference count (reference count). A Kobject also contains a parent pointer (which can be arranged hierarchically between objects), a special type (that is, ktype), a representation in the SYSFS virtual file system (representation).

Kobjects basically does not care about itself, they are often embedded in other data structures that contain truly concerned members.

Never let a data structure contain more than 1 kobject, and if you do, the reference count for that object must be messy and incorrect, and your code will be full of bugs, so don't do it.

L A Ktype is the type of object that contains Kobject

Each structure that contains kobject requires a corresponding ktype. Ktype controls what happens when Kobject is created and destroyed.

L A Kset is a group of kobjects

This group of kobjects can belong to the same ktype, or it can belong to different ktypes. Kset is the basic container type that collects kobjects. Ksets also contains their own kobjects, but you can safely ignore those implementation details, because Kset's core code automatically handles their own kobject.

We will learn how to create and manipulate all these types. We will use the bottom-up approach and go back to Kobjects's learning.

First, embedded kobjects

Kernel code basically does not create a separate kobject, but there are exceptions (explained later). Kobjects is used to control access to a larger, domain-specific object. So, you'll find that kobjects is often embedded in other data structures. If you are accustomed to thinking in an object-oriented way, you can assume that kobjects is the abstract base class of the inherited top level. Kobject implements a set of operations that are not of much use to themselves, but are useful for other objects (objects that contain kobject). The C language does not support direct support for inheritance relationships, so you must use other techniques-such as embedding data structures. For example, UiO's code has a data structure that defines the memory boundaries associated to a UiO device:

struct UIO_MEM

{

struct Kobject kobj;

unsigned long addr;

unsigned long size;

int memtype;

void __iomem *internal_addr;

};

If you have a uio_mem struct, use its kobj members to find the embedded koject. Code that uses kobjects often encounters a problem: Given a kobject pointer, how can I find a pointer to the structure that contains the Kobject? You must avoid some "tricks", such as assuming that Kobject is the first member of a struct (the pointer to the first member of the struct is the pointer to the struct), instead, you should use the CONTAINER_OF macro ():

CONTAINER_OF (pointer, type, member)

Pointer is a pointer to an embedded kobject, type is a structure that contains kobject, and member is the name of the field in the structure that the pointer points to. The return value of the container_of is a pointer to the given type. For example, KP points to the kobject in the UIO_MEM structure, so you can get a pointer to Uio_mem in the following way:

struct Uio_mem *u_mem = container_of (KP, struct uio_mem, kobj);

Programmers typically define a simple macro that kobject the pointer "back" to the type of its "container" (that is, a pointer to the structure that contains the Kobject).

Second, the initialization of kobjects

The code that creates kobject must, of course, have to initialize that object. Some internal domains enforce the use of kobject_init () to initialize:

void Kobject_init (struct kobject *kobj, struct kobj_type *ktype);

Because each kobject must be associated with a kobj_type, it takes a ktype to create the kobject correctly. After calling Kobject_init (), the function Kobject_add () must be called in order to register the Kobject in SYSFS:

int Kobject_add (struct kobject *kobj, struct kobject *parent, const char *fmt, ...);

The function can correctly set the name of the Kobject and its parent node. If Kobject is associated to a special Kset, Kobj->kset must be assigned before calling Kobject_add (). If a kset is associated to a kobject, then the parent node of the Kobject in the Kobject_add () call can be set to null (the second parameter of Kobject_add () is set to null), and the The parent node of the Kobject is the kset itself.

Because the name of Kobject is set when Kobject joins the kernel, you should never directly manipulate a kobject name. If you have to change the name of Kobject, then call Kobject_rename ():

int kobject_rename (struct kobject *kobj, const char *new_name);

The function does not perform any locking, nor does it check the legitimacy of the name, so the caller must provide the locking mechanism and check the legitimacy of the name.

There is also a function called Kobject_set_name (), the function will be deleted, so do not call this function.

You should use the function kobject_name () to get the name of Kobject:

const char *kobject_name (const struct kobject * kobj);

There is also a function for initializing and adding kobject to the kernel at the same time, i.e. Kobject_init_and_add ():

int Kobject_init_and_add (struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...);

The parameters of the function are the same as those described by the individual functions Kobject_init () and Kobject_add ().

Three, hot Plug and Unplug

When a kobject is registered to the Kobject core, it is necessary to declare that the Kobject has been created. Can be implemented by calling Kobject_uevent ():

int kobject_uevent (struct kobject *kobj, enum kobject_action action);

The Kobj_add event is used when Kobject is first added to the kernel. When you use this event, all kobject properties or children must have been properly initialized, because when kobj_add occurs, the user space starts checking them immediately.

When Kobject is removed from the kernel, the Kobject core automatically creates Kobj_remove events, and the caller does not have to create them manually.

Iv. Reference Counting

A key feature of Kobject is the reference count as the object that contains it. The object (and the code that supports the object) must exist as long as a reference to the object exists. The function of the underlying operation Kobject reference count is:

struct Kobject *kobject_get (struct kobject *kobj);

void Kobject_put (struct kobject *kobj);

Calling Kobject_get () correctly will increase the Kobject reference count and return a pointer to Kobject.

When a reference is released, calling Kobject_put () reduces the reference count, and it is possible to dispose of the object (when the reference count is 0 o'clock). Note that the Kobject_init () setting reference count is 1, so the code that sets Kobject eventually needs to call Kobject_put () to release that reference.

Because kobjects are dynamic, they cannot be declared static or stored on the stack, but are always allocated dynamically. Future versions of the kernel will contain run-time checks of Kobject and will warn the developer if Kobject is found to be statically created.

If you only want to use Kobject as the reference counter for your structure, use the structure kref; using Kobject is too wasteful. For information about Kref, please refer to documentation/kref.txt.

V. Create a "simple" kobjects

Sometimes developers just want to have a way to create a simple directory in the SYSFS hierarchy, rather than having to mix with complex ksets, show and store methods, and other details. This is an exception to the need to create a single kobject (previously said not to create a single kobject). To create such a portal, you can use the function:

struct Kobject *kobject_create_and_add (char *name, struct kobject *parent);

The function creates and places a kobject below the parent kobject specified in Sysfs. When you create a simple property associated with the Kobject, you can use:

int sysfs_create_file (struct kobject *kobj, struct attribute *attr);

or int sysfs_create_group (struct kobject *kobj, struct attribute_group *grp);

There are two types of properties on the Kobject created by Kobject_create_and_add (), which can be of type kobj_attribute, so you do not need to create custom properties.

Vi. Ktypes and Release methods

An important thing has not been discussed, that is, what happens when a Kobject reference count is 0 o'clock? The code that creates the Kobject generally does not know when this happens (the reference count becomes 0), and even the expected life cycle of an object can become complex after the introduction of SYSFS, because the rest of the kernel can refer to any kobject that is registered in the system.

The end result is a structure that is protected by kobject (the structure contains a kobject) that cannot be released until its reference count becomes 0. The code that creates kobject does not directly control the reference count. Therefore, when the last reference to kobjects disappears, the code must be notified asynchronously.

Once you have registered your kobject through Kobject_add (), never use Kfree directly to release it. The only safe way to do this is to use Kobject_put ().

This notification is done through the Kobject release () method. Typically, such a method has a format:

void My_object_release (struct kobject *kobj)

{struct My_object *mine = container_of (kobj, struct my_object, kobj);

/* Perform Any additional cleanup on this object, then ... */

Kfree (mine); }

It is important to note that each kobject must have a release () method, and that the kobject must be persisted (in a stable state) until the method is called. If you do not encounter such a limitation, then the code is flawed. Note that if you forget to provide the release () method, the kernel will give you a warning. Do not attempt to circumvent this warning by providing an "empty" release method, and if you try to do so, you will be mercilessly ridiculed by kobject defenders.

Note that the Kobject name is available in the release method, but must not be changed in the callback. Otherwise, there will be a memory leak in the kobject core, unpleasant.

Interestingly, the release method does not exist inside Kobject, but is associated with Ktype. So let's introduce the KOBJ_TYPE structure:

struct Kobj_type {void (*release) (struct kobject *);

struct Sysfs_ops *sysfs_ops;

struct attribute **default_attrs; };

This structure is used to describe a particular type of kobject (or, more precisely, the "container" object that describes Kobject). Each kobject requires an associated kobj_type structure, and a pointer to the KOBJ_TYPE structure must be assigned when you call Kobject_init () or Kobject_init_and_add ().

The release member of the struct Kobj_type is a pointer to the release method corresponding to that class of Kobject. The other two members (Sysfs_ops and Default_attrs) control how objects of this type are represented in Sysfs, which is beyond the scope of this document.

The default_attrs pointer is a list of default properties that are automatically added when you create a kobject that is registered with this ktype.

Seven, Ksets

A kset is just a collection of kobjects that want to relate to each other. There is no special restriction that these kobjects belong to the same ktype, but if not, then be very careful.

A kset provides the following features:

L It provides a container for a group of kobjects

A kset can be used by the kernel to track all block devices or all PCI device drivers.

L A kset is also a subdirectory of Sysfs, where the kobjects associated with it will be displayed

Each kset contains a kobject, which can be set to the parent of other kobjects, and the top-level directory of SYSFS is built in this way.

L Ksets supports kobjects hot swapping and affects how uevent events are reported to user space

In the object-oriented realm, Kset is the top-level container class; Ksets contains their own kobject, but the Kobject is managed by Kset code and should not be manipulated by other users.

A kset uses a standard kernel-linked list to manage its child nodes. Kobjects through their kset members points to the kset that contain them. Basically in all cases, a kobject that belongs to a kset treats the kset that contains it as its parent (or, strictly speaking, kobject as a parent node embedded in kset).

Because a kset contains a kobject, Kset should always be dynamically created rather than statically declared or run on the stack.

Create a Kset using the following code:

struct Kset *kset_create_and_add (const char *name, struct kset_uevent_ops *u,

struct Kobject *parent);

When you end the use of Kset, call void Kset_unregister (struct kset *kset) to destroy it. If a kset wants to control the uevent operation of the kobjects associated with it, the struct kset_uevent_ops can be used:

struct Kset_uevent_ops {int (*filter) (struct kset *kset, struct kobject *kobj);

const char * (*name) (struct kset *kset, struct kobject *kobj); Int (*uevent) (struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env); };

For a specific Kobject,filter function, allow Kset to block uevent events from being routed to user space. If the filter function returns a 0,uevent event, it will not be sent.

The call to the name function can override the default name of the Kset that sends uevent to the user space. By default, the name is Kset's own name, but if the name function exists, then the default name can be overridden.

The Uevent function would be a called when the uevent was about-to-be sent to userspace-to-allow more environment variables to Being added to the uevent.

The Uevent function is called (-_-....) when the Uevent event is about to be sent to the user space to allow more environment variables to be added to the Uevent event.

One might ask how, exactly, a kobject are added to a kset, given this no functions which perform that function has been PR Esented.

(The above sentence will not translate ...) )

The answer is that this work is handled by Kobject_add (). When a kobject is passed to Kobject_add (), Kobject's Kset member should point to the Kobject to which it (Kset) belongs, and then Kobject_add () handle the rest.

If the kobject that belong to a kset do not have a parent Kobject collection (do not understand ...) ), it will be added to the Kset directory. Not all Kset members need to exist in the Kset directory. If a parent kobject is assigned to the Kobject before Kobject is added, the kobject is registered in Kset, but is added to its parent Kobject directory.

Viii. Removal of Kobject

When a kobject is successfully registered into the Kobject core, it must be cleared when the code ends its use. You can call Kobject_put (), and after calling the function, the Kobject core will automatically release all the memory allocated to the Kobject. If a kobj_add uevent is sent to Kobject, then a corresponding Kobj_remove uevent will also be sent, and all other sysfs of space management will also be processed.

If you need two stages to delete kobject (that is, when you need to destroy Kobject), call Kobject_del (), the function will remove the kobject from the SYSFS, which will make kobject invisible, but not cleared, and the reference count of the object has not changed. Call Kobject_put () at a later time to complete the release of the memory associated with the Kobject.

If a circular reference is formed, Kobject_del () can be used to discard a reference to the parent node. This is useful in some situations, such as a parent node referencing a child node. You must use Kobject_del () to break the circular reference, after which a release method is called and the objects in the previous loop are each other.

For more detailed examples of ksets and kobjects, refer to Sample/kobject/kset-example.c code

Linux device Driver Model--brief analysis--turn

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.