Linux学习笔记-内核篇

1.Linux内核介绍

操作系统:操作系统是指在整个系统中负责完成最基本功能和系统管理的那些部分,这些部分应该包括内核,设备驱动程序,启动引动程序,命令行shell或者其他种类的用户界面,基本的文件管理工具和系统工具。

 

内核空间:系统态:拥有受保护的内存空间和访问硬件的所有权限。这种系统态和被保护起来的空间统称为内核空间。

 

用户空间:普通应用程序所运行的空间。它们只能看到允许它们使用的 部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,还有一些其他限制。

 

我们可以将处理器在任何时间点上的活动范围概括为下列三者之一:
1.运行于内核空间,进程上下文,代表某个特定的进程执行。

2.运行于内核空间,中断上下文,代表某个特定的中断执行。

3.运行于用户空间,执行用户进程。

当CPU处于空闲时,会在内核运行一个空进程,为进程上下文,但是运行在内核空间。

 

Linux内核与unix各种变体的内核特点分析比较:

1.Linux支持动态加载内核模块,尽管Linux内核也是单内核,但是可以在需要时加载或者卸载部分内核代码。

2.Linux支持对称多处理(SMP)机制,尽管许多Unix的变体也支持,但是传统的UNIX并不支持。

3.Linux内核可以根据优先级进行抢占。

4.Linux对线程的支持实现比较有意思:内核并不区分线程和其他一般的线程,对于内核来说,所有的进程都一样,只不过其中的一些共享资源而已。

5.Linux提供具有设备类的面向对象的设备模型,热插拔事件,以及用户空间的设备文件系统(sysfs).

6.Linux忽略了一些被认为设计的很拙劣的UNIX特性,像STREAMS,他还忽略了那些实际上已经根本不会使用的过时标准。

7.Linux体现了自由这个字的精髓,现有的Linux特性集就是Linux公开开发模型自由发展的结果。

 

内核开发与应用开发的区别:

1.内核编程时不能访问C库。

2.内核编程时必须使用GNU C。

3.内核编程时缺乏像用户空间那样的内存保护机制。

4.内核编程时浮点数很难使用。

5.内核只有一个很小的定长堆栈。

6.由于内核支持异步中断,抢占和SMP,因此必须时刻注意同步和并发。

7.要考虑可移植性地重要性。

 

C库太大了,因此一个小小的子集内核空间都受不了,但是很多常用的C函数都被包含在内核文件夹下。

 

printk函数负责把格式化好的字符串拷贝到内核日志缓冲区上,这样,syslog程序就可以通过读取该缓冲区来获取内核信息,和Printf的区别在于printk允许通过指定一个标志来设置优先级,syslog会根据这个优先级来决定在什么地方显示这条系统消息。

Eg. Printk(KERN_ERR "this is an error!\n");

 

GUN  C特性

1.内联函数:Inline

函数会在它调用的位置上展开。这么做可以消除函数调用和返回带来的开销。通常把那些对时间要求比较高,而本身长度又比较短的函数定义成内联函数。定义一个内联函数必须以static来限定它。

 

 

2.内联汇编

Gcc 编译器支持在C函数中嵌入汇编指令。Linux的内核混合使用了C和汇编语言,在偏近体系结构的底层或对执行时间要求严格的地方,一般使用的是汇编语言,其他大部分是用C语言写的。

 

 

3.分支声明

 

unlikely和likely,用于声明选择结构是否有分支。

比如  if(unlikely(foo)){

};

 4.没有内存保护机制

用户程序试图进行非法的内存访问时,内核会发现这个错误。并且发送SIGSEGV,并且结束整个进程,然而如果是内核自己访问就没人能管了。

 

5.不能再内核中使用浮点数

 

 

6.容积小而固定的栈

用户空间的栈本身比较大,甚至还能动态增长,但是内核不行。

32位机的内核栈是8KB,64位机是16KB,这是固定不变的,每个处理器都有自己的栈。

 

7.同步和并发

内核很容易产生竞争条件,内核的许多特性都要求能够并发的访问共享数据,,这就要求有同步机制保证不出现竞争条件,尤其是:

1.Linux是抢占多任务操作系统,内核的进程调度程序即兴对进程进行调度和重新调度,内核必须对这样任务同步。

2.Linux是内核支持多处理器系统。所以,如果没有适当的保护,在两个或两个以上的处理器上运行的代码很可能会同时访问共享的同一个资源。

3.中断异步的到来。

4.内核可以被抢占。

常用的解决竞争的办法是自旋锁和信号量。

自旋锁实际上就是忙等锁,如果任务一直没有结束,CPU就会一直等自旋锁解锁。

自旋锁可能导致系统死锁。引发这个问题最常见的情况是递归使用一个自旋

锁,即如果一个已经拥有某个自旋锁的CPU 想第二次获得这个自旋锁,则

该CPU 将死锁。此外,如果进程获得自旋锁之后再阻塞,也有可能导致死

锁的发生。copy_from_user()、copy_to_user()和kmalloc()等函数都有可能引

起阻塞,因此在自旋锁的占用期间不能调用这些函数。

从严格意义上说,信号量和自旋锁属于不同层次的互斥手段,前者的实现依

赖于后者。在信号量本身的实现上,为了保证信号量结构存取的原子性,在多

CPU中需要自旋锁来互斥。

信号量是进程级的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是

该内核执行路径是以进程的身份,代表进程来争夺资源的。如果竞争失败,会发生进

程上下文切换,当前进程进入睡眠状态,CPU将运行其他进程。鉴于进程上下文切换

的开销也很大,因此,只有当进程占用资源时间较长时,用信号量才是较好的选择。

当所要保护的临界区访问时间比较短时,用自旋锁是非常方便的,因为它节省上

下文切换的时间。但是CPU得不到自旋锁会在那里空转直到其他执行单元解锁为止,

所以要求锁不能在临界区里长时间停留,否则会降低系统的效率。

由此,可以总结出自旋锁和信号量选用的3 项原则。

1.当锁不能被获取时,使用信号量的开销是进程上下文切换时间Tsw,使用自

旋锁的开销是等待获取自旋锁(由临界区执行时间决定)Tcs,若Tcs 比较小,

应使用自旋锁,若Tcs很大,应使用信号量。

2. 信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避免

用来保护包含这样代码的临界区。因为阻塞意味着要进行进程的切换,如果

进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发生。

3.信号量存在于进程上下文,因此,如果被保护的共享资源需要在中断或软中

断情况下使用,则在信号量和自旋锁之间只能选择自旋锁。当然,如果一定

要使用信号量,则只能通过down_trylock()方式进行,不能获取就立即返回

以避免阻塞。

 

并发和竞态广泛存在,中断屏蔽、原子操作、自旋锁和信号量都是解决并发问题

的机制。中断屏蔽很少单独被使用,原子操作只能针对整数进行,因此自旋锁和信号

量应用最为广泛。

自旋锁会导致死循环,锁定期间不允许阻塞,因此要求锁定的临界区小。信号量

允许临界区阻塞,可以适用于临界区大的情况。

读写自旋锁和读写信号量分别是放宽了条件的自旋锁和信号量,它们允许多个执

行单元对共享资源的并发读。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值