线程推行完事后就能脱离,都会自动创键U盘的设施节点/dev/sda%d

反向替换

图片 1

  若想求解,就务须去掉根号,但是未来发觉没办法用以往的学问求解了。

  以后尝试求助于三角函数。在上篇小说中,大家关系:

图片 2

  那刚刚契合根号下的表明式。现在令 x =
tanθ,则:

图片 3

  在三角函数中,独有sin和cos是相比较和煦的,别的都以变态。所以除非一眼能收看哪些简化,不然应当把持有项都写成sin和cos的花样。

图片 4

  已经济体改为熟习的三角形函数积分了。

图片 5

  未来的主题材料是哪些将θ调换为x。那需必要助于三角函数的几何意义,实际中元经应用过频仍,如下图所示:

图片 6

  由上航海用体育场合可以预知:图片 7,最后,经过反向替换:

图片 8

1.当大家每回插入u盘后,都会自行创键U盘的设备节点/dev/sda%d

1.RunLoop简介

三角形替换的主干套路

图片 9

这是因为内部调用了device_create()完成的, busybox的mdev机制就可以凭仗程序设备号等新闻,在/dev下成立设备节点,正如图所示:

1.1 什么是RunLoop

归纳的话正是:运转循环,能够清楚成一个死循环,一向在运营。

RunLoop实际上正是二个对象,这几个指标用来处理程序运转进度中冒出的各样风浪(触摸、提姆er、互连网),从而保障线程的穿梭运营,并且在并未有事件管理的时候,会进去休眠,从而节省CPU财富,提升程序质量。

OSX/iOS系统中,提供了七个那样的对象:NSRunLoop 和
CFRunLoopRef。CFRunLoopRef 是在CoreFoundation 框架内的,它提供了纯 C
函数的 API,所以这一个API都以现有安全的;NSRunLoop是依照 CFRunLoopRef
的包裹,提供了面向对象的API,然则那么些API不是现存安全的。

配方

  比相当多时候,根号下的表明式而不是地点表格中的标准套路,这就要求利用配方法将其凑成正规套路。

 图片 10

  假使根号下是x2+4就好办了。大家的靶子是将其改为正规套路中的一种,然后使用三角替换将根号去掉。

图片 11

  未来,结果符合规范套路了

图片 12

图片 13

  最终索要运用反向替换将θ调换为x。

图片 14

 图片 15

1.2 RunLoop和线程

RunLoop
和线程有很密切的关系,大家领略线程的职分是用来施行五个或几个特定的天职,但是在默许意况下,线程实行完事后就能退出。这时候,若是大家想让这么些线程一向去管理职责,并不脱离,所以就有了RunLoop。

  1. 一条线程对应叁个RunLoop对象,不过子线程中的RunLoop默许是不运转的,必要调用RunLoop的run方法,这一个措施就是三个死循环
  2. 大家只可以在眼下线程中操作当前线程的RunLoop对象;
  3. RunLoop对象是在第二遍拿走RunLoop对象时成立,在线程甘休的时候销毁;
  4. 主线程RunLoop对象,系统帮我们创造好了,子线程的RunLoop对象,要求大家团结去制造。

示例

图片 16

图片 17

  查看一下积分表,可以知道:

 图片 18

  最后将θ替换为x,图片 19,通过反向替换:

图片 20

图片 21

 


   作者:我是8位的

  出处:http://www.cnblogs.com/bigmonkey

  本文以念书、研商和享用为主,如需转发,请联系小编,标注作者和出处,非商业用途! 

 

而想接纳方面包车型客车sda1器具节点,读写多少时,还索要选用mount /dev/sda1
 /mnt,来挂载u盘才行,会显得拾壹分麻烦,正如图所示:

1.3 默许意况下的主线程的RunLoop原理

我们在起步贰个顺序的时候,系统会调用创造项目时自动生成的 main.m 文件:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

 在那之中 UIApplicationMain 函数内部帮大家打开了主线程的
RunLoop,UIApplicationMain 函数内部有叁个有线循环的代码,上边开启
RunLoop 的代码能够轻易的敞亮为以下代码:

