背景

通过上一讲了解完设备树DTS有关概念,我们这一讲就来基于设备树例程,学习设备树的语法规则。

参考:设备树详解dts、设备树语法详解、设备树使用总结

设备树框架

1个dts文件 + n个dtsi文件,它们编译而成的dtb文件就是真正的设备树。

基于同样的软件分层设计的思想,由于一个SoC可能对应多个machine,如果每个machine的设备树都写成一个完全独立的.dts文件,那么势必相当一些.dts文件有重复的部分。

为了解决这个问题,Linux设备树目录把一个SoC公用的部分或者多个machine共同的部分提炼为相应的.dtsi文件。

这样每个.dts就只有自己差异的部分,公有的部分只需要"include"相应的.dtsi文件, 以保证整个设备树的管理更加有序。

以solidrun公司的hummingboard为例,其组成为

imx6dl-hummingboard.dts
|_imx6dl.dtsi
| |_imx6qdl.dtsi
|_imx6qdl-microsom.dtsi
|_imx6qdl-microsom-ar8035.dtsi

此外,dts/dtsi兼容c语言的一些语法,能使用宏定义,也能包含.h文件

设备树用树状结构描述设备信息,它有以下几种特性:

  1. 每个设备树文件都有一个根节点,每个设备都是一个节点。
  2. 节点由 节点名 + 属性 组成。
  3. 节点间可以嵌套,形成父子关系,这样就可以方便的描述设备间的关系。
  4. 每个设备的属性都用一组key-value对(键值对)来描述。
  5. 每个属性的描述用;结束

所以,一个设备树的基本框架可以写成下面这个样子,一般来说,/表示板子,它的子节点node1表示SoC上的某个控制器,控制器中的子节点node2表示挂接在这个控制器上的设备(们)。

/ {                                 //根节点
node1{ //node1是节点名,是/的子节点
key=value; //node1的属性
...
node2{ //node2是node1的子节点
key=value; //node2的属性
...
}
} //node1的描述到此为止
node3{
key=value;
...
}
}

节点node

{}包围起来的结构称之为节点,dts中最开头的/ {},称为根节点。

在节点中,以 key = value 代表节点属性。

树中每个表示一个设备的节点都需要一个 compatible 属性。

节点名 name

  • 节点名称:每个节点名格式为:<name>[@<unit_address>],其中:

    • :设备名,就是一个不超过31位的简单 ascii 字符串,节点的命名应该根据它所体现的是什么样的设备。
    • <unit_address> :设备地址,用来唯一标识一共节点。没有指定<unit_address>时,同级节点命名必须是唯一的;但只要<unit_address>不同,多个节点也可以使用一样的通用名称。

下面是典型节点名的写法:

/ {
model = "Freescale i.MX23 Evaluation Kit";
compatible = "fsl,imx23-evk", "fsl,imx23"; memory {
reg = <0x40000000 0x08000000>;
};
// 注意这里
apb@80000000 {
...
};
}

上面的节点名是apb,节点路径是/apb@80000000 ,这点要注意,因为根据节点名查找节点的API的参数是不能有"@xxx"这部分的。

Linux中的设备树还包括几个特殊的节点:比如chosen,chosen节点不描述一个真实设备,而是用于firmware传递一些数据给OS,比如bootloader传递内核启动参数给内核

/include/ "zynq-7000.dtsi"

/ {
model = "Zynq ZC702 Development Board";
compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000"; ... chosen {
bootargs = "console=ttyPS1,115200 earlyprintk";
};
};

引用

当我们找一个节点的时候,我们必须书写完整的节点路径,这样当一个节点嵌套比较深的时候就不是很方便。所以,设备树允许我们用下面的形式为节点标注引用(起别名),借以省去冗长的路径。

标号引用常常还作为节点的重写方式,用于修改节点属性。

  • 格式:

    • 声明别名: 别名 : 节点名
    • 访问 : &别名

编译设备树的时候,相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写(覆盖前值),使用引用可以避免移植者四处找节点,直接在板级.dts增改即可。

/include/ "imx53.dtsi"

