Data Types in the Kernel <LDD3 学习笔记>

Data Types in the Kernel

Use of Standard C Types

/*
 * datasize.c -- print the size of common data items
 * This runs with any Linux kernel (not any Unix, because of <linux/types.h>)
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 */
#include <stdio.h>
#include <sys/utsname.h>
#include <linux/types.h>

int main(int argc, char **argv)
{
    struct utsname name;

    uname(&name); /* never fails :) */
    printf("arch   Size:  char  short  int  long   ptr long-long "
	   " u8 u16 u32 u64\n");
    printf(       "%-12s  %3i   %3i   %3i   %3i   %3i   %3i      "
	   "%3i %3i %3i %3i\n",
	   name.machine,
	   (int)sizeof(char), (int)sizeof(short), (int)sizeof(int),
	   (int)sizeof(long),
	   (int)sizeof(void *), (int)sizeof(long long), (int)sizeof(__u8),
	   (int)sizeof(__u16), (int)sizeof(__u32), (int)sizeof(__u64));
    return 0;
}

Therefore, generic memory addresses in the kernel are usually unsigned long , exploiting the fact that pointers and long integers are always the same size, at least on all the platforms currently supported by
Linux.

这个都简单,有意思的是遇到一个新的结构体——struct utsname

在kernel里面找了一会儿,老是找不到,找到的utsname是个指针函数。

忽然<sys/utsname.h>提醒我。。。这家伙user space,

于是去/usr/include/x86。。。/sys/里面找,找到了utsname.h

把整个sys/utsname.h 贴出来

/* Copyright (C) 1991-2014 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

/*
 *	POSIX Standard: 4.4 System Identification	<sys/utsname.h>
 */

#ifndef	_SYS_UTSNAME_H
#define	_SYS_UTSNAME_H	1

#include <features.h>

__BEGIN_DECLS

#include <bits/utsname.h>

#ifndef _UTSNAME_SYSNAME_LENGTH
# define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH
#endif
#ifndef _UTSNAME_NODENAME_LENGTH
# define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH
#endif
#ifndef _UTSNAME_RELEASE_LENGTH
# define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH
#endif
#ifndef _UTSNAME_VERSION_LENGTH
# define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH
#endif
#ifndef _UTSNAME_MACHINE_LENGTH
# define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH
#endif

/* Structure describing the system and machine.  */
struct utsname
  {
    /* Name of the implementation of the operating system.  */
    char sysname[_UTSNAME_SYSNAME_LENGTH];

    /* Name of this node on the network.  */
    char nodename[_UTSNAME_NODENAME_LENGTH];

    /* Current release level of this implementation.  */
    char release[_UTSNAME_RELEASE_LENGTH];
    /* Current version level of this release.  */
    char version[_UTSNAME_VERSION_LENGTH];

    /* Name of the hardware type the system is running on.  */
    char machine[_UTSNAME_MACHINE_LENGTH];

#if _UTSNAME_DOMAIN_LENGTH - 0
    /* Name of the domain of this node on the network.  */
# ifdef __USE_GNU
    char domainname[_UTSNAME_DOMAIN_LENGTH];
# else
    char __domainname[_UTSNAME_DOMAIN_LENGTH];
# endif
#endif
  };

#ifdef __USE_SVID
/* Note that SVID assumes all members have the same size.  */
# define SYS_NMLN  _UTSNAME_LENGTH
#endif

/* Put information about the system in NAME.  */
extern int uname (struct utsname *__name) __THROW;

__END_DECLS

#endif /* sys/utsname.h  */

哈哈,自己写个demo,把他们统统打印粗来,满足好奇心。

/*************************************************
code writer : EOF
code date : 2014.08.14
e-mail:	[email protected]
code purpose:
	just a demo for how to use structure--utsname

	If you find something wrong with my code,
please touch me by e-mail. Thank you.

*************************************************/
#include <stdio.h>
#include <sys/utsname.h>

int main()
{
	struct utsname demo;

	uname(&demo);

	printf("sysname: %s\nnodename: %s\nrelease :%s\nmachine: %s\n",
		demo.sysname,demo.nodename,demo.release,demo.machine);
#ifdef __USE_GNU
	printf("domainname: %s\n",demo.domainname);
#else
	printf("__domainname: %s\n",demo.__domainname);
#endif

	return 0;
}

Assigning an Explicit Size to Data Items

Sometimes kernel code requires data items of a specific size, perhaps to match pre- defined binary structures, to communicate with user space, or to align data within structures by inserting “padding” fields (but refer to the section “Data Alignment” for
information about alignment issues).

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__ . If, for example, a driver needs to exchange binary structures with a program running
in user space by means of ioctl, the header files should declare 32-bit fields in the structures as __u32 .

Time Intervals

When dealing with time intervals, don’t assume that there are 1000 jiffies per second.
Although this is currently true for the i386 architecture, not every Linux platform runs at this speed. 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 time-out 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. Assuming that the page size is 4 KB and hardcoding the value is a common error among PC programmers, instead, supported platforms
show page sizes from 4 KB to 64 KB, and sometimes they differ between different implementations of the same platform. The relevant macros are PAGE_SIZE and PAGE_SHIFT . The latter contains the number of bits to shift an address to get its page number.

其实在早期的0.1内核里面linus就是直接用的4KB那么去做的,反正那时候他没想到linux会被这么广泛的应用

Linked Lists

To use the list mechanism, your driver must include the file <linux/list.h>. This file defines a simple structure of type list_head :

