Linux中断(interrupt)子系统之一:中断系统基本原理【转】
转自:http://blog.csdn.net/droidphone/article/details/7445825
这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层。内核版本基于3.3。虽然内核的版本不断地提升,不过自从上一次变更到当前的通用中断子系统后,大的框架性的东西并没有太大的改变。
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
1. 设备、中断控制器和CPU
一个完整的设备中,与中断相关的硬件可以划分为3类,它们分别是:设备、中断控制器和CPU本身,下图展示了一个smp系统中的中断硬件的组成结构:
图 1.1 中断系统的硬件组成
设备 设备是发起中断的源,当设备需要请求某种服务的时候,它会发起一个硬件中断信号,通常,该信号会连接至中断控制器,由中断控制器做进一步的处理。在现代的移动设备中,发起中断的设备可以位于soc(system-on-chip)芯片的外部,也可以位于soc的内部,因为目前大多数soc都集成了大量的硬件IP,例如I2C、SPI、Display Controller等等。
中断控制器 中断控制器负责收集所有中断源发起的中断,现有的中断控制器几乎都是可编程的,通过对中断控制器的编程,我们可以控制每个中断源的优先级、中断的电器类型,还可以打开和关闭某一个中断源,在smp系统中,甚至可以控制某个中断源发往哪一个CPU进行处理。对于ARM架构的soc,使用较多的中断控制器是VIC(Vector Interrupt Controller),进入多核时代以后,GIC(General Interrupt Controller)的应用也开始逐渐变多。
CPU cpu是最终响应中断的部件,它通过对可编程中断控制器的编程操作,控制和管理者系统中的每个中断,当中断控制器最终判定一个中断可以被处理时,他会根据事先的设定,通知其中一个或者是某几个cpu对该中断进行处理,虽然中断控制器可以同时通知数个cpu对某一个中断进行处理,实际上,最后只会有一个cpu相应这个中断请求,但具体是哪个cpu进行响应是可能是随机的,中断控制器在硬件上对这一特性进行了保证,不过这也依赖于操作系统对中断系统的软件实现。在smp系统中,cpu之间也通过IPI(inter processor interrupt)中断进行通信。
2. IRQ编号
系统中每一个注册的中断源,都会分配一个唯一的编号用于识别该中断,我们称之为IRQ编号。IRQ编号贯穿在整个Linux的通用中断子系统中。在移动设备中,每个中断源的IRQ编号都会在arch相关的一些头文件中,例如arch/xxx/mach-xxx/include/irqs.h。驱动程序在请求中断服务时,它会使用IRQ编号注册该中断,中断发生时,cpu通常会从中断控制器中获取相关信息,然后计算出相应的IRQ编号,然后把该IRQ编号传递到相应的驱动程序中。
3. 在驱动程序中申请中断
Linux中断子系统向驱动程序提供了一系列的API,其中的一个用于向系统申请中断:
- int request_threaded_irq(unsigned int irq, irq_handler_t handler,
- irq_handler_t thread_fn, unsigned long irqflags,
- const char *devname, void *dev_id)
其中,
- irq是要申请的IRQ编号,
- handler是中断处理服务函数,该函数工作在中断上下文中,如果不需要,可以传入NULL,但是不可以和thread_fn同时为NULL;
- thread_fn是中断线程的回调函数,工作在内核进程上下文中,如果不需要,可以传入NULL,但是不可以和handler同时为NULL;
- irqflags是该中断的一些标志,可以指定该中断的电气类型,是否共享等信息;
- devname指定该中断的名称;
- dev_id用于共享中断时的cookie data,通常用于区分共享中断具体由哪个设备发起;
关于该API的详细工作机理我们后面再讨论。
4. 通用中断子系统(Generic irq)的软件抽象
在通用中断子系统(generic irq)出现之前,内核使用__do_IRQ处理所有的中断,这意味着__do_IRQ中要处理各种类型的中断,这会导致软件的复杂性增加,层次不分明,而且代码的可重用性也不好。事实上,到了内核版本2.6.38,__do_IRQ这种方式已经彻底在内核的代码中消失了。通用中断子系统的原型最初出现于ARM体系中,一开始内核的开发者们把3种中断类型区分出来,他们是:
- 电平触发中断(level type)
- 边缘触发中断(edge type)
- 简易的中断(simple type)
后来又针对某些需要回应eoi(end of interrupt)的中断控制器,加入了fast eoi type,针对smp加入了per cpu type。把这些不同的中断类型抽象出来后,成为了中断子系统的流控层。要使所有的体系架构都可以重用这部分的代码,中断控制器也被进一步地封装起来,形成了中断子系统中的硬件封装层。我们可以用下面的图示表示通用中断子系统的层次结构:
图 4.1 通用中断子系统的层次结构
硬件封装层 它包含了体系架构相关的所有代码,包括中断控制器的抽象封装,arch相关的中断初始化,以及各个IRQ的相关数据结构的初始化工作,cpu的中断入口也会在arch相关的代码中实现。中断通用逻辑层通过标准的封装接口(实际上就是struct irq_chip定义的接口)访问并控制中断控制器的行为,体系相关的中断入口函数在获取IRQ编号后,通过中断通用逻辑层提供的标准函数,把中断调用传递到中断流控层中。我们看看irq_chip的部分定义:
- struct irq_chip {
- const char *name;
- unsigned int (*irq_startup)(struct irq_data *data);
- void (*irq_shutdown)(struct irq_data *data);
- void (*irq_enable)(struct irq_data *data);
- void (*irq_disable)(struct irq_data *data);
- void (*irq_ack)(struct irq_data *data);
- void (*irq_mask)(struct irq_data *data);
- void (*irq_mask_ack)(struct irq_data *data);
- void (*irq_unmask)(struct irq_data *data);
- void (*irq_eoi)(struct irq_data *data);
- int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
- int (*irq_retrigger)(struct irq_data *data);
- int (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
- int (*irq_set_wake)(struct irq_data *data, unsigned int on);
- ......
- };
看到上面的结构定义,很明显,它实际上就是对中断控制器的接口抽象,我们只要对每个中断控制器实现以上接口(不必全部),并把它和相应的irq关联起来,上层的实现即可通过这些接口访问中断控制器。而且,同一个中断控制器的代码可以方便地被不同的平台所重用。
中断流控层 所谓中断流控是指合理并正确地处理连续发生的中断,比如一个中断在处理中,同一个中断再次到达时如何处理,何时应该屏蔽中断,何时打开中断,何时回应中断控制器等一系列的操作。该层实现了与体系和硬件无关的中断流控处理操作,它针对不同的中断电气类型(level,edge......),实现了对应的标准中断流控处理函数,在这些处理函数中,最终会把中断控制权传递到驱动程序注册中断时传入的处理函数或者是中断线程中。目前内核提供了以下几个主要的中断流控函数的实现(只列出部分):
- handle_simple_irq();
- handle_level_irq(); 电平中断流控处理程序
- handle_edge_irq(); 边沿触发中断流控处理程序
- handle_fasteoi_irq(); 需要eoi的中断处理器使用的中断流控处理程序
- handle_percpu_irq(); 该irq只有单个cpu响应时使用的流控处理程序
中断通用逻辑层 该层实现了对中断系统几个重要数据的管理,并提供了一系列的辅助管理函数。同时,该层还实现了中断线程的实现和管理,共享中断和嵌套中断的实现和管理,另外它还提供了一些接口函数,它们将作为硬件封装层和中断流控层以及驱动程序API层之间的桥梁,例如以下API:
- generic_handle_irq();
- irq_to_desc();
- irq_set_chip();
- irq_set_chained_handler();
驱动程序API 该部分向驱动程序提供了一系列的API,用于向系统申请/释放中断,打开/关闭中断,设置中断类型和中断唤醒系统的特性等操作。驱动程序的开发者通常只会使用到这一层提供的这些API即可完成驱动程序的开发工作,其他的细节都由另外几个软件层较好地“隐藏”起来了,驱动程序开发者无需再关注底层的实现,这看起来确实是一件美妙的事情,不过我认为,要想写出好的中断代码,还是花点时间了解一下其他几层的实现吧。其中的一些API如下:
- enable_irq();
- disable_irq();
- disable_irq_nosync();
- request_threaded_irq();
- irq_set_affinity();
这里不再对每一层做详细的介绍,我将会在本系列的其他几篇文章中做深入的探讨。
5. irq描述结构:struct irq_desc
整个通用中断子系统几乎都是围绕着irq_desc结构进行,系统中每一个irq都对应着一个irq_desc结构,所有的irq_desc结构的组织方式有两种:
基于数组方式 平台相关板级代码事先根据系统中的IRQ数量,定义常量:NR_IRQS,在kernel/irq/irqdesc.c中使用该常量定义irq_desc结构数组:
- struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
- [0 ... NR_IRQS-1] = {
- .handle_irq = handle_bad_irq,
- .depth = 1,
- .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
- }
- };
基于基数树方式 当内核的配置项CONFIG_SPARSE_IRQ被选中时,内核使用基数树(radix tree)来管理irq_desc结构,这一方式可以动态地分配irq_desc结构,对于那些具备大量IRQ数量或者IRQ编号不连续的系统,使用该方式管理irq_desc对内存的节省有好处,而且对那些自带中断控制器管理设备自身多个中断源的外部设备,它们可以在驱动程序中动态地申请这些中断源所对应的irq_desc结构,而不必在系统的编译阶段保留irq_desc结构所需的内存。
下面我们看一看irq_desc的部分定义:
- struct irq_data {
- unsigned int irq;
- unsigned long hwirq;
- unsigned int node;
- unsigned int state_use_accessors;
- struct irq_chip *chip;
- struct irq_domain *domain;
- void *handler_data;
- void *chip_data;
- struct msi_desc *msi_desc;
- #ifdef CONFIG_SMP
- cpumask_var_t affinity;
- #endif
- };
- struct irq_desc {
- struct irq_data irq_data;
- unsigned int __percpu *kstat_irqs;
- irq_flow_handler_t handle_irq;
- #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
- irq_preflow_handler_t preflow_handler;
- #endif
- struct irqaction *action; /* IRQ action list */
- unsigned int status_use_accessors;
- unsigned int depth; /* nested irq disables */
- unsigned int wake_depth; /* nested wake enables */
- unsigned int irq_count; /* For detecting broken IRQs */
- raw_spinlock_t lock;
- struct cpumask *percpu_enabled;
- #ifdef CONFIG_SMP
- const struct cpumask *affinity_hint;
- struct irq_affinity_notify *affinity_notify;
- #ifdef CONFIG_GENERIC_PENDING_IRQ
- cpumask_var_t pending_mask;
- #endif
- #endif
- wait_queue_head_t wait_for_threads;
- const char *name;
- } ____cacheline_internodealigned_in_smp;
对于irq_desc中的主要字段做一个解释:
irq_data 这个内嵌结构在2.6.37版本引入,之前的内核版本的做法是直接把这个结构中的字段直接放置在irq_desc结构体中,然后在调用硬件封装层的chip->xxx()回调中传入IRQ编号作为参数,但是底层的函数经常需要访问->handler_data,->chip_data,->msi_desc等字段,这需要利用irq_to_desc(irq)来获得irq_desc结构的指针,然后才能访问上述字段,者带来了性能的降低,尤其在配置为sparse irq的系统中更是如此,因为这意味着基数树的搜索操作。为了解决这一问题,内核开发者把几个低层函数需要使用的字段单独封装为一个结构,调用时的参数则改为传入该结构的指针。实现同样的目的,那为什么不直接传入irq_desc结构指针?因为这会破坏层次的封装性,我们不希望低层代码可以看到不应该看到的部分,仅此而已。
kstat_irqs 用于irq的一些统计信息,这些统计信息可以从proc文件系统中查询。
action 中断响应链表,当一个irq被触发时,内核会遍历该链表,调用action结构中的回调handler或者激活其中的中断线程,之所以实现为一个链表,是为了实现中断的共享,多个设备共享同一个irq,这在外围设备中是普遍存在的。
status_use_accessors 记录该irq的状态信息,内核提供了一系列irq_settings_xxx的辅助函数访问该字段,详细请查看kernel/irq/settings.h
depth 用于管理enable_irq()/disable_irq()这两个API的嵌套深度管理,每次enable_irq时该值减去1,每次disable_irq时该值加1,只有depth==0时才真正向硬件封装层发出关闭irq的调用,只有depth==1时才会向硬件封装层发出打开irq的调用。disable的嵌套次数可以比enable的次数多,此时depth的值大于1,随着enable的不断调用,当depth的值为1时,在向硬件封装层发出打开irq的调用后,depth减去1后,此时depth为0,此时处于一个平衡状态,我们只能调用disable_irq,如果此时enable_irq被调用,内核会报告一个irq失衡的警告,提醒驱动程序的开发人员检查自己的代码。
lock 用于保护irq_desc结构本身的自旋锁。
affinity_hit 用于提示用户空间,作为优化irq和cpu之间的亲缘关系的依据。
pending_mask 用于调整irq在各个cpu之间的平衡。
wait_for_threads 用于synchronize_irq(),等待该irq所有线程完成。
irq_data结构中的各字段:
irq 该结构所对应的IRQ编号。
hwirq 硬件irq编号,它不同于上面的irq;
node 通常用于hwirq和irq之间的映射操作;
state_use_accessors 硬件封装层需要使用的状态信息,不要直接访问该字段,内核定义了一组函数用于访问该字段:irqd_xxxx(),参见include/linux/irq.h。
chip 指向该irq所属的中断控制器的irq_chip结构指针
handler_data 每个irq的私有数据指针,该字段由硬件封转层使用,例如用作底层硬件的多路复用中断。
chip_data 中断控制器的私有数据,该字段由硬件封转层使用。
msi_desc 用于PCIe总线的MSI或MSI-X中断机制。
affinity 记录该irq与cpu之间的亲缘关系,它其实是一个bit-mask,每一个bit代表一个cpu,置位后代表该cpu可能处理该irq。
这是通用中断子系统系列文章的第一篇,这里不会详细介绍各个软件层次的实现原理,但是有必要对整个架构做简要的介绍:
- 系统启动阶段,取决于内核的配置,内核会通过数组或基数树分配好足够多的irq_desc结构;
- 根据不同的体系结构,初始化中断相关的硬件,尤其是中断控制器;
- 为每个必要irq的irq_desc结构填充默认的字段,例如irq编号,irq_chip指针,根据不同的中断类型配置流控handler;
- 设备驱动程序在初始化阶段,利用request_threaded_irq() api申请中断服务,两个重要的参数是handler和thread_fn;
- 当设备触发一个中断后,cpu会进入事先设定好的中断入口,它属于底层体系相关的代码,它通过中断控制器获得irq编号,在对irq_data结构中的某些字段进行处理后,会将控制权传递到中断流控层(通过irq_desc->handle_irq);
- 中断流控处理代码在作出必要的流控处理后,通过irq_desc->action链表,取出驱动程序申请中断时注册的handler和thread_fn,根据它们的赋值情况,或者只是调用handler回调,或者启动一个线程执行thread_fn,又或者两者都执行;
- 至此,中断最终由驱动程序进行了响应和处理。
6. 中断子系统的proc文件接口
在/proc目录下面,有两个与中断子系统相关的文件和子目录,它们是:
- /proc/interrupts:文件
- /proc/irq:子目录
读取interrupts会依次显示irq编号,每个cpu对该irq的处理次数,中断控制器的名字,irq的名字,以及驱动程序注册该irq时使用的名字,以下是一个例子:
/proc/irq目录下面会为每个注册的irq创建一个以irq编号为名字的子目录,每个子目录下分别有以下条目:
- smp_affinity irq和cpu之间的亲缘绑定关系;
- smp_affinity_hint 只读条目,用于用户空间做irq平衡只用;
- spurious 可以获得该irq被处理和未被处理的次数的统计信息;
- handler_name 驱动程序注册该irq时传入的处理程序的名字;
根据irq的不同,以上条目不一定会全部都出现,以下是某个设备的例子:
# cd /proc/irq
# ls
ls
332
248
......
......
12
11
default_smp_affinity
# ls 332
bcmsdh_sdmmc
spurious
node
affinity_hint
smp_affinity
# cat 332/smp_affinity
3
可见,以上设备是一个使用双核cpu的设备,因为smp_affinity的值是3,系统默认每个中断可以由两个cpu进行处理。
本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/4837319.html,如需转载请自行联系原作者
相关文章:

