家电维修班,手机维修班,电脑维修班,电工班,焊工班,液晶电视维修班,电动工具维修班、电动车摩托车维修班、网络营销培训、网站设计培训、淘宝培训---全国招生 家电维修班,手机维修班,电脑维修班,电工班,焊工班,液晶电视维修班,电动工具维修班、电动车摩托车维修班、网络营销培训、网站设计培训、淘宝培训---全国招生
您的位置:网站首页 > 电器维修资料网 > 正文 >

linux内核中一些常用的数据结构和操作

★★★★★【文章导读】:linux内核中一些常用的数据结构和操作具体内容是:};链表头的初始化,注意,结构中的指针为NULL并不是初始化,而是指向自身才是初始化,如果只是按普通情况下的置为NULL,而不是指向自身,系统会崩溃,这是一个容易犯的错误:#defineLIST_HEAD_INIT(name){&(nAME…

来源: 日期:2013-12-11 14:27:12 人气:标签:

linux内核中一些常用的数据结构和操作

    };链表头的初始化,注意,结构中的指针为NULL并不是初始化,而是指向自身才是初始化,如果只是按普通情况下的置为NULL,而不是指向自身,系统会崩溃,这是一个容易犯的错误:#define LIST_HEAD_INIT(name) { &(nAME), &(name) }#define LIST_HEAD(name)

    struct list_head name = LIST_HEAD_INIT(name)#define INIT_LIST_HEAD(ptr) do {

    (ptr)->next = (ptr); (ptr)->prev = (ptr);

    } while (0)最常用的链表操作:插入到链表头:

    void list_add(struct list_head *new, struct list_head *head);插入到链表尾:

    void list_add_tail(struct list_head *new, struct list_head *head);删除链表节点:

    void list_del(struct list_head *entry);将节点移动到另一链表:

    void list_move(struct list_head *list, struct list_head *head);将节点移动到链表尾:

    void list_move_tail(struct list_head *list,struct list_head *head);判断链表是否为空,返回1为空,0非空

    int list_empty(struct list_head *head);把两个链表拼接起来:

    void list_splICe(struct list_head *list, struct list_head *head);取得节点指针:

    #define list_entry(ptr, type, member)

    ((type *)((char *)(ptr)-(unsigned lONg)(&((type *)0)->member)))遍历链表中每个节点:

    #define list_for_each(pos, head)

    for (pos = (head)->next, prefetch(pos->next); pos != (head);

    pos = pos->next, prefetch(pos->next))逆向循环链表中每个节点:

    #define list_for_each_prev(pos, head)

    for (pos = (head)->prev, prefetch(pos->prev); pos != (head);

    pos = pos->prev, prefetch(pos->prev))举例:LISH_HEAD(mylist);struct my_list{

    struct list_head list;

    int data;

    };stATIc int ini_list(void)

    {

    struct my_list *p;

    int i;

    for(i=0; i<100; i++){

    p=kmalLOC(sizeof(struct my_list), GFP_KERNEL);

    list_add(&p->list, &mylist);

    }

    }

    在内存中形成如下结构的一个双向链表:+---------------------------------------------------------------+

    | |

    | mylist 99 98 0 |

    | +----+ +---------+ +---------+ +---------+ |

    +->|next|--->|list.next|--->|list.next|--->...--->|list.next|---+

    |----| |---------| |---------| |---------|

    +--|prev|<---|list.prev|<---|list.prev|<---...<---|list.prev|<--+

    | +----+ |---------| |---------| |---------| |

    | | data | | data | | data | |

    | +---------+ +---------+ +---------+ |

    | |

    +---------------------------------------------------------------+知道了链表头就能遍历整个链表,如果是用list_add()插入新节点的话,从链表头的next方向看是一个堆栈型。从链表中删除节点很容易:staTIc void del_item(struct my_list *p)

    {

    list_del(&p->list, &mylist);

    kfree(p);

    }最重要的宏是list_entry,这个宏的思路是根据链表元素结构中链表头结构list_head的地址推算出链表元素结构的实际地址:#define list_entry(ptr, type, member)

    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))ptr是链表元素结构(如struct my_list)中链表头结构list_head的地址

    member是链表元素结构(如struct my_list)中链表头结构list_head参数的名称

    type是链表元素结构类型(如struct my_list)计算原理是根据链表头结构list_head的地址减去其在链表元素结构中的偏移位置而得到链表元素结构的地址。例如:static void print_list(void)

    {

    struct list_head *cur;

    struct my_list *p;list_for_each(cur, &mylist){

    p=list_entry(cur, struct my_list, list);

    printk("data=%dn", p->data);

    }

    }优点:这样就可以用相同的数据处理方式来描述所有双向链表,不用再单独为各个链表编写各种编辑函数。缺点:

    1) 链表头中元素置为NULL不是初始化,与普通习惯不同;

    2) 仍然需要单独编写各自的删除整个链表的函数,不能统一处理,因为不能保证所有链表元素结构中链表头结构list_head的偏移地址都是相同的,当然如果把链表头结构list_head都作为链表元素结构的第一个参数,就可以用统一的删除整个链表的函数。

    3. HASH表HASH表适用于不需要对整个空间元素进行排序,而是只需要能快速找到某个元素的场合,是一种以空间换时间的方法,本质也是线性表,但由一个大 的线性表拆分为了多个小线性表,由于只需要查找小表,因此搜索速度就会线性查整个大表提高很多,理想情况下,有多少个小线性表,搜索速度就提高了多少倍, 通常把小线性表的表头综合为一个数组,大小就是HASH表的数量。HASH表速度的关键是HASH函数的设计,HASH函数根据每个元素中固定的参数进行计算,算出一个不大于HASH表数量的索引值,表示该元 素需要放在该索引号对应的那个表中,对于固定的参数,计算结果始终是固定的,但对于不同的参数值,希望计算出来的结果能尽可能地平均到每个索引值, HASH函数计算得越平均,表示每个小表中元素的数量都会差不多,这样搜索性能将越好。HASH函数也要尽可能的简单,以减少计算时间,常用的算法是将参 数累加求模,在include/linux/jhash.h中已经定义了一些HASH计算函数,可直接使用。HASH表在路由cache表,状态连接表等处用得很多。举例,连接跟踪中根据tuple值计算HASH:// net/ipv4/netfiLTEr/ip_conntrack_core.cu_int32_t

    hash_conntrack(const struct ip_conntrack_tuple *tuple)

    {

    #if 0

    dump_tuple(tuple);

    #endif

    return (jhash_3words(tuple->SRC.ip,

    (tuple->dst.ip ^ tuple->dst.protonum),

    (tuple->src.u.all | (tuple->dst.u.all << 16)),

    ip_conntrack_hash_rnd) % ip_conntrack_htable_size);

    }// include/linux/jhash.h

    static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)

    {

    a += JHASH_GOLDEN_RATIO;

    b += JHASH_GOLDEN_RATIO;

    c += initval;__jhash_mix(a, b, c);return c;

    }4. 定时器(timer)linux内核定时器由以下结构描述:/* include/linux/timer.h */

    struct timer_list {

    struct list_head list;

    unsigned long expires;

    unsigned long data;

    void (*function)(unsigned long);

    };list:timer链表

    expires:到期时间

    function:到期函数,时间到期时调用的函数

    data:传给到期函数的数据,实际应用中通常是一个指针转化而来,该指针指向一个结构

    timer的操作:增加timer,将timer挂接到系统的timer链表:

    extern void add_timer(struct timer_list * timer);删除timer,将timer从系统timer链表中拆除:

    extern int del_timer(struct timer_list * timer);

    (del_timer()函数可能会失败,这是因为该timer本来已经不在系统timer链表中了,也就是已经删除过了)对于SMP系统,删除timer最好使用下面的函数来防止冲突:

    extern int del_timer_sync(struct timer_list * timer);修改timer,修改timer的到期时间:

    int mod_timer(struct timer_list *timer, unsigned long expires);通常用法:

    struct timer_list通常作为数据结构中的一个参数,在初始化结构的时候初始化timer,表示到期时要进行的操作,实现定时动作,通常更多的是作为超时 处理的,timer函数作为超时时的资源释放函数。注意:如果超时了运行超时函数,此时系统是处在时钟中断的bottom half里的,不能进行很复杂的操作,如果要完成一些复杂操作,如到期后的数据发送,不能直接在到期函数中处理,而是应该在到期函数中发个信号给特定内核 线程转到top half进行处理。为判断时间的先后,内核中定义了以下宏来判断:#define time_after(a,b) ((long)(b) - (long)(a) < 0)

    #define time_before(a,b) time_after(b,a)#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0)

    #define time_before_eq(a,b) time_after_eq(b,a)这里用到了一个技巧,由于linux中的时间是无符号数,这里先将其转换为有符号数后再判断,就能解决时间回绕问题,当然只是一次回绕,回绕两次当然是判断不出来的,具体可自己实验体会。5. 内核线程(kernel_thread)内核中新线程的建立可以用kernel_thread函数实现,该函数在kernel/fork.c中定义:long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)fn:内核线程主函数;

    arg:线程主函数的参数;

    flags:建立线程的标志;内核线程函数通常都调用daemonize()进行后台化作为一个独立的线程运行,然后设置线程的一些参数,如名称,信号处理等,这也不是必须 的,然后就进入一个死循环,这是线程的主体部分,这个循环不能一直在运行,否则系统就死在这了,或者是某种事件驱动的,在事件到来前是睡眠的,事件到来后 唤醒进行操作,操作完后继续睡眠;或者是定时睡眠,醒后操作完再睡眠;或者加入等待队列通过schedule()调度获得执行时间。总之是不能一直占着 CPU。以下是内核线程的一个实例,取自kernel/context.c:int start_context_thread(void)

    {

    static struct completion startup __initdata = COMPLETION_INITIALIZER(startup);kernel_thread(context_thread, &startup, CLONE_FS | CLONE_FILES);

    wait_for_completion(&startup);

    return 0;

    }static int context_thread(void *startup)

    {

    struct task_struct *curtask = current;

    DECLARE_WAITQUEUE(wait, curtask);

    struct k_sigaction sa;daemonize();

    strcpy(curtask->comm, "keventd");

    keventd_running = 1;

    keventd_task = curtask;sPIN_lock_IRQ(&curtask->sigmask_lock);

    siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));

    recalc_sigpending(curtask);

    spin_unlock_irq(&curtask->sigmask_lock);complete((struct completion *)startup);/* Install a handler so SIGCLD is delivered */

    sa.sa.sa_handler = SIG_IGN;

    sa.sa.sa_flags = 0;

    siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));

    do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);/*

    * If one of the functions on a task queue re-adds itself

    * to the task queue we call schedule() in state TASK_RUNNING

    */

    for (;;) {

    set_task_state(curtask, TASK_INTERRUPTIBLE);

    add_wait_queue(&context_task_wq, &wait);

    if (TQ_ACTIVE(tq_context))

    set_task_state(curtask, TASK_RUNNING);

    schedule();

    remove_wait_queue(&context_task_wq, &wait);

    run_task_queue(&tq_context);

    wake_up(&context_task_done);

    if (signal_pending(curtask)) {

    while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)

    ;

    spin_lock_irq(&curtask->sigmask_lock);

    flush_signals(curtask);

    recalc_sigpending(curtask);

    spin_unlock_irq(&curtask->sigmask_lock);

    }

    }

    }6. 结构地址在C中,结构地址和结构中第一个元素的地址是相同的,因此在linux内核中经常出现使用结构第一个元素的地址来表示结构地址的情况,在读代码时要注意这一点,这和list_entry宏的意思一样。如:

    struct my_struct{

    int a;

    int b;

    }c;if(&c == &c.a){ // always true

    ...

    }