struct list_head {
struct list_head *next, *prev;
};

List heads must be initialized prior to use with the INIT_LIST_HEAD macro. A “things to do” list head could be declared and initialized with:

struct list_head todo_list;
INIT_LIST_HEAD(&todo_list);

Alternatively, lists can be initialized at compile time:

LIST_HEAD(todo_list);

Several functions are defined in <linux/list.h> that work with lists:

list_add(struct list_head *new, struct list_head *head);
               Adds the new entry immediately after the list head—normally at the beginning of the list. Therefore, it can be used to build stacks. Note, however, that the head need not be the nominal head of the list; if you pass a list_head structure that happens to be in the middle of the list somewhere, the new entry goes immediately after it. Since Linux lists are circular, the head of the list is not generally different from any other entry.
list_add_tail(struct list_head *new, struct list_head *head);
              Adds a new entry just before the given list head—at the end of the list, in other words. list_add_tail can, thus, be used to build first-in first-out queues.
list_del(struct list_head *entry);
list_del_init(struct list_head *entry);
           The given entry is removed from the list. If the entry might ever be reinserted into another list, you should use list_del_init, which reinitializes the linked list pointers.
list_move(struct list_head *entry, struct list_head *head);
list_move_tail(struct list_head *entry, struct list_head *head);
             The given entry is removed from its current list and added to the beginning of head . To put the entry at the end of the new list, use list_move_tail instead.
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);
          Joins two lists by inserting list immediately after head . The list_head structures are good for implementing a list of like structures, but the invoking program is usually more interested in the larger structures that make up the
list as a whole. 

A macro, list_entry, is provided that maps a list_head structure pointer back into a pointer to the structure that contains it. It is invoked as follows:

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 field_name is the name of the list field within the structure. In our todo_struct structure from before, the list field is called simply list . 

Thus, we would turn a list entry into its containing structure with a line such as:

struct todo_struct *todo_ptr = list_entry(listptr, struct todo_struct, list);

The list_entry macro takes a little getting used to but is not that hard to use.

"像倦鸟归去留下的空寂,安安静静"

Data Types in the Kernel <LDD3 学习笔记>,布布扣,bubuko.com

时间: 2024-10-12 18:52:37

Data Types in the Kernel <LDD3 学习笔记>的相关文章

Data Types in the Kernel &amp;lt;LDD3 学习笔记&amp;gt;

Data Types in the Kernel Use of Standard C Types /* * datasize.c -- print the size of common data items * This runs with any Linux kernel (not any Unix, because of <linux/types.h>) * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyr

Time, Delays, and Deferred Work &lt;LDD3&gt; 学习笔记 + jiffies.h 分析

Time, Delays, and Deferred Work Dealing with time involves the following tasks, in order of increasing complexity: ? Measuring time lapses and comparing times ? Knowing the current time ? Delaying operation for a specified amount of time ? Scheduling

kernel&amp;uboot学习笔记

uboot kernel uboot 1.根据include/configs/$(target).h可以生成include/autoconf.mk. kernel 1.由.config生成的autoconf.h的位置: include/generated/autoconf.h 或者 include/linux/autoconf.h ,比较新的内核使用的前者. 2.Linux的Makefile的五个部分: Makefile 顶层Makefile .config 内核配置文件 arch/$(ARCH

&lt;Debugging Techniques&gt; LDD3 学习笔记

Debugging Techniques 内核debug的挑战: Kernel programming brings its own, unique debugging challenges. Kernel code can not be easily executed under a debugger, nor can it be easily traced, because it is a set of functionalities not related to a specific pr

Data Science at the Command Line学习笔记(一)

学习Data Science at the Command Line时,win7下安装环境是遇到了一些小问题,最后通过百度解决. 1)电脑安装完vagrant+virtual box之后,新建工作目录,cmd进入工作目录后 $ vagrant init data-science-toolbox/data-science-at-the-command-line 生成了一个Vagrantfile文件.文件内容如下: Vagrant.configure(2) do |config| config.vm

Communicating with Hardware 《LDD3 学习笔记》

Communicating with Hardware Using I/O Ports I/O ports are the means by which drivers communicate with many devices, at least part of the time. This section covers the various functions available for making use of I/O ports; we also touch on some port

Data Science at the Command Line学习笔记(二)

1.vagrant建立简单httpserver方法: 1)映射端口 修改Vagrantfile, 末尾添加本地端口和虚机端口的映射关系, 然后执行vagrant reload. Vagrant::Config.run do |config| # Forward guest port 8000 to host port 8000 config.vm.forward_port 8000, 8000 end 2)启动HTTPServer 通过python自带web服务器SimpleHTTPServer

Professional Linux Kernel Architecture - 学习笔记.进程管理和调度

1.相关概念. 1.程序.进程.线程 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本:进程是程序的一次执行活动,属于动态概念.允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行.这是这样的设计,进程的出现让每个用户感觉到自己独享CPU. 线程是进程的一个实体, 是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,

Linux System Programming 学习笔记(二) 文件I/O

1.每个Linux进程都有一个最大打开文件数,默认情况下,最大值是1024 文件描述符不仅可以引用普通文件,也可以引用套接字socket,目录,管道(everything is a file) 默认情况下,子进程会获得其父进程文件表的完整拷贝 2.打开文件 open系统调用必须包含 O_RDONLY,O_WRONLY,O_RDWR 三种存取模式之一 注意 O_NONBLOCK模式 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644