haskell的分数运算
孩子要上3年级了,里面涉及分数的部分,先准备一下。 haskell中涉及分数的模块是Ratio。 Ratio Synopsis Documentation data Ratio a Rational numbers, with numerator and denominator of some Integral type. Instances Typeable1 Ratio Integral a &g…

【复盘】端端,棒棒哒!
Scratch竞赛交流群已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档)。 昨晚2…

UI设计培训分享:平面广告设计中的文案表达技巧
UI设计培训包含平面设计,而且其中的应用频率是非常大的,本期小编就为大家详细的介绍一下平面广告设计中的文案表达技巧,希望下面的介绍能够帮助到正在学习UI设计的同学们。 平面广告设计中的文案表达技巧,平面广告中文案的编排创意…

工具类——md5
android的开发过程中,数据安全始终是个问题。这里记录一个md5的工具类,感觉挺好用的。 package com.xzw.test; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class TestMD5 { public static…

【青少年编程】【一级】小狗散步
Scratch竞赛交流群已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档)。 小狗散…

avplayer VS2008编译
错误1. typedef void * POINTER_64 PVOID64; 解决办法 typedef void *PVOID;typedef void * POINTER_64 PVOID64;在它之前加下:#define POINTER_64 __ptr64 官网给出的解决办法 打开winnt.h文件(这个是vc安装时带的文件) 找到 #include <…

