2024年9月linux内核设计与实现(学习linux内核,请推荐几本书及顺序,谢谢)

 更新时间:2024-09-21 08:40:00

  ⑴linux内核设计与实现(学习linux内核,请推荐几本书及顺序,谢谢

  ⑵学习linux内核,请推荐几本书及顺序,谢谢

  ⑶linux内核最经典的书是《深入理解Linux内核》,这本书内核编程看;如果你是搞UNIX/Linux环境下的应用程序编程,那么就看《UNIX环境高级编程》;如果做Linux下设备驱动程序开发,就看《Linux设备驱动》(第三版。这几本都是老外写的,都是很经典的书。

  ⑷linuxkernel的四库全书是哪四个

  ⑸LinuxKernel四库全书.Linux内核设计与实现Edition.Linux设备驱动Edition.Linux内核源代码情景分析.深入理解Linux内核(第三版.LINUXKERNEL技术手册;LINUXKERNELinanutshell;Linux内核驱动和应用程序开发QQ群:,欢迎交流讨论;Linux内核设计与实现原书名:LinuxKernelDevelopment(ndEdition)原出版社:NovellPress作者:(美RobertLove译者:陈莉君康华张波出版社:机械工业出版社ISBN:出版日期:年月页码:LinuxDeviceDrivers,rdEditionByJonathanCorbet,GregKroah-Hartman,AlessandroRubiniPublisher:O’ReillyPubDate:FebruaryPages:LINUX设备驱动程序(第版)译者:魏永明,耿岳,钟书毅出版社:中国电力出版社;出版日期:年月日平装:页LINUX内核源代码情景分析作者:毛德操,胡希明出版社:浙江大学出版社;出版日期:年月日平装:页ISBN:深入理解Linux内核UnderstandingtheLinuxKernel,rdEditionByDanielP.Bovet,MarcoCesatiPublisher:O’ReillyPubDate:NovemberISBN:---Pages:作者美博韦,西斯特著,陈莉君,张琼声,张宏伟译出版社:中国电力出版社出版时间:出版时间:--ISBN:LINUXKERNEL技术手册;LINUXKERNELinanutshell;作者:(美哈特曼著出版社:东南大学出版社出版时间:--页数:ISBN:

  ⑹对待知识领域,我们总喜欢去下一个定义。操作系统是我们每天工作都要使用的东西,由于现代商业操作系统的复杂性和没有统一的标准,若对一个操作系统下定义并不能精确的描述操作系统所属领域。根据经验我们可以认为操作系统就是在整个应用系统中负责最基本功能和系统管理的那部分。包括内核、设备驱动程序、启动引导程序、命令行Shell或者GUI界面、基本文件管理工具和系统工具。

  ⑺严格的来讲linux只是操作系统内核本身,广义上的linux则常用来指基于linux内二的完整的操作系统,它包括GUI组件和其它许多工具。

  ⑻GUI其实只是操作系统的表象,内核才是操作系统内在的核心。系统的其它部分必须依靠内核所提供的服务,像管理硬件设备、分配系统资源等,内核有时候被称为管理者或者操作系统核心。

  ⑼通常一个内核由负责响应中断的中断服务程序,负责进程调度的CPU调度程序,负责管理进程地址空间的内存管理程序以及网络、进程间通信等系统服务共同组成的。

  ⑽内核在有安全机制的操作系统中不同于普通程序,一般处于系统态(内核态),拥有受保护的内存空间和访问硬件设备的所有权限。这种系统状态和被保护起来的内存空间,统称为内核空间。

  ⑾与内核空间相对的,用户所执行的应用程序在用户空间执行。用户态的应用程序只能访问允许它们使用的系统资源,并且只使用某些特定的系统功能,不能直接访问硬件,也不能访问内核划分给其它应用程序的内存空间。

  ⑿应用程序通过系统调用来和内核通信,当一个应用程序发起系统调用时,内核便代其执行。在这种情况下应用程序通过系统调用在内核空间运行,而内核被称为运行在进程上下文中。应用程序通过系统调用进入内核空间时应用完成其工作的基本方式。

  ⒀操作系统内核可分为两大阵营:单内核和微内核。

  ⒁单内核是一种较为简单的设计,通常以单个静态二进制文件存储在磁盘中,整体上作为一个单独的大过程,所有的内核服务都在这样的一个大内核地址空间上运行。内核服务都处于内核态,并身处同一内核地址空间,之间可以几乎无性能损耗的相互通信。

  ⒂单内核具有简单和高性能等特点。

  ⒃微内核根据功能被分割成多个独立的过程,每个过程都叫做一个服务器。所有的服务器都运行在各自的地址空间上(大部分处于用户空间,只有强烈请求特权服务的服务器才运行在特权模式下。

  ⒄微内核服务器之间不能直接调用函数通信,而是通过消息传递通信。系统采用进程间通信(IPC)机制,服务之间各自独立,通过IPC互换消息,有效的避免了服务之间的失败传染。

  ⒅IPC机制的开销远高于函数调用,而且在运行时还会牵扯到内核空间和用户空间上下文切换,所以消息传递需要一些开销。所以在内核的实际实现上大部分微内核的操作系统也会让大部分的服务放置与内核中,这样就可以直接调用函数,消除消息传递的开销。

  ⒆windowsNT和Mach(MacOSX)都是典型的微内核,不过在实际实现上,其所有服务都运行在内核空间。

  ⒇linux是一个单内核,不过linux汲取了微内核的精华,并拥有模块化设计、抢占式内核、支持内核线程以及动态装载内核模块等特性。

  ⒈linux内核在设计时充分参考了已有的很多UNIX的内核实现,并且有一些创新方案。linux内核和传统的UNIX系统之间存在一些显著的差异:

  ⒉本文的写作和学习中参考了以下资料.《LinuxKenelDevelopment~ThridEdition》

  ⒊linux内核同步问题

  ⒋Linux内核设计与实现十、内核同步方法

  ⒌手把手教Linux驱动-自旋锁、信号量、互斥体概述

  ⒍并发:多个执行单元同时进行或多个执行单元微观串行执行,宏观并行执行

  ⒎竞态:并发的执行单元对共享资源(硬件资源和软件上的全局变量的访问而导致的竟态状态。

  ⒏临界资源:多个进程访问的资源

  ⒐临界区:多个进程访问的代码段

  ⒑单CPU之间进程间的并发:时间片轮转,调度进程。A进程访问打印机,时间片用完,OS调度B进程访问打印机。

  ⒒单cpu上进程和中断之间并发:CPU必须停止当前进程的执行中断;

  ⒓单CPU上中断之间的并发

  ⒔==信号量用于进程之间的同步,进程在信号量保护的临界区代码里面是可以睡眠的(需要进行进程调度,这是与自旋锁最大的区别。==

  ⒕信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存的存取状况。它负责协调各个进程,以保证他们能够正确、合理的使用公共资源。它和spinlock最大的不同之处就是:无法获取信号量的进程可以睡眠,因此会导致系统调度。

  ⒖==用于进程与进程之间的同步==

  ⒗==允许多个进程进入临界区代码执行,临界区代码允许睡眠;==

  ⒘信号量本质是==基于调度器的==,在UP和SMP下没有区别;进程获取不到信号量将陷入休眠,并让出CPU;

  ⒙不支持进程和中断之间的同步

  ⒚==进程调度也是会消耗系统资源的,如果一个int型共享变量就需要使用信号量,将极大的浪费系统资源==

  ⒛信号量可以用于多个线程,用于资源的计数(有多种状态

  ==信号量加锁以及解锁过程:==

  sema_init(&sp-》dead_sem,);/初始化/

  down(&sema);

  up(&sema);

  ==信号量定义:==

  ==信号量初始化:==

  ==dowm函数实现:==

  ==up函数实现:==

  信号量一般可以用来标记可用资源的个数。

  ==dowm函数实现原理解析:==

  判断sem-》count是否》,大于则说明系统资源够用,分配一个给该进程,否则进入__down(sem);

  调用__down_mon(sem,TASK_UNINTERRUPTIBLE,MAX_SCHEDULE_TIMEOUT);其中TASK_UNINTERRUPTIBLE=代表进入睡眠,且不可以打断;MAX_SCHEDULE_TIMEOUT休眠最长LONG_MAX时间;

  list_add_tail(&waiter.list,&sem-》wait_list);

  把当前进程加入到sem-》wait_list中;

  进入__down_mon前已经加锁了,先把解锁,调用schedule_timeout(timeout),当waiter.up=后跳出for循环;退出函数之前再加锁;

  Linux内核ARM构架中原子变量的底层实现研究

  rk原子操作和原子位操作

  原子变量适用于只共享一个int型变量;

  原子操作是指不被打断的操作,即它是最小的执行单位。

  最简单的原子操作就是一条条的汇编指令(不包括一些伪指令,伪指令会被汇编器解释成多条汇编指令)

  ==以atomic_inc为例介绍实现过程==

  在Linux内核文件archarmincludeasmatomic.h中。执行atomic_read、atomic_set这些操作都只需要一条汇编指令,所以它们本身就是不可打断的。需要特别研究的是atomic_inc、atomic_dec这类读出、修改、写回的函数。

  所以atomic_add的原型是下面这个宏:

  atomic_add等效于:

  result(%tmp(%(v-》counter)(%(&v-》counter)(%i(%

  注意:根据内联汇编的语法,result、tmp、&v-》counter对应的数据都放在了寄存器中操作。如果出现上下文切换,切换机制会做寄存器上下文保护。

  意思是将&v-》counter指向的数据放入result中,并且(分别在Localmonitor和Globalmonitor中设置独占标志。

  result=result+i

  意思是将result保存到&v-》counter指向的内存中,此时Exclusivemonitors会发挥作用,将保存是否成功的标志放入tmp中。

  测试strex是否成功(tmp==??

  如果发现strex失败,从(再次执行。

  Spinlock是内核中提供的一种比较常见的锁机制,==自旋锁是“原地等待”的方式解决资源冲突的==,即,一个线程获取了一个自旋锁后,另外一个线程期望获取该自旋锁,获取不到,只能够原地“打转”(忙等待。由于自旋锁的这个忙等待的特性,注定了它使用场景上的限制——自旋锁不应该被长时间的持有(消耗CPU资源,一般应用在==中断上下文==。

  spinlock是一种死等机制

  信号量可以允许多个执行单元进入,spinlock不行,一次只能允许一个执行单元获取锁,并且进入临界区,其他执行单元都是在门口不断的死等

  由于不休眠,因此spinlock可以应用在中断上下文中;

  由于spinlock死等的特性,因此临界区执行代码尽可能的短;

  ==spinlock加锁以及解锁过程:==

  spin_lock(&devices_lock);

  spin_unlock(&devices_lock);

  ==spinlock初始化==

  ==进程和进程之间同步==

  ==本地软中断之间同步==

  ==本地硬中断之间同步==

  ==本地硬中断之间同步并且保存本地中断状态==

  ==arch_spinlock_t结构体定义如下:==

  ==arch_spin_lock的实现如下:==

  lockval(%newval(%tmp(%&lock-》slock(%《《TICKET_SHIFT(%

  把lock-》slock的值赋值给lockval;并且(分别在Localmonitor和Globalmonitor中设置独占标志。

  newval=lockval+(《《;相当于next+;

  newval=lockval+(《《;相当于next+;

  意思是将newval保存到&lock-》slock指向的内存中,此时Exclusivemonitors会发挥作用,将保存是否成功的标志放入tmp中。

  测试strex是否成功

  如果发现strex失败,从(再次执行。

  通过上面的分析,可知关键在于strex的操作是否成功的判断上。而这个就归功于ARM的Exclusivemonitors和ldrex/strex指令的机制。

  while(lockval.tickets.next!=lockval.tickets.owner)

  如何lockval.tickets的next和owner是否相等。相同则跳出while循环,否则在循环内等待判断;

  *(wfe()和smp_mb()最终调用#definebarrier()asmvolatile(““:::“memory“)*

  阻止编译器重排,保证编译程序时在优化屏障之前的指令不会在优化屏障之后执行。

  ==arch_spin_unlock的实现如下:==

  退出锁时:tickets.owner++

  ==出现死锁的情况:==

  拥有自旋锁的进程A在内核态阻塞了,内核调度B进程,碰巧B进程也要获得自旋锁,此时B只能自旋转。而此时抢占已经关闭,(单核不会调度A进程了,B永远自旋,产生死锁。

  进程A拥有自旋锁,中断到来,CPU执行中断函数,中断处理函数,中断处理函数需要获得自旋锁,访问共享资源,此时无法获得锁,只能自旋,产生死锁。

  ==如何避免死锁:==

  如果中断处理函数中也要获得自旋锁,那么驱动程序需要在拥有自旋锁时禁止中断;

  自旋锁必须在可能的最短时间内拥有

  避免某个获得锁的函数调用其他同样试图获取这个锁的函数,否则代码就会死锁;不论是信号量还是自旋锁,都不允许锁拥有者第二次获得这个锁,如果试图这么做,系统将挂起;

  锁的顺序规则(a)按同样的顺序获得锁;b)如果必须获得一个局部锁和一个属于内核更中心位置的锁,则应该首先获取自己的局部锁;c)如果我们拥有信号量和自旋锁的组合,则必须首先获得信号量;在拥有自旋锁时调用down(可导致休眠)是个严重的错误的;

  ==rw(read/writespinlock:==

  假设临界区内没有任何的thread,这个时候任何的读线程和写线程都可以键入

  假设临界区内有一个读线程,这时候信赖的read线程可以任意进入,但是写线程不能进入;

  假设临界区有一个写线程,这时候任何的读、写线程都不可以进入;

  假设临界区内有一个或者多个读线程,写线程不可以进入临界区,但是写线程也无法阻止后续的读线程继续进去,要等到临界区所有的读线程都结束了,才可以进入,可见:==rw(read/writespinlock更加有利于读线程;==

  ==seqlock(顺序锁:==

  假设临界区内没有任何的thread,这个时候任何的读线程和写线程都可以键入

  假设临界区内没有写线程的情况下,read线程可以任意进入;

  假设临界区有一个写线程,这时候任何的读、写线程都不可以进入;

  假设临界区内只有read线程的情况下,写线程可以理解执行,不会等待,可见:==seqlock(顺序锁更加有利于写线程;==

  读写速度:CPU》一级缓存》二级缓存》内存,因此某一个CPU的lock修改了,其他的CPU的lock就会失效;那么其他CPU就会依次去LL和主存中读取lock值,一旦其他CPU去读取了主存,就存在系统性能降低的风险;

  mutex用于互斥操作。

  互斥体只能用于一个线程,资源只有两种状态(占用或者空闲

  mutex的语义相对于信号量要简单轻便一些,在锁争用激烈的测试场景下,mutex比信号量执行速度更快,可扩展

  另外mutex数据结构的定义比信号量小;、

  同一时刻只有一个线程可以持有mutex

  不允许递归地加锁和解锁

  当进程持有mutex时,进程不可以退出。

  ?mutex必须使用官方API来初始化。

  ?mutex可以睡眠,所以不允许在中断处理程序或者中断下半部中使用,例如tasklet、定时器等

  structmutexmutex_;

  mutex_init(&mutex_);

  mutex_lock(&mutex_)

  mutex_unlock(&mutex_)

  Linux该怎么入门呢

  入门的话找本不用太厚,你能看懂的书来学习,再厚你看不懂,掌握不了方法也是白搭。我看过同事以前培训教材,某某青鸟的linux书,里面是关于Centos系统的一些介绍,基本上都是简单易学,学习一些方法还是可以的。但是要注意Centos以后的命令语法,有部分改变了不少,甚至完全不太一样,建议从开始学吧。另外就是对着书不停地练习,不管是学习使用命令,还是修改配置文档,过程中会遇到各种各样的问题,遇到问题解决问题,不管是翻书还是网上百度,直到把问题解决了,掌握的知识点要做好笔记,不断地积累,学习一段时间,你就会感觉即使用遇到新问题都有办法解决。linux种类有不少,Centos是跟redhand有点类似的,其它的还有ubuntu,debian,国产的还有UOS,deepin等等,基本命令都差不多,也有些是自身系统特定的格式,不过都差不多。看你只是学习,还是以后工作也要使用的,找一个适合自己的来入门。

您可能感兴趣的文章:

相关文章