/ {
model = "Freescale i.MX53 Automotive Reference Design Board";
compatible = "fsl,imx53-ard", "fsl,imx53"; memory {
reg = <0x70000000 0x40000000>;
}; eim-cs1@f4000000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,eim-bus", "simple-bus";
reg = <0xf4000000 0x3ff0000>; lan9220@f4000000 {
compatible = "smsc,lan9220", "smsc,lan9115";
reg = <0xf4000000 0x2000000>;
phy-mode = "mii";
interrupt-parent = <&gpio2>; // 直接使用引用 vdd33a-supply = <&reg_3p3v>;
};
}; regulators {
compatible = "simple-bus"; reg_3p3v: 3p3v { // 定义一个引用
compatible = "regulator-fixed";
regulator-name = "3P3V";
};
}; ...
// 引用一个节点,新增/修改其属性。
&reg_3p3v {
regulator-always-on;
}

节点属性 property

属性一般由 key = value; 键值对构成。

Linux设备树语法中定义了一些具有规范意义的属性,包括:compatible, address, interrupt等,这些信息能够在内核初始化找到节点的时候,自动解析生成相应的设备信息。

此外,还有一些Linux内核定义好的,一类设备通用的有默认意义的属性,这些属性一般不能被内核自动解析生成相应的设备信息,但是内核已经编写的相应的解析提取函数,常见的有 "mac_addr","gpio","clock","power"。"regulator" 等等。

  • 简单的键-值对,它的值可以为空或者包含一个任意字节流。虽然数据类型并没有编码进数据结构,但在设备树源文件中任有几个基本的数据表示形式:

    • 文本字符串(无结束符)可以用双引号表示: string-property = "a string"
    • Cells是 32 位无符号整数,用尖括号限定: cell-property = <0xbeef 123 0xabcd1234>
    • 二进制数据用方括号限定: binary-property = [01 23 45 67];
    • 不同表示形式的数据可以使用逗号连在一起: mixed-property = "a string", [01 23 45 67], <0x12345678>;
    • 逗号也可用于创建字符串列表: string-list = "red fish", "blue fish";
    • 混合形式:上述几种的混合形式

compatible 兼容性

如果一个节点是设备节点,那么它一定要有compatible(兼容性),因为这将作为驱动和设备(设备节点)的匹配依据,compatible(兼容性)的值可以有不止一个字符串以满足不同的需求。(设备节点中对应的节点信息已经被内核构造成struct platform_device。驱动可以通过相应的函数从中提取信息。)

compatible属性是用来查找节点的方法之一,另外还可以通过节点名或节点路径查找指定节点。

而根节点的compatible也是非常重要的,一般在系统启动以后,用于识别对应系统一些东西,并由此进行对应的初始化。

  • 格式:compatible = "<manufacturer>,<model>" [, "<manufacturer>,<model>"]

    • manufacturer指定厂家名,model指定特定设备型号;后续的<manufacturer,model>指定兼容的设备型号(其中,后续的<manufacturer> 可空,第二个model也可空)。

      我们来看 compatible 是如何与 驱动捆绑在一起的:

      可以看出,驱动中用于匹配的结构使用的compatible和设备树中一模一样,否则就可能无法匹配,这里另外的一点是struct of_device_id数组的最后一个成员一定是空,因为相关的操作API会读取这个数组直到遇到一个空。

1)先随便在设备树中出一个网卡设备,关键是找到 compatible 属性中的 <model>值。

// 文件节选于:arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
ethernet@2,02000000 {
compatible = "smsc,lan9118", "smsc,lan9115";
reg = <2 0x02000000 0x10000>;
interrupts = <15>;
phy-mode = "mii";
reg-io-width = <4>;
smsc,irq-active-high;
smsc,irq-push-pull;
vdd33a-supply = <&v2m_fixed_3v3>;
vddvario-supply = <&v2m_fixed_3v3>;
};

2)在驱动中(为了方便读者理解,这里在内核源码根目录下查找,实际上就是在driver目录中),找到对应的.compatible 关键字所在的文件以及行数。

$ find . 2>/dev/null | grep lan9115
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi:50: compatible = "smsc,lan9118", "smsc,lan9115";
arch/arm/boot/dts/vexpress-v2m.dtsi:49: compatible = "smsc,lan9118", "smsc,lan9115";
drivers/net/ethernet/smsc/smsc911x.c:2578: { .compatible = "smsc,lan9115", },

3)顺藤摸瓜,找到所在行,也就找到了用来描述设备信息的结构体of_device_id 。