Python培训分享:python爬虫可以用来做什么?
爬虫又被称为网络蜘蛛,它可以抓取我们页面的一些相关数据,近几年Python技术的到来,让我们对爬虫有了一个新的认知,那就是Python爬虫,下面我们就来看看python爬虫可以用来做什么? Python培训分享:python爬虫…

【字符串操作之】返回指定位置的字符和Unicode 字符代码 根据unicode返回字符→→charAt、charCodeAt和fromCharCode...
//charAt和charCodeAt分别返回指定位置处的字符和字符对应的unicode码 var str:String"abcdefg"; var str2str.charAt(1); var str3str.charCodeAt(1); trace(str2); //b trace(str3); //98 fromCharCode是个静态方法,根据unicode返回字符 var str:String…

E667:Fsync failed(how to solve)
今天在学习一个关闭icmp回显的配置时候,vim出现了Fsync failed这个问题! 下面来说一下我发生这种情况的原因(系统CentOS6.5),那时编辑完后先是输入“q”,正如我们所想,已修改过的配置它会提醒我要把数据写入…

【复盘】第一次灌鸡汤
Scratch竞赛交流群已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档)。 上周日…

Python中常用的数据分析工具(模块)有哪些?
本期Python培训分享:Python中常用的数据分析工具(模块)有哪些?Python本身的数据分析功能并不强,需要安装一些第三方的扩展库来增强它的能力。我们课程用到的库包括NumPy、Pandas、Matplotlib、Seaborn、NLTK等,接下来将针对相关库做一个简单…