【看看这篇文章在百度的收录情况】

相关文章

联系方式

  • 0731-85579057 , 0731-85569651
  • 点击这里给我发消息点击这里给我发消息点击这里给我发消息
网站栏目导航: 培训课程 手机硬件 手机软件 综合维修 学校资讯 考证指南 就业导航 招生指南 教学管理 入学须知 学校图片 教学大纲 师资力量 学生感言 学校概况 教学实景 手机维修培训资讯 电脑维修培训 维修间故事 手机维修培训 液晶电视维修培训 家电维修资料网 电器维修资料网 招生地区 刷机教程 家电维修 手机技巧 老版网站 招生平台网络工程
友情链接: 监控安装培训 电动工具维修 家电维修学校 电工培训学校 液晶电视维修 焊工培训学校 电工焊工学校 电脑维修学校 家电维修培训 电脑维修培训 家装电工培训网络安装维护 主板维修 液晶显示器 笔记本电脑维修 电脑组装维护 电脑硬件维修 电脑维修 电工考证 电工证 装修电工 水电工 维修电工 电工 焊接技术 电焊工 焊工 电动设备维修 电动工具维修 制冷维修 空调维修 冰箱维修  更多>>
阳光-手机维修教育品牌学校
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校 电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校 电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校 电工培训学校 电动车维修学校 摩托车维修学校 摩托车维修培训 手机维修培训 家电维修培训 电脑维修培训 电动工具维修培训 液晶电视维修培训 安防监控培训 空调维修培训 网络营销培训 网站设计培训 淘宝网店培训 电器维修培训 家电维修学校 电工培训 焊工培训 电工学校
中山市,固原市,银川市,玉树,海东,陇南市,酒泉市,张掖市,天水市,金昌市,兰州市,榆林市,延安市,渭南市,铜川市,阿里,山南,拉萨市,怒江,文山州,楚雄州,普洱市,昭通市,玉溪市,昆明市,毕节,铜仁,遵义市,贵阳市,甘孜州,资阳市,达州市,宜宾市,南充市,遂宁市,绵阳市,泸州市,自贡市,三亚市,崇左市,河池市,玉林市,钦州市,梧州市,柳州市,梅州市,肇庆市,湛江市,佛山市,珠海市,韶关市,湘西州,怀化市,郴州市,张家界市,邵阳市,株洲市,仙桃市,随州市,荆州市,荆门市,襄樊市,黄石市,驻马店市,信阳市,南阳市,漯河市,中卫市,石嘴山市,海西,海南藏州,黄南州,海北,甘南,庆阳市,平凉市,武威市,白银市,嘉峪关市,安康市,汉中市,咸阳市,宝鸡市,林芝,日喀则,昌都,迪庆,德宏,大理,西双版纳,红河州,临沧市,丽江市,保山市,曲靖市,黔东州,黔西州,安顺市,六盘水市,凉山州,阿坝州,雅安市,广安市,眉山市,内江市,广元市,德阳市,攀枝花市,成都市,海口市,来宾市,百色市,贵港市,北海市,桂林市,南宁市,云浮市,揭阳市,潮州市,清远市,阳江市,汕尾市,惠州市,茂名市,江门市,汕头市,深圳市,广州市,娄底市,永州市,益阳市,岳阳市,湘潭市,长沙市,恩施州,黄冈市,孝感市,鄂州市,十堰市,武汉市,周口市,商丘市,三门峡市,许昌市,焦作市,安阳市,鹤壁市,平顶山市,开封市,郑州市,聊城市,滨州市,德州市,莱芜市,日照市,泰安市,烟台市,潍坊市,东营市,淄博市,上饶市,济南市,抚州市,宜春市,赣州市,新余市,九江市,景德镇市,宁德市,南平市,泉州市,莆田市,厦门市,宣城市,亳州市,六安市,宿州市,黄山市,滁州市,安庆市,淮北市,马鞍山市,蚌埠市,芜湖市,合肥市,丽水市,舟山市,衢州市,金华市,湖州市,嘉兴市,宁波市,宿迁市,镇江市,盐城市,连云港市,苏州市,徐州市,南京市,绥化市,牡丹江市,佳木斯市,大庆市,鹤岗市,哈尔滨市,白城市,白山市,辽源市,吉林市,葫芦岛市,铁岭市,盘锦市,阜新市,锦州市,本溪市,鞍山市,沈阳市,锡林郭勒盟,通辽市,乌海市,吕梁市,忻州市,晋中市,晋城市,阳泉市,太原市,廊坊市,承德市,保定市,邯郸市,唐山市,宁夏,甘肃省,西藏,贵州省,重庆市,广西,湖南省,河南省,江西省,安徽省,江苏省,黑龙江省,辽宁省,山西省,天津市,四平市,内蒙古,吴忠市,果洛,西宁市,定西市,商洛市,西安市,那曲,黔南州,巴中市,乐山市,贺州市,防城港市,东莞市,河源市,常德市,衡阳市,咸宁市,宜昌市,濮阳市,新乡市,洛阳市,菏泽市,临沂市,威海市,济宁市,枣庄市,青岛市,吉安市,鹰潭市,萍乡市,南昌市,龙岩市,漳州市,三明市,福州市,池州市,巢湖市,阜阳市,铜陵市,淮南市,台州市,绍兴市,温州市,杭州市,泰州市,扬州市,淮安市,南通市,常州市,无锡市,大兴安岭,黑河市,七台河市,伊春市,双鸭山市,鸡西市,齐齐哈尔市,延边,松原市,通化市,长春市,朝阳市,辽阳市,营口市,丹东市,抚顺市,大连市,阿拉善盟,兴安盟,乌兰察布市,巴彦淖尔市,呼伦贝尔市,鄂尔多斯市,赤峰市,包头市,呼和浩特市,临汾市,运城市,朔州市,长治市,大同市,衡水市,沧州市,张家口市,邢台市,秦皇岛市,石家庄市,青海省,陕西省,云南省,四川省,海南省,广东省,湖北省,山东省,福建省,浙江省,上海市,吉林省,河北省,北京市