// 节选于 drivers/net/ethernet/smsc/smsc911x.c
#ifdef CONFIG_OF
static const struct of_device_id smsc911x_dt_ids[] = {
{ .compatible = "smsc,lan9115", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
#endif

可以看出,驱动中用于匹配的结构使用的compatible和设备树中一模一样,且,字符串需要严格匹配。

注:这里另外的一点是 struct of_device_id 数组的最后一个成员一定是空,因为相关的操作API会读取这个数组直到遇到一个空。

i2c和spi驱动还支持一种“别名匹配”的机制,就以pcf8523为例,假设某程序员在设备树中的pcf8523设备节点中写了compatible = "pcf8523";,显然相对于驱动id_table中的"nxp,pcf8523",他遗漏了nxp字段,但是驱动却仍然可以匹配上,因为别名匹配对compatible中字符串里第二个字段敏感。

驱动程序将直接和设备树里的设备节点进行配对,是通过设备节点中的compatible(兼容性)来与设备节点进行配对的,具体的应用详见基于i2c子系统的驱动分析、 基于platform总线的驱动分析

address 地址属性

有关节点的地址,比如i2c@021a0000,虽然它在名字后面跟了地址,但是正式的设置是在reg属性中设置。

(几乎)所有的设备都需要与CPU的IO口相连,所以其IO端口信息就需要在设备节点节点中说明。常用的属性有:

  • #address-cells = <CNT>,用来描述子节点"reg"属性的地址表中用来描述首地址的cell的数量
  • #size-cells = <CNT>, 用来描述子节点"reg"属性的地址表中用来描述地址长度的cell的数量。
  • reg = <address ... length>: address 代表基地址, length 代表长度。基址和长度的格式是可变的,addr由父节点的#address-cells个uint32值组成,len由父节点的#size-cells个uint32值组成。表明了设备使用的一个地址范围。

    例如:
	aips-bus@02000000 { /* AIPS1 */
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x02000000 0x100000>; i2c1: i2c@021a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";
reg = <0x021a0000 0x4000>; rtc: rtc@68 {
compatible = "stm,mt41t62";
reg = <0x68>;
};
};
}; /*
我们知道,aips-bus@02000000 是 i2c@021a0000 的父节点;i2c@021a0000 是 rtc@68 的父节点。 aips-bus@02000000的 #address-cells 和#size-cells均为1,所以 i2c@021a0000 中的 `reg` 格式为: `<address length>`
i2c@021a0000的 #address-cells 和#size-cells分别为1和0,所以 rtc@68 中的 `reg` 格式为: `<address>` 通俗来讲,如果现在有 一个节点A的 #address-cells 和#size-cells分别为2和1;那么A的子节点B 的 `reg`格式为 `<address address length>`
*/

interrupts 中断属性

中断产生设备用interrupts属性描述中断源(interrupt specifier),因为不同的硬件描述中断源需要的数据量不同,所以interrupts属性的类型也是。为了明确表示一个中断由几个u32表示,又引入了#interrupt-cells属性,#interrupt-cells属性的类型是u32,假如一个中断源需要2个u32表示(一个表示中断号,另一个表示中断类型),那么#interrupt-cells就设置成2。

有些情况下,设备树的父节点不是中断的父节点(主要是中断控制器一般不是父节点),为此引入了interrupt-parent属性,该属性的类型是,用来引用中断父节点(我们前边说过,一般用父节点的标签,这个地方说中断父节点而不是中断控制器是有原因的)。如果设备树的父节点就是中断父节点,那么可以不用设置interrupt-parent属性。interrupts属性和interrupt-parent属性都是中断产生设备节点的属性,但是#interrupt-cells属性不是,#interrupt-cells属性是中断控制器节点以及interrupt nexus节点的属性,这两类节点都可能是中断父节点。

一个计算机系统中大量设备都是通过中断请求CPU服务的,所以设备节点中就需要在指定中断号。常用的属性有:

  • interrupt-controller: 一个空属性用来声明这个node接收中断信号,即这个node是一个中断控制器。
  • #interrupt-cells :是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符,用来描述子节点中interrupts属性使用了父节点中的interrupts属性的具体的哪个值。一般,如果父节点的该属性的值是3,则子节点的interrupts一个cell的三个32bits整数值分别为:<中断域 中断 触发方式>,如果父节点的该属性是2,则是<中断 触发方式>
  • interrupt-parent:标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的
  • interrupts:一个中断标识符列表,表示每一个中断输出信号。
  • reg : 在schips todo

这里重点说明一下,interrupts 属性,在ARM GIC(Generic Interrupt Controller)中:

备注:ARM GIC 说明文档位于:Documentation/devicetree/bindings/arm/gic.txt ;此外,本人并没有找到 #interrupt-cells为1个时的文档说明。

当interrupt-cells为3时,interrupts包含三个cells,如interrupts = <0 168 4> :

第一个cell代表中断类型:0 表示SPI中断,1 表示PPI中断。

第二个cell代表具体的中断类型:、

  • PPI中断:私有外设中断(Private Peripheral Interrupt),是每个CPU私有的中断。最多支持16个PPI中断,范围【0 - 15】。
  • SPI中断类型:公用外设中断(Shared Peripheral Interrupt),最多可以支持988个外设中断,范围【0 - 987】。

第三个cell代表中断触发标志:

  • bits [ 3 :0 ] 触发类型和级别标志:

    1 = 低- 至- 高边沿触发

    2 = 高- 到- 低边沿触发

    4 = 活跃的高水平 - 敏感

    8 = 低电平有效 - 敏感
  • bits [ 15 :8 ] PPI中断cpu掩码。每个位对应于每个位附加到GIC的8个可能的cpu。指示设置为"1"的位中断被连接到该CPU 。只有有效的PPI中断。

当interrupt-cells为2时,interrupts包含2个cells,如interrupts = <2 4>:

第一个cell代表具体的中断类型:

  • SGI中断:软件触发中断(Software Generated Interrupt),通常用于多核间通讯,最多支持16个SGI中断,硬件中断号从ID0~ID15。
  • PPI中断:私有外设中断(Private Peripheral Interrupt),是每个CPU私有的中断。最多支持16个PPI中断,硬件中断号从ID16~ID31。
  • SPI中断类型:公用外设中断(Shared Peripheral Interrupt),最多可以支持988个外设中断,硬件中断号从ID32~ID1019。

第二个cell代表中断触发标志:

bits [ 3 :0 ] 触发类型和级别标志:

  • 1 = 低- 至- 高边沿触发

  • 2 = 高- 到- 低边沿触发

  • 4 = 活跃的高水平- 敏感

  • 8 = 低电平有效- 敏感

    bits [ 15 :8 ] PPI中断cpu掩码。每个位对应于每个位附加到GIC的8个可能的cpu。指示设置为"1"的位中断被连接到该CPU 。只有有效的PPI中断。

/ {
compatible = "acme,coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;//指定依附的中断控制器是intc serial@101f0000 { //子节点:串口设备
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
interrupts = < 1 0 >;
}; intc: interrupt-controller@10140000 { //intc中断控制器
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
interrupt-controller;//定义为中断控制器设备
#interrupt-cells = <2>;
};
}