Android应用中通过AIDL机制实现进程间的通讯实例
Android中,每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢?显然,Java中是不支持跨进程内存共享的,因此要传递对象,需要把对象解析成操作系统能够理解的数据格式&am…

06 Scratch等级考试(一级)模拟题
Scratch竞赛交流群已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档)。 这是第…

区分BundleVersion和BundleShortVersionString
区分BundleVersion和BundleShortVersionString最近遇到了关于检查更新的版本问题了。问题出在了Info.Plist配置中的两个字段,BundleVersion和BundleShortVersionString。搞了两年的开发,第一次看到还有另一个字段的版本。由于版本检测升级的问题…

UI设计培训技术分享:配色秘籍
设计中颜色的使用是一个非常值得关注的问题,同样的构图、版式,但是不同的颜色搭配给人的感觉就完全不一样,色彩的冷暖,明暗变化琳琅满目,表达不同的氛围与情绪,对于新手设计来讲,配色是个不容小…

安全的Web主机iptables防火墙脚本
下面以自己的Web服务器举例说明之,系统的默认策略是INPUT为DROP,OUTPUT、FORWARD链为ACCEPT,DROP设置得比较宽松,因为我们知道出去的数据包比较安全;为了验证脚本的通用性,我特的查看了服务器的内核及iptab…

用户至上-阿里马马篇
最近经常在阿里巴巴的平台里活动,突然发现,支付宝病了。 当用户生成一单交易后,需要用支付宝支付时,如何保证是用户本人在操作呢? 当初,支付宝是国内第一家很好地解决这个问题的。 解决的途径主要是&#x…

【复盘】小朋友的奇思妙想
Scratch竞赛交流群已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档)。 上周日…

UI设计培训技术分享:搞定萌萌哒可爱图标
UI设计要学到的东西有很多,那么关于图标设计就是其中的一种,很多企业比较忠于萌萌哒的可爱图标,那么如何搞定萌萌哒可爱图标呢?来看看下面UI设计培训技术分享教程。 UI设计培训技术分享:搞定萌萌哒可爱图标 萌萌哒的图标制作有三…

远程处理Remoting
日程 ?应用程序域 ?Remoting和原理 ?编程式和管理式配置实例 用应用程序域 操作系统和运行库环境通常会在应用程序间提供某种形式的隔离。例如,Microsoft Windows 使用进程来隔离应用程序。为确保在一个应用程序中运行的代码不会对其他不相关的应用程序产生不良影…

Datawhale组队学习周报(第002周)
Datawhale组队学习周报(第002周) (一)当下 本周(02月22日~02月28日),我们正在进行5门开源内容的组队学习。一共建立了6个学习群,参与人数1080人。到目前为止,有4门课开…

LVS(Linux Virtual Server)三种负载均衡模型和十种调度的简单介绍
LVS(Linux Virtual Server)三种负载均衡模型和十种调度的简单介绍 LVS (Linux Virtual Server) LVS(Linux Virtual Server)其实就是针对高可伸缩、高可用网络服务的需求,给出了基于IP层和基于内容请求分发的负载平衡调度解决方法,…

UI设计培训分享:设计当中的颜色运用
参加UI设计培训的同学应该都知道,颜色的搭配是学习UI设计非常重要的一步,颜色跟其他的东西一样,适量才会运用得当,如果在你的配色计划中坚持使用马克思三原色的话,你会得到更好的配色结果,为一个项目配色时…

《重构-改善既有代码的设计》读书笔记(二)
12、Lazy Class – 冗赘类 对于几乎没有用的类,运用inline class 将其功能移动。去除这些不值得维护的类。 13、Speculative Generality – 夸夸其谈未来性 对于你现在用不到,觉得总有一天会用到的代码,要警惕。用不上的装置总会挡我们的路&a…

css属性选择符的应用
注释:Internet Explorer 7 (以及更高版本)在规定了 !DOCTYPE 的情况下支持属性选择器。IE6 及更低的版本不支持属性选择器。 [title]{color:red;} //为带有 title 属性的所有元素设置样式: [title"website"]{color:r…

【青少年编程】【答疑】控制Scratch异步代码的执行顺序
问题 几天前,我写了一篇图文 对「等待(0)秒」的理解,发现可以利用「等待(0)秒」这个积木块来解决Scratch中异步代码的执行顺序问题,即点击绿旗后可以控制多个角色中响应该事件的代码的顺序。 …

UI设计培训分享:学习UI设计有哪些技巧
互联网时代的快速发展,UI设计这个行业在互联网有着一席之地,越来越多的人都想要参加UI设计培训班学习,那么对于初学者来说,学习UI设计有哪些技巧呢?来看看下面的详细介绍吧。 学习UI设计有哪些技巧? 1、基础软件操作 UI设计培训…

07 Scratch等级考试(一级)模拟题
Scratch竞赛交流群已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】,即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料(视频、代码、文档)。 这是第…

遮罩层+软键盘
一.清关里边申请清关 上传图片由于本身就是布局用的图片,微信手机长按会出现保存收藏该图片。 解决方法:添加同级元素充当遮罩层。设置样式,把点击事件从设置的上传图片中移除即可。 1)<!-- 图片遮罩层 --> <…

UI培训技术分享:设计大神都在用的10种技法!
越来越多的人开始学习UI设计,想要进群到UI设计这个行业,本期小编为大家介绍的UI培训教程就是关于设计师会经常用到的一些技巧,帮助大家后期的工作中的应用。 UI培训技术分享:设计大神都在用的10种技法! 1.将图片融入背景来使用 同…