Chinaunix首页 | 论坛 | 博客
  • 博客访问: 157507
  • 博文数量: 129
  • 博客积分: 125
  • 博客等级: 入伍新兵
  • 技术积分: 670
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-17 16:37
文章分类

全部博文(129)

文章存档

2013年(12)

2012年(117)

我的朋友

分类:

2012-07-19 17:30:06

原文地址:浅析理解__init宏 作者:emmoblin

浅析理解__init

kernel中有很多__init,下面是其定义:
file:/include/linux/init.h
 43 #define __init      __attribute__ ((__section__ (".init.text"))) __cold
 44 #define __initdata  __attribute__ ((__section__ (".init.data")))
 45 #define __exitdata  __attribute__ ((__section__(".exit.data")))
 46 #define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))

 

关于__attribute__ ((__section__ (".init.text"))) __cold的作用,参考 info gcc C Extensions Attribute Syntax

简单来说是告诉连接器把标记的数据或者函数放到指定段。
linux
中把一些启动及初始化时候用的数据用__init标识,然后在适当的时候把它们释放,回收内存。因为初始化初始化一次后就没有用了,这部分内存可以释放了。
说到这个__init,就不能不说module_initsubsys_initcall
init.h中我们能够找到 #define subsys_initcall(fn)     __define_initcall("4",fn,4)

file:/include/linux/init.h

110 #define __define_initcall(level,fn,id) \
111     static initcall_t __initcall_##fn##id __attribute_used__ \
112     __attribute__((__section__(".initcall" level ".init"))) = fn


subsys_initcall(usb_init)

转换后就变成了 static initcall_t  __initcall_usbinit4   __attribute_used__ \
__attribute__((__section__(".initcall 4.init"))) = usb_init
就是把usb_init的函数入口指针存放在.initcall4.init中。
file:/include/asm-generic/vmlinux.lds.h
239 #define INITCALLS                           \
240     *(.initcall0.init)                      \
241     *(.initcall0s.init)                     \
242     *(.initcall1.init)                      \
243     *(.initcall1s.init)                     \
244     *(.initcall2.init)                      \
245     *(.initcall2s.init)                     \
246     *(.initcall3.init)                      \
247     *(.initcall3s.init)                     \
248     *(.initcall4.init)                      \
249     *(.initcall4s.init)                     \
250     *(.initcall5.init)                      \
251     *(.initcall5s.init)                     \
252     *(.initcallrootfs.init)                     \
253     *(.initcall6.init)                      \
254     *(.initcall6s.init)                     \
255     *(.initcall7.init)                      \
256     *(.initcall7s.init)


file:/arch/kernel/vmlinux_32.lds.S
144   .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
145     __initcall_start = .;
146     INITCALLS
147     __initcall_end = .;
148   }

系统是如何执行这些函数呢?
进入start_kernel
start_kernel  -->rest_init() -->kernel_init()  --> do_basic_setup()  -->do_initcalls()

这个do_initcalls()就是调用这些函数的地方。
file:/init/main.c
662 static void __init do_initcalls(void)
663 {
664     initcall_t *call;
665     int count = preempt_count();
666
667    
for (call = __initcall_start; call < __initcall_end; call++) {
668         ktime_t t0, t1, delta;
669         char *msg = NULL;
670         char msgbuf[40];
671         int result;
672
673         if (initcall_debug) {
674             printk("Calling initcall 0x%p", *call);
675             print_fn_descriptor_symbol(": %s()",
676                     (unsigned long) *call);
677             printk("\n");
678             t0 = ktime_get();
679         }
680
681        
result = (*call)();
682
683         if (initcall_debug) {
684             t1 = ktime_get();
685             delta = ktime_sub(t1, t0);
686
687             printk("initcall 0x%p", *call);
688             print_fn_descriptor_symbol(": %s()",
689                     (unsigned long) *call);
690             printk(" returned %d.\n", result);
691
692             printk("initcall 0x%p ran for %Ld msecs: ",
693                 *call, (unsigned long long)delta.tv64 >> 20);
694             print_fn_descriptor_symbol("%s()\n",
695                 (unsigned long) *call);
696         }
697
698         if (result && result != -ENODEV && initcall_debug) {
699             sprintf(msgbuf, "error code %d", result);
700             msg = msgbuf;
701         }
702         if (preempt_count() != count) {
703             msg = "preemption imbalance";
704             preempt_count() = count;
705         }
706         if (irqs_disabled()) {
707             msg = "disabled interrupts";
708             local_irq_enable();
709         }
710         if (msg) {
711             printk(KERN_WARNING "initcall at 0x%p", *call);
712             print_fn_descriptor_symbol(": %s()",
713                     (unsigned long) *call);
714             printk(": returned with %s\n", msg);
715         }
716     }
717
718     /* Make sure there is no pending stuff from the initcall sequence */
719     flush_scheduled_work();
720 }

阅读(464) | 评论(0) | 转发(0) |
0

上一篇:list_entry()宏

下一篇:给模块传递参数

给主人留下些什么吧!~~