GPIO 属性

gpio也是最常见的IO口,常用的属性有:

  • "gpio-controller",用来说明该节点描述的是一个gpio控制器
  • "#gpio-cells",用来描述gpio使用节点的属性一个cell的内容,即 `属性 = <&引用GPIO节点别名 GPIO标号 工作模式>

通过上面的属性定义以后,就可以使用它,例如:

  2 &spi_1 {
1 status = "okay";
388 cs-gpios = <&gpa2 5 GPIO_ACTIVE_HIGH>; // 使用 GPIO A2 第5个引脚,
1
2 w25q80bw@0 {
3 #address-cells = <1>;
4 #size-cells = <1>;
5 compatible = "w25x80";
6 reg = <0>;
7 spi-max-frequency = <1000000>;
8
9 controller-data {
10 samsung,spi-feedback-delay = <0>;
11 };
12

驱动自定义key属性

针对具体的设备,有部分属性很难做到通用,需要驱动自己定义好。

可以在设备树中自定义key属性,再在驱动中通过内核的属性提取解析函数进行值的获取。

比如:

/* 有关的 设备树写法 */
6 ethernet@2,02000000 {
5 compatible = "smsc,lan9118", "smsc,lan9115";
4 reg = <2 0x02000000 0x10000>;
3 interrupts = <15>;
2 phy-mode = "mii";
1 reg-io-width = <4>;
55 smsc,irq-active-high; // 自定义key
1 smsc,irq-push-pull; // 自定义key
2 vdd33a-supply = <&v2m_fixed_3v3>;
3 vddvario-supply = <&v2m_fixed_3v3>;
4 };
5
6 usb@2,03000000 {
7 compatible = "nxp,usb-isp1761";
8 reg = <2 0x03000000 0x20000>;
9 interrupts = <16>;
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi /* 有关的驱动写法 */ 2389 if (of_get_property(np, "smsc,irq-active-high", NULL))
1 config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH;
2
3 if (of_get_property(np, "smsc,irq-push-pull", NULL))
4 config->irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL;
5
6 if (of_get_property(np, "smsc,force-internal-phy", NULL))
7 config->flags |= SMSC911X_FORCE_INTERNAL_PHY;
8
9 if (of_get_property(np, "smsc,force-external-phy", NULL))
10 config->flags |= SMSC911X_FORCE_EXTERNAL_PHY;
11
12 if (of_get_property(np, "smsc,save-mac-address", NULL))
13 config->flags |= SMSC911X_SAVE_MAC_ADDRESS;
14
15 return 0;
drivers/net/ethernet/smsc/smsc911x.c

附录:补充对于interrupt-parent的一些知识点

为什么会有interrupt-parent?

首先讲讲Linux设备管理中对中断的设计思路演变。随着linux kernel的发展,在内核中将interrupt controller抽象成irqchip这个概念越来越流行,甚至GPIO controller也可以被看出一个interrupt controller chip,这样,系统中至少有两个中断控制器了。另外,在硬件上,随着系统复杂度加大,外设中断数据增加,在这种趋势下,内核中原本的中断源直接到中断号的方式已经很难继续发展了,为了解决这些问题,linux kernel的大牛们就创造了irq domain(中断域)这个概念。domain在内核中有很多,除了irqdomain,还有power domain,clock 这些domain等等;所谓domain,就是领域,范围的意思(即:任何的定义出了这个范围就没有意义了)。

实际上系统可以需要多个中断控制器进行级联,形成事实上的硬件中断处理结构:

如上所述,系统中所有的interrupt controller会形成树状结构,对于每个interrupt controller都可以连接若干个外设的中断请求(interrupt source,中断源),interrupt controller会对连接其上的interrupt source(根据其在Interrupt controller中物理特性)进行编号(也就是HW interrupt ID了)。有了irq domain这个概念之后,这个编号仅仅限制在本interrupt controller范围内。

有了这样的设计,CPU(Linux 内核)就可以根据级联的规则一级一级的找到想要访问的中断。当然,通常我们关心的只是内核中的中断号,具体这个中断号是怎么找到相应的中断源的,我们作为程序员往往不需要关心。

在写设备树的时候,设备树就是要描述嵌入式软件开发中涉及的所有硬件信息。所以,设备树就需要准确描述硬件上处理中断的这种树状结构,如此,就有了我们的interrupt-parant这样的概念:用来连接这样的树状结构的上下级,用于表示这个中断归属于哪个interrupt controller,比如,一个接在GPIO上的按键,它的组织形式就是:

中断源--interrupt parent-->GPIO--interrupt parent-->GIC1--interrupt parent-->GIC2--...-->CPU

有了parant,我们就可以使用一级一级的偏移量来最终获得当前中断的绝对编号。

可以看出,在我板子上的dm9000的的设备节点中,它的"interrupt-parent"引用了"exynos4x12-pinctrl.dtsi"(被板级设备树的exynos4412.dtsi包含)中的gpx0节点:

而在gpx0节点中,指定了#interrupt-cells = <2>;,所以在dm9000中的属性interrupts = <6 4>;表示dm9000的的中断在作为irq parant的gpx0中的中断偏移量,即gpx0中的属性interrupts中的<0 22 0>,通过查阅exynos4412的手册知道,对应的中断号是EINT[6]。

设备树DTS 学习:2-设备树语法的更多相关文章

  1. 设备树DTS 学习:1-有关概念

    背景 设备树在Linux驱动开发中是一种比较常用的架构. 参考:<设备树DTS使用总结> .<linux内核设备树及编译> Linux设备树 介绍 在Linux 2.6中,ar ...

  2. 设备树DTS 学习:Linux DTS文件加载过程

    背景 了解机制有利于对内核有更深的认识. wget https://mirrors.aliyun.com/linux-kernel/v3.x/linux-3.2.61.tar.xz 内核 在drive ...

  3. 设备树DTS 学习:4-编写实战

    背景 讲完设备树的有关概念以及语法以后,我们接下来就让 我们的驱动 使用 设备树. ref : <内核学习笔记14:内核设备树学习>.<u-boot对设备树的支持> 测试代码 ...

  4. 设备树DTS 学习:3-常用的DTS 函数

    Linux内核中目前DTS相关的函数都是以of_前缀开头的,它们的实现位于内核源码的drivers/of下面 void __iomem*of_iomap(struct device_node *nod ...

  5. 设备树DTS 学习: uboot 传递 dtb 给 内核

    背景 得到 dtb 文件以后,我们需要想办法下载到 板子中,并给 Linux 内核使用. (高级版本的 uboot也有了 自己使用设备树支持,我们这里不讨论 uboot 使用的设备树) Linux 内 ...

  6. Linux dts 设备树详解(二) 动手编写设备树dts

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 前言 硬件结构 设备树dts文件 前言 在简单了解概念之后,我们可以开始尝试写一个 ...

  7. linux设备树笔记__dts基本概念及语法【转】

    转自:http://www.360doc.com/content/15/1113/11/15700426_512794532.shtml 设备树手册(Device Tree Usage)原文地址:ht ...

  8. Linux 总线、设备、驱动模型 与 设备树

    1.总线.设备.驱动模型 本着高内聚.低耦合的原则,Linux 把设备驱动模型分为了总线.设备和驱动三个实体,这三个实体在内核里的职责分别如下: 设备和驱动向总线进行注册,总线负责把设备和对应的驱动绑 ...

  9. 【总结】设备树对platform平台设备驱动带来的变化(史上最强分析)【转】

    本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74375086 版权声明:本文为博主原创文章,转载请注明http://blog.c ...

随机推荐

  1. TP-LINK路由器端口映射全套教程(亲测有效)

    最近想在自己的笔记本上搭建一个博客系统,方便自己写写日志,记录一些知识心得. 由于笔记本是长期放在家里的,需要在外边也能访问它,于是需要在路由器上设置一个端口映射,让在因特网上的其他电脑能访问到家里的 ...

  2. nginx反向代理实战之轮询、Ip_hash、权重

    实验环境 192.168.200.111 web1 centos7 192.168.200.112 web2 centos7 192.168.200.113 wev3 centos7 三台主机环境: ...

  3. 包装类和toString和static关键字

    包装类 针对八种基本数据类型定义的引用类型. 有类的特点,可以调用类中的方法. 基本数据类型 包装类 boolean Boolean byte Byte short Short int Integer ...

  4. 【协作式原创】查漏补缺之Golang中mutex源码实现(预备知识)

    预备知识 CAS机制 1. 是什么 参考附录3 CAS 是项乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是 ...

  5. 《iOS开发实战 从入门到上架App Store(第2版)》书籍目录

    第1章 开发准备 1.1 iOS 10新特性简述 1.1.1 新增触觉反馈编程接口 1.1.2 SiriKit框架的开放 1.1.3 引入Messages App 1.1.4 通知框架的整合与扩展 1 ...

  6. java.util.ConcurrentModificationException 异常原因和解决方法

    不要在 foreach 循环里进行元素的 remove/add 操作.remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁. 注意: 1.foreach遍历 ...

  7. python 静态方法,类方法,类下面的函数区别

    @clssmenthod(类方法) 与 @staticmethod(静态方法) 与类下面的函数的区别: 1.@classmethod修饰的方法def name(cls)需要通过cls参数传递当前类本身 ...

  8. springdata框架

    SpringData jpa:    JPA(Java Persistence API)是当年的 Sun 官方提出的 Java 持久化规范.    Spring Data JPA 是 Spring 基 ...

  9. Android之收音机UI实现(转)

    源码: http://www.2cto.com/kf/201211/171417.html 最近在研究收音机的源码,本来想把收音机从源码中提取出来,做成一个单独的应用,但是,收音机需要底层的支持,所以 ...

  10. Gamma 矫正

    参考如下链接: https://www.zhihu.com/question/27467127