int main(int argc, char * argv[]) {        
    BOOL running = YES;
    do {
        // 执行各种任务,处理各种事件
        // ......
    } while (running);

    return 0;
}

 从上边能够看来,程序平素在 do-while 循环中施行,所以 UIApplicationMain
函数平昔未有重回,我们在运维程序之后,不会立即退出,会保持不断运维情状。

来看一张官方的 RunLoop 模型图:

图片 22

从上航海用教室中可以看见,RunLoop 正是线程中的的一个循环,RunLoop
在循环中会不断检查评定,通过 Input Source (输入源) 和 Timer Source(定期源)
三种事件源来等待接受事件,然后对接到到的事件通报线程管理,并在尚未事件的时候休息。

 图片 23

2.RunLoop相关类

上边大家来精通一下 Core Fundation 框架下,关于RunLoop 的5个类:

  1. CFRunLoopRef:代表RunLoop对象
  2. CFRunLoopModeRef:代表RunLoop的周转情势
  3. CFRunLoopSourceRef:便是RunLoop模型中涉嫌的输入源/事件源
  4. CFRunLoopTimerRef:正是RunLoop模型中的定期源
  5. CFRunLoopObserverRef:观看者,可以监听RunLoop的场所改变

上面是这5个类的关系图:

图片 24

经过上海教室,我们能够看出,二个RunLoop对象(CFRunLoopRef)包括若干个运营情势(CFRunLoopModeRef),每二个运营格局下又含有着多少个输入源(CFRunLoopSourceRef),定时源(CFRunLoopTimerRef),观看者(CFRunLoopObserverRef)

  • 历次RunLoop运转的时候,只好钦点此中的一种运维方式(CFRunLoopModeRef),那一个运营方式被称之为
    currentMode
  • 假若急需切换运转情势(CFRunLoopModeRef),只可以退出
    RunLoop,在再次钦赐二个运营情势(CFRunLoopModeRef)步入
  • 那样做首如果为着分割开输入源(CFRunLoopSourceRef),定时源(CFRunLoopTimerRef),观望者(CFRunLoopObserverRef),使其不受影响

 

2.1 CFRunLoopRef

CFRunLoopRef 就是 Core Foundation 框架下的 RunLoop
类,大家得以透过以下措施来博取 RunLoop 对象:

  • Core Foundation

    CFRunLoopGetCurrent(); // 拿到当前线程的RunLoop对象
    CFRunLoopGetMain(); // 获得主线程的RunLoop对象

  •  Foundation

    [NSRunLoop currentRunLoop]; // 得到当前线程的RunLoop对象
    [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象

 

 2.2 CFRunLoopModeRef

系统默料定义了多种运营情势:

  1. kCFRunLoopDefaultMode :
    App的暗许运转情势,平日主线程是在这里个运转形式下运行
  2. UITrackingRunLoopMode :追踪客户的互动事件
    (用于scrollView追踪触摸滑动,保障分界面滑动时不受其余mode影响),只好是触摸事件唤醒,品级最大
  3. UIInitializationRunLoopMode:在刚启航App的时候走入的首先个mode,运行成功后就不在使用
  4. GS伊芙ntReceiveRunLoopMode:接受系统内部事件,经常用不到
  5. kCFRunLoopCommonMode:占位形式,不是一种真正的运作方式,

 

2.3 CFRunLoopTimerRef

CFRunLoopTimerRef 按期源,通晓为依据时间的触发器,基本上正是NSTimer。

 上面我们来演示下 CFRunLoopModeRef 和 CFRunLoopTimerRef
结合的运用用法,进而加剧精晓:

 – 大家先新建一个iOS项目,在Main.storyboard中拖入贰个Text View。

 – 在ViewController.m 文件中参与以下代码

- (void)viewDidLoad {
    [super viewDidLoad];

    // 定义一个定时器,约定两秒之后调用self的run方法
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

    // 将定时器添加到当前RunLoop的NSDefaultRunLoopMode下
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

- (void)run
{
    NSLog(@"---run");
}

  –
然后运转,那时候我们会开采只要大家不对模拟器进行任何操作的话,坚持计时器会平稳的每间距2秒调用run
方法打印

 – 可是当大家拖动Text View 滚动时,大家发掘 :run 方法不打印了,也正是说
NSTimer 不干活了。而当大家放手鼠标的时候, NSTimer就又起来平常办事了。

那是因为:

  • 当大家不做别的操作的时候,RunLoop 处于 NSDefaultRunLoopMode 下
  • 而当我们拖动 Text View 的时候,RunLoop 就甘休NSDefaultRunLoopMode,切换成了 UITrackingRunLoopMode
    格局下,那一个形式下未有增多 NSTimer,所以大家的 NSTimer 就不办事了
  • 但当大家松手鼠标的时候,RunLoop就截至 UITrackingRunLoopMode
    格局,又切换回 NSDefaultRunLoopMode 方式,所以 NSTimer
    就又开端平常办事了。

能够试着将上边代码中的:

// 将定时器添加到当前RunLoop的NSDefaultRunLoopMode下
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

 换成

// 将定时器添加到当前RunLoop的NSDefaultRunLoopMode下
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

 也正是将电磁照管计时器增添到当前 RunLoop 的UITrackingRunLoopMode
下,你就能意识反应计时器只会在拖动 Text View
的形式下办事,而不做操作的时候,沙漏就不坐班。

那难道我们就无法再那三种方式下让NSTimer都能经常专门的工作呢?

自然能够啊,那就用到了后面说的 伪格局(kCFRunLoopCommonModes)
,也能够明白为占位方式,这实质上不是一种真实的情势,而是一种标记方式,意思正是足以在打上Common
Modes标志的形式下运维。

那就是说此时,大家供给将 NSDefaultRunLoopMode 和 UITrackingRunLoopMode
打上标记,所以我们只要将NSTimer 加多到最近 RunLoop 的占位形式下就能够让
NSTimer 在不做操作和拖动 Text View 三种情状下欢悦的办事了。

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

 顺便讲一下 NSTimer 中的 scheduled提姆erWithTimeInterval 方法和 RunLoop
的涉及:

[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

 这句代码调用了 scheduledTimer 再次来到的坚持计时器,NSTimer 会自动被投入到了
RunLoop 的 NSDefaultRunLoopMode 情势下,这句代码也就是上边两句代码:

NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

2.其实,能够在/etc/mdev.conf文件里参加一行语句就会促成全自动装载u盘,也得以在里面干任何与设施节点相关的事

 2.4 CFRunLoopSourceRef

CFRunLoopSourceRef 是事件源,它有二种分类方法:

第一种:遵照合斯洛伐克语档来分类(就好像RunLoop模型图中那么):

  • Port-Based Sources (基于端口)
  • Custom Input Sources (自定义)
  • Cocoa Perform Selector Sources

第三种:根据函数调用栈来分类:

  • Source0:非基于Port(那是个什么?举办间通讯的轻量级的办法?),管理App内部事件、App担任管理,如UI伊芙nt、CFS
    ocket.
  • Source1:基于Port,通过基础和任何线程通讯,接收、分发系统事件

那二种分类方法实际并未有分裂,只但是第一种是透过官方理论来分类,第三种是在事实上使用中通过调用函数来分类、。 

上边大家比方差不离来打听一下函数调用栈和Source:

图片 25

当我们点击咖啡色区域的时候,会弹出上边包车型客车窗口,那正是点击事件发生的函数调用栈:

图片 26

 

故而点击事件是那样来的:

  1. 先是程序运营,调用 16
    行的main函数,main函数调用15行的UIApplicationMain函数,然后径直往上调用函数,最后调用到
    0 行的BtnClick 函数,即点击函数。
  2. 再正是我们能够观察11 行中有Sources0,也正是说大家点击事件是属于
    Sources0 函数的,点击事件正是在 Sources0 中拍卖的。
  3. 而关于
    Sources1,则是用来接受、分发系统事件,然后再分发到Sources0中管理的。

2.1而/etc/mdev.conf又是哪些?

2.5 CFRunLoopObserverRef

CFRunLoopObserverRef 是阅览者,用来监听RunLoop的气象更换:

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),               // 即将进入Loop:1
    kCFRunLoopBeforeTimers = (1UL << 1),        // 即将处理Timer:2    
    kCFRunLoopBeforeSources = (1UL << 2),       // 即将处理Source:4
    kCFRunLoopBeforeWaiting = (1UL << 5),       // 即将进入休眠:32
    kCFRunLoopAfterWaiting = (1UL << 6),        // 即将从休眠中唤醒:64
    kCFRunLoopExit = (1UL << 7),                // 即将从Loop中退出:128
    kCFRunLoopAllActivities = 0x0FFFFFFFU       // 监听全部状态改变  
};

 下边大家通过代码来监听RunLoop中的状态改变:

  1. 增多以下代码:

    • (void)viewDidLoad {
      [super viewDidLoad];

      // 成立旁观者
      CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

        NSLog(@"监听到RunLoop发生改变---%zd",activity);
      

      });

      // 增加观望者到当前RunLoop中
      CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

      // 释放observer,最终加多完必要释放掉
      CFRelease(observer);
      }

 2.然后运转,看下打字与印刷结果:

2017-12-18 23:05:06.992894+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.993346+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:06.993608+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.993798+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:06.993986+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.994204+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:06.997608+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.997771+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:06.997951+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.998064+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:06.998226+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.998342+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:06.999366+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.999518+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:06.999653+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:06.999757+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:07.002657+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:07.003307+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:07.067024+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---2
2017-12-18 23:05:07.067467+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---4
2017-12-18 23:05:07.068242+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---32
2017-12-18 23:05:07.248755+0800 RunLoop[10436:1007150] 监听到RunLoop发生改变---64

 能够见见RunLoop的意况在持续的改造,最后产生了事态
32,也便是就要步向梦眠状态,表达RunLoop之后就能够跻身睡眠状态。

它是属于mdev的三个配置文件,而mdev此前就讲过了,它主要的功效是治本/dev目录底下的装置节点

3. RunLoop 原理

下边,大家来精通下RunLoop的运维逻辑了:

图片 27

那张图对于我们精晓RunLoop很有救助,上面大家说下官方文书档案给我们的RunLoop逻辑:

在每回运转开启RunLoop的时候,所在线程的RunLoop会自动处理从前未管理的平地风波,并且布告相关的观望者:

  1. 照会阅览者RunLoop已经运维
  2. 通报观看者即将要从头的机械漏刻
  3. 照会观看者任何将在开发银行的非基于端口的源
  4. 启航任何希图好的非基于端口的源
  5. 借使依照端口的源筹划好并处于等候情形,立时运营,并跻身步骤9
  6. 通报观察者线程走入休眠状态
  7. 将线程置于休眠直到任一上边的事件发生:某一平地风波达到基于端口的源 –
    计时器运转 – RunLoop设置的光阴已经过期 – RunLoop被出示唤醒
  8. 通报观看者线程将被唤醒
  9. 拍卖未管理的事件 –
    假若客户定义的电火花计时器运维,管理测量时间的装置事件一碗水端平启RunLoop,步入步骤2  –
    假设输入源运营,传递相应的新闻 –
    假使RunLoop被出示唤醒并且时间还没超时,重启RunLoop,步向步骤2
  10. 通报观望者RunLoop甘休。

当系统中有自动注册设备节点的时候,mdev就能够调用/etc/mdev.conf一遍,
该文件能够实现与道具节点相关的事,比方自动装载usb,打字与印刷创制的装备节点音信等

4 使用情状

 

4.1 后台常驻线程(很常用)

咱俩在开拓顺序的经过中,假诺后台操作极度频仍,常常会在子线程做一些耗费时间操作(下载文件、后台播放音乐等),我们最CANON让那条线程永恒常驻内部存款和储蓄器。

那正是说怎么办吧?

增多一条用于常驻内部存储器的强援引的子线程,在该线程的RunLoop下增加三个Sources,开启 RunLoop。

- (void)viewDidLoad {
    [super viewDidLoad];

    // 创建线程,并调用run1方法执行任务
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(run1) object:nil];
    // 开启线程
    [self.thread start];    
}

- (void) run1
{
    // 这里写任务
    NSLog(@"----run1-----");

    // 添加下边两句代码,就可以开启RunLoop,之后self.thread就变成了常驻线程,可随时添加任务,并交于RunLoop处理
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];

    // 测试是否开启了RunLoop,如果开启RunLoop,则来不了这里,因为RunLoop开启了循环。
    NSLog(@"未开启RunLoop");
}

 运营之后发掘打字与印刷了 —run1— ,而未开启RunLoop则未打字与印刷。

那般我们就敞开了一条常驻线程,假使我们再去增多其他任务的时候,—run1—还恐怕会继续打字与印刷,那就落成了常驻线程的必要。

 

3.大家先是来解析device_create(),是什么样来调用到/etc/mdev.conf的,前面再讲怎么着使用mdev.conf(也能够直接跳过,直接看上边第4小节,怎样选取)

(PS:
在此以前创设字符设备节点用的class_device_create(),其实是和device_create功用大概)

3.1
device_create()最后调用了:device_create()->device_register()->device_add():

device_create()->device_register()->device_add()函数如下所示:

int class_device_add(struct class_device *class_dev)
{
       ... ...
       kobject_uevent(&class_dev->kobj, KOBJ_ADD);         // KOBJ_ADD是一个枚举值
              //调用了kobject_uevent_env(kobj, action, NULL);              // action=KOBJ_ADD
}

3.2
device_create()->device_register()->device_add()->kobject_uevent_env()函数如下所示:

int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[])
{
       char **envp;
       char *buffer;
       char *scratch;
       int i = 0;
       ... ...

       /* 通过KOBJ_ADD获取字符串"add",所以action_string="add"  */
       action_string = action_to_string(action);              // action=KOBJ_ADD


       /* environment index */
       envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);      //分配一个环境变量索引值

       /* environment values */
    buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);     //分配一个环境变量缓冲值      

/* event environemnt for helper process only */
/*设置环境变量*/
       envp[i++] = "HOME=/";
       envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
       scratch = buffer;
       envp [i++] = scratch;
       scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;  //"ACTION= add"
       envp [i++] = scratch;
       scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
       envp [i++] = scratch;
       scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
       ... ...
       /*调用应用程序,比如mdev*/
       if (uevent_helper[0]) {
            char *argv [3];
              argv [0] = uevent_helper;       // uevent_helper[]= "/sbin/hotplug";
              argv [1] = (char *)subsystem;
              argv [2] = NULL;
              call_usermodehelper (argv[0], argv, envp, 0);        //调用应用程序,根据传入的环境变量参数来创建设备节点
       }
}

从地点的代码和注释来看,最后经过*argv[],
*envp[]三个字符串数组里面存的景况变量参数来创制设备节点的

3.2接下去便在kobject_uevent_env()函数里增多打字与印刷新闻,
然后再度烧内核:

 图片 28

 

3.3然后大家以登记三个按钮驱动为例 

输入 insmod
key.ko,打字与印刷了以下语句:

class_device: argv[0]=/sbin/mdev                 //调用mdev

class_device: argv[1]=sixth_dev                      //类名

class_device: envp[0]=HOME=/

class_device: envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin

class_device: envp[2]=ACTION=add             //add:表示添加设备节点,  若=remove:表示卸载设备节点

class_device: envp[3]=DEVPATH=/class/sixth_dev/buttons   //设备的路径

class_device: envp[4]=SUBSYSTEM=sixth_dev                //类名

class_device: envp[5]=SEQNUM=745

class_device: envp[6]=MAJOR=252                          //主设备号

class_device: envp[7]=MINOR=0

3.4结尾那么些参数依照/sbin/mdev就进去了busybox的mdev.c的mdev_main()函数里:

int mdev_main(int argc, char **argv)
{
... ...
action = getenv("ACTION");           //获取传进来的执行参数,它等于“add”,则表示创建设备节点
env_path = getenv("DEVPATH");      //获取设备的路径“/class/sixth_dev/buttons”
sprintf(temp, "/sys%s", env_path);   //指定temp (真正设备路径)为“/sys/class/sixth_dev/buttons”

if (!strcmp(action, "remove"))           //卸载设备节点
                    make_device(temp, 1);

else if (!strcmp(action, "add")) {       //创建设备节点
                     make_device(temp, 0);
 ... ... 
}

3.5最后调用mdev_main
()->make_device()函数来创立/卸载设备节点,该函数如下所示:

static void make_device(char *path, int delete) //delete=0:创建, delete=1:卸载
{
       /*判断创建的设备节点是否是有效的设备*/
       if (!delete) {
              strcat(path, "/dev");
              len = open_read_close(path, temp + 1, 64);
              *temp++ = 0;
              if (len < 1) return;
       }

device_name = bb_basename(path);    //通过设备路径,来获取要创建/卸载的设备节点名称
                      //例: path =“/sys /class/sixth_dev/buttons”,那么device_name=“buttons”



type = path[5]=='c' ? S_IFCHR : S_IFBLK;     //判断如果是在/sys/class/目录下,那么就是字符设备
                                              //因为块设备,是存在/sys/block/目录下的


/* 如果配置了支持mdev.conf选项,那么就解析里边内容并执行   */
 if (ENABLE_FEATURE_MDEV_CONF) { 
       /* mmap the config file */
fd = open("/etc/mdev.conf", O_RDONLY);     //调用/etc/mdev.conf配置文件

      ... ...         //开始操作 mdev.conf配置文件
}



       if (!delete) {                  //如果是创建设备节点

              if (sscanf(temp, "%d:%d", &major, &minor) != 2) return;   //获取主次设备号

        /*调用mknod ()创建字符设备节点*/
if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST)
                     bb_perror_msg_and_die("mknod %s", device_name);


              if (major == root_major && minor == root_minor)
                     symlink(device_name, "root");

              /*若配置了支持mdev.conf选项,则调用chown命令来改变属主,默认uid和gid=0 */
              if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);
}

     if (delete) unlink(device_name);           //如果是卸载设备节点
}

从上边的代码和注释分析到,要选用mdev.conf配置文件,还要求配置busybox的menuconfig,
使mdev帮忙mdev.conf选项才行

平常来讲图,步向busybox目录,然后输入make
menuconfig,开掘大家曾经陈设过了该选项了

 图片 29

 

 

 

4.接下来,便来探访哪些选择mdev.conf, 
参谋busybox-1.7.0/docs/mdev.txt文书档案

选取格局如下所示:

the format:

       <device
regex
> <uid>:<gid> <octal
permissions
> [<@|$|*>
<command>]

The special characters
have the meaning:

@ Run after
creating the device.

$ Run before
removing the device.

* Run both after
creating and before removing the device.

大概便是:

配置文件格式:

<device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]  

梯次参数代表的含义如下:  

device regex:

正则表明式,来表明哪多少个设备 ,正则表明式疏解链接:https://deerchao.net/tutorials/regex/regex.htm

uid: 

owner       (uid,gid:注册设备节点时,就能被chown命令调用,来更动设备的属主,私下认可都填0就可以)

gid: 

组ID  

octal permissions:

以八进制表示的权限值,会被chmod命令调用,来退换设备的拜见权限,私下认可填660就能够

@
创建设备节点之后实践命令  

$  :
 
删去设备节点在此以前实施命令  

*  
开创造备节点之后 和 删除设备节点以前 施行命令  

command
要实行的吩咐  

 

5.接下来便来行使mdev.conf,完成u盘自动装载

vi /etc/mdev.conf

增加以下一句:

sda[1-9]+ 0:0 660 * if
[ $ACTION = “add” ]; then mount /dev/$MDEV /mnt; else umount /mnt;
fi

 


[1-9] : 匹配1~9的数字,


 :  双重相配三次或更频仍

$ACTION==”add”   :表示注册设备节点,不然就是打消设备节点

/dev/$MDEV      :表示要开创/注销的要命设备节点


 

为此当大家插上u盘,自动创制了/dev/sda1时,mdev便会步向/etc/mdev.conf配置文件,然后实践mount
/dev/
命令,就可以自行李装运载U盘,如下图所示:

 图片 30

输入ls
/dev/sda1
 -l,能够观看都以因此mdev.conf里安顿新闻来成立的设施节点,如下图所示:

图片 31

而抽取u盘时,同样自动umount
 /mnt来卸载

 

相关文章