亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 904 | 回復: 0
打印 上一主題 下一主題

LDD2 notes--Ch 10 JUDICIOUS USE OF DATA TYPES [復制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-11-12 15:37 |只看該作者 |倒序瀏覽
Given the multiplatform nature of Linux, drivers intended for serious use should be portable as well.
1 Use of Standard C Types
2 Assigning an Explicit Size to Data Items
The kernel offers the following data types to use whenever you need to know the size of your data. All the types are declared in , which in turn is included by :

u8; /* unsigned byte (8 bits) */
u16; /* unsigned word (16 bits) */
u32; /* unsigned 32-bit value */
u64; /* unsigned 64-bit value */

These data types are accessible only from within kernel code (i.e., __KERNEL__ must be defined before including ). The corresponding signed types exist, but are rarely used; just replace u with s in the name if you need them.

    If a user-space program needs to use these types, it can prefix the names with a double underscore: __u8 and the other types are defined independent of __KERNEL__.

    It's important to remember that these types are Linux specific, and using them hinders porting software to other Unix flavors. Systems with recent compilers will support the C99-standard types, such as uint8_t and uint32_t; when possible, those types should be used in favor of the Linux-specific variety.
3 Interface-Specific Types
Most of the commonly used data types in the kernel have their own typedef statements, thus preventing any portability problems. For example, a process identifier (pid) is usually pid_t instead of int. Even when no interface specific type is defined, it's always important to use the proper data type in a way consistent with the rest of the kernel.

    The complete list of _t types appears in , but when you need a specific type, you'll find it in the prototype of the function you need to call or in the data structure you use. Whenever your driver uses functions that require such "custom" types and you don't follow the convention, the compiler issues a warning. Use the -Wall flag and be careful to remove all the warnings to make sure you code is portable.

    The main problem with _t data items is that when you need to print them, it's not always easy to choose the right printk or printf format. The best way to avoid this is cast the value to the biggest possible type (usually long or unsigned long) and print it through the corresponding format.
4 Other Portability Issues
A general rule is be suspicious of explicit constant values.
Time Intervals
    When dealing with time intervals, don't assume that there are 100 jiffies per second.  The assumption can be false even for the x86 if you play with the HZ value (as some people do), and nobody knows what will happen in future kernels. Whenever you calculate time intervals using jiffies, scale your times using HZ (the number of timer interrupts per second). For example, to check against a timeout of half a second, compare the elapsed time against HZ/2. More generally, the number of jiffies corresponding to msec milliseconds is always msec*HZ/1000.
Page Size
    When playing games with memory, remember that a memory page is PAGE_SIZE bytes, not 4 KB. Relevant macros are PAGE_SIZE and PAGE_SHIFT. The latter contains the number of bits to shift an address to get its page number. They are defined in , user-space programs can use getpagesize() if they ever need the information.
    If a driver needs 16 KB for temporary data, it shouldn't specify an order of  2 to get_free_pages(), instead the following code is suggested:

int order = (14 - PAGE_SHIFT > 0) ? 14 - PAGE_SHIFT : 0;
buf = get_free_pages(GFP_KERNEL, order);
The solution depends on the knowledge that 16 KB is 1Byte Order
Be careful not to make assumptions about byte ordering. Whenever possible, your code should be written such that it does not care about byte ordering in the data it manipulates.
    You'll need to deal with endianness when you fill in network packet headers, or when you are dealing with a peripheral that operates in a specific byte ordering mode. In that case, the code should include  and should check whether __BIG_ENDIAN or __LITTLE_ENDIAN is defined by the header.
    The Linux kernel defines a set of macros that handle conversions between the processor's byte ordering and that of the data you need to store or load in a specific byte order. For example:
u32 __cpu_to_le32(u32);
u32 __le32_to_cpu(u32);
These two macros convert a value form what ever the CPU uses to an unsigned, little-endian, 32-bit quantity and back. They work whether your CPU is big-endian or little-endian, and whether it is a 32-bit processor or not.
    There are dozens of similar routines; find them at  and . When dealing with pointers, you can also use functions like __cpu_to_le32p, which take a pointer to the value to be converted rather than the value itself.
Data Alignment
    PC users often access unaligned data items, but few architectures permit it. If you need to access unaligned data, you should use the following macros:
#include asm/unaligned.h>
get_unaligned(ptr);
put_unaligned(val, ptr);
These macros are typeless and work for every data item, whether it's one, two, four, or eight bytes long. Thy are defined with any kernel version.
    Another issue related to alignment is portability of data structures across platforms. The same data structure (as defined in the C-language source file) can be compiled differently on different platforms. The compiler arranges structure fields to be aligned according to conventions that differ from platform to platform. At least in theory, the compiler can reorder structure fields in order to optimize memory usage.
    In order to write data structures for data items that can be moved across architectures, you should always enforce natural alignment of the data items in addition to standardizing on a specific endianness. Natural alignment means storing data items at an address that is a multiple of their size. To do this, you should use filler fields that avoid leaving holes in the data structure.
    Note that not all platforms align 64-bit values on 64-bit boundaries, so you'll need filler fields to enforce alignment.
5 Linked Lists
The Linux kernel developers have created a standard implementation of circular, doubly-linked lists; others needing to manipulate lists are encouraged to use this facility.
    To use the list mechanism, your driver must include the file . This header defines a simple structure of type list_head:
struct list_head {
    struct list_head *next, *prev;
};
To use the Linux list facility in your code, you need only embed a list_head inside the structures that make up the list. If your driver maintains a list of things to do, its declaration would look like this:
struct todo_struct {
    struct list_head list;
    int priority; /* driver specific */
    /* other specific fields */
};
The head of the list must be a standalone list_head structure. List heads must be initialized prior to use with the INIT_LIST_HEAD macro:
struct list_head todo_list;
INIT_LIST_HEAD(&todo_list);
Alternatively, lists can be initialized at compile time as follows:
LIST_HEAD(todo_list);
Several functions are defined in  that work with lists:
    list_add(struct list_head *new, struct list_head *head);
This function adds the new entry immediately after the list head--normally at the beginning of the list. It can thus be used to build stacks. Note that the "head" need not be the nominal head of the list; since Linux lists are circular, the head of the list is not different from any other entry.
    list_add_tail(struct list_head *new, struct list_head *head);
Add a new entry just before the given list head--at the end of the list, in other words. Can be used to build FIFO queues.
    list_del(struct list_head *entry);
The given entry is removed from the list.
    list_empty(struct list_head *head);
Returns a nonzero value if the given list is empty.
    list_splice(struct list_head *list, struct list_head *head);
This function joins two lists by inserting list immediately after head.
    A macro, list_entry, is provided that will map a list_head structure pointer back into a pointer to the structure that contains it:
    list_entry(struct list_head *ptr, type_of_struct, field_name);
where ptr is a pointer to the struct list_head being used, type_of_struct is the type of the structure containing the ptr, and the field_name is the name of the list field within the structure.
    The traversal of linked lists is easy: one need only follow the prev and next pointers.
     also defines a macro list_for_each that is used to traverse the linked list.


本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u/17532/showart_2092701.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP