IA-32体系概要

IA-32体系结构中由三种模式和一种准操作结构: 实模式:与8086兼容的操作模式,有一些拓展。 保护模式:处理器的一种最基本的操作模式,在这种模式中,处理器的所有指令及体系结构中的所有特色都是可用的,并且能够达到最高性能。 系统管理模式,提供给操作系统的一种透明的管理机制,用于实现电源管理等特殊操作。 虚拟8086模式是一个准操作模式,允许处理器在保护模式中执行实模式的程序。 Intel 64体系结构新增一种IA-32e操作模式包含两个子模式 兼容模式,在该模式下可以不加修改地运行大多数IA-32体系结构的程序 64位模式,可以使用64位线性地址空间和一些新增加的特性。IA-32e不再支持虚拟8086模式 处理器加电或者Reset后默认操作模式是实模式。 实模式和保护模式之间的转换由控制寄存器CR0中的PE位控制。 保护模式和IA-32e模式之间的转换由IA32_EFER寄存器中的LME和CR0中的PE位控制。 兼容模式和64位模式之间的转换由代码段寄存器CS和L位控制。 保护模式和虚拟8086模式之间的转换由标志寄存器EFLAGS中的VM位控制。 进入系统管理模式的唯一途径是SMI中断,在系统管理模式中执行指令RSM会将处理器切换回原来的操作模式。

九月 30, 2021

Life of a Pixel Chromium浏览器内核渲染原理 学习笔记

Chromium浏览器内核中,来自前端的内容如何在最终转换成为屏幕上的各个像素点,也就是浏览器内核渲染过程,这是一个复杂的工程上的一系列步骤。对于这些复杂的步骤我们需要把握的方面包括该过程每个阶段的设计思想、数据模型、数据模型的交互。深入而仔细地理解上述内容,有利与我们阅读庞大源码中始终保持清醒找准定位。下面我将基于我对Life of a Pixel的理解仔细来讨论这个过程。 Life of a Pixel输入与输出 首先需要谈谈输入与输出,这一系列步骤的输入成为Web Content。它由一系列现有协议所定义的一套描述Web内容的文本主要组成,当然也包括其他引用内容。现有的协议(我们常称为编程语言),通常是HTML、CSS与JavaScript。这三者分别有定义了Web内容的结构内容、样式、逻辑。但这并非严格分工,在当下流行的前端设计思想(前后端分离)中JavaScript正在承担着越来越多的职责。JavaScript本身也正在不断地变得独立,近年来逐渐跳出浏览器这个平台来独立发挥其作用(node.js、react-vr)。 另一方面,谈谈输出。如何绘制屏幕上的像素,涉及到计算机图形学方面的理论与工程。在传统上,我们可以认为计算机向屏幕输出内容经历了以下步骤。应用软件将其想要表达的图形内容转换成为对操作系统与图形相关的函数库的调用(OpenGL、Direct X等),这些函数库通过操作系统中安装驱动程序及其他操作系统有关服务向硬件(GPU等)传送数据与指令,并操纵硬件的计算核心与存储器(GPU等)完成光栅化等步骤、最终将硬件(GPU等)存储器中的最终内容转化为向屏幕输出的信号。在这方面,由函数库(OpenGL)所提供的API都是比较低级的。 举个例子,原来我也做过OpenGL相关的编程,虽然现代OpenGL提供一些模型与协议(如管线等)来简化工作,但是其提供的模型以及依照模型设计的API带有明显的硬件气息。对于OpenGL来说,调用者要精确输入预设的或者利用GPU程序计算出的数据其所绘制内容的在几何坐标系下的位置、颜色以及绘制顺序。 由输入输出来大致推断,浏览器的工作是按照先行前端协议(前端编程语言)及其附属多媒体、数据等方面的内容精确理解前端开发者对于Web页面的描述,并通过数据的层层流动与转换计算推断出图形函数库所需的各类信息。现行前端协议的复杂性与兼容性与鲁棒性要求使得这一步骤的实现十分复杂与庞大。而对于性能与稳定的要求更提升了设计与实现上的难度。实现这一系列不仅仅是技术上,而且也是软件工程上的难题。 页面生命周期综述 由上述对于输入与输出的讨论,我们可以理解Chromium团队提出以下有关于页面生命周期。 基于Web Content经过若干步骤产生相关数据模型。 数据模型随时间、交互等因素的不断更新。 其中,对于第二点要求尽可能少地快速地修改由初由第一步骤产生的数据模型,尽可能降低计算成本。其原因在于,第一步骤产生数据模型所进行的相关计算与数据模型的交互对于现有平均性能水平来说依然十分昂贵,所以不断重复执行第一步骤在实际环境中不可取。 初步渲染步骤概论 对于上面提及过的在输入与输出之间的相关步骤,我们将在下面按照前后顺序进行有关论述。 DOM 对于HTML来说,其语法规则有着明显的树状特征。这使得利用HTML能够方便地描述出文档结构并附带部分内容。所以我们需要提取出其中地结构信息与内容信息。在这一步中,HTML文档解析器将解析HTML文档中的文本并转换其为DOM树。 有关于DOM树,不得不提的是JavaScript对于DOM树的操作能力,我认为这也是JavaScript的核心内容之一。JavaScript借由该能力能够对页面进行控制、更新与内容添加、更改、删除等操作,我认为这是前后端分离思想的技术基础。上述能力对DOM树的实际操作由V8引擎具体完成,该引擎实现了JavaScript的操作DOM树的API,使得JavaScript具备该能力。 CSS(style) CSS有着两方面的主要作用,筛选或者指定其作用的HTML标签,定义其所对应HTML标签的内容。对于我们来说,其本质在于筛选或者查找出DOM节点,并将样式信息与DOM节点对应起来。 其中有个问题需要注意,在CSS文件对于某一个或者几个DOM节点的样式的描述中,可能存在着未定义、重复定义、冲突、无效的样式定义。针对这个问题,Chromium团队引入了重计算(recalc)针对DOM树每一个节点计算所有对应的Computed Style。 Layout 有了上面两个步骤提供的信息,我们需要进一步的转换。将DOM节点与Compute Style一道转换为视觉几何结构(Layout)。在这一步中我们需要解决的问题包括文字、表格、布局等等元素的在页面最终位置、排布及大小。为了能够对这些信息进行有效计算并且整理,Chromium构造了Layout Tree。这个数据结构旨在容纳结构有关信息并且进行上述工作。 在代码中,以下结构描述了有关信息。 // A LayoutRect contains the information needed to generate a CGRect that may or // may not be flipped if positioned in RTL or LTR contexts. |boundingWidth| is // the width of the bounding coordinate space in which the resulting rect will // be used. |position| is used to describe the location of the resulting frame, // and |size| is the size of resulting frame. struct LayoutRect { CGFloat boundingWidth; LayoutRectPosition position; CGSize size; }; Layout树与DOM树的节点关系并非一对一,有一些情况下DOM节点并不需要有其对应的Layout对象或者其可以放入其他有关的Layout对象中(通常为父节点对应的Layout对象)。其中有一点正在变化的内容需要注意,legacy layout object与LayoutNG。LayoutNG的提出,是为了解决当前的Layout对象中输入输出及其他中间内容混杂并且在计算过程中父子节点相互引用的问题。原先的设计首先带来了节点数据有效性的确定的问题,正在计算的节点需要判断其引用的数据是其需要的最终状态,不然节点当前所计算出的数据依然可能要在稍后重新计算,这提升了算法设计的复杂度。与此对应,LayoutNG的输入与输出分离,而且输出一旦产生其状态就已经确定且不可以修改,结构清晰,所以在算法设计上相对简单有效率。 ...

九月 7, 2021

UNIX伪终端

介绍 最近在研究有关UNIX的相关理论知识,在此记录相关重要概念备忘。 概述 伪终端是指,对于一个应用程序而言,它看似一个终端,但事实上它并不是一个真正的终端。 通常一个进程打开伪终端主设备,调用fork。子进程建立一个新的会话,打开一个相应的伪终端从设备,将其文件描述符复制到标准输入输出错误,然后调用exec。伪终端从设备称为子进程的控制终端。 看起来像一个双向管道,从设备上的终端行规程使得我们拥有普通管道没有的其他处理能力。 伪终端的典型用途 网络登录服务器 最典型的例子是telnetd和rlogind服务器。 在rlogind服务器和登录shell之间有两个exec调用,这是因为login程序通常在两个exec之间检验用户是否合法。 窗口系统终端模拟 终端模拟器最为shell和窗口管理器之间的媒介。每个shell在自己的窗口中执行。 shell将自己的标准输入、标准输出、标准错误连接到PTY的从设备端。 script程序 script程序将终端会话期间的所有输入和输出信息复制到一个文件中。 使用script的不足是必须处理文件中的控制字符。 expect程序 在非交互模式中驱动交互模式运行。 运行协同进程 当通过管道与协同进程通信时,标准I/O库会完全缓冲标准输入和标准输出,从而引起死锁。 现在协同进程的标准输入和标准输出就像终端设备一样,所以标准I/O库会将这两个流设置为行缓冲。 观看长时间运行程序的输出 由于重定向到文件时,标准I/O库将完全缓冲它的标准输出。 打开伪终端设备 PTY表现得就像物理终端设备一样,因此应用程序就无需在意它们在使用的是何种设备。 在伪设备可用之前,它的权限必须设置,以便应用程序可以访问它。

二月 10, 2021

UNIX 终端I/O

介绍 我阅读并且学习了有关于UNIX系统终端I/O相关的内容。在此记录一些比较关键的概念。 引论 终端I/O十分复杂,原因之一是它应用于许多事物。 综述 终端I/O的两种工作模式:规范模式输入处理(默认)、非规范模式输入处理。 规范模式下,对于每一个读请求,终端驱动程序最多返回一行。 可以认为终端设备是由内核中的终端驱动程序控制的,每一个终端设备都有一个输入队列和一个输出队列。 开启回显功能时,在输入队列和输出队列之间有一个隐含连接。 输入队列长度是有限值。 输出队列虽然也有限,但是程序并不能获取这个值。在输出队列要填满时,内核会直接将写进程休眠。 大多是UNIX系统在一个称为终端行规程的模块中进行全部的规范处理。该模块在内核通用读写函数和实际设备驱动程序之间。 所有可以检测和更改的终端设备特性都包含在termios结构中。 使用tcsetattr和tcgetattr可以设置终端选项进而控制终端。 特殊输入字符 POSIX定义了11个在输入时要特殊处理的字符。在这11个特殊字符中,9个字符的值可以任意更改。 为了更改特殊字符,需要修改termios结构中的c_cc数组的相应项。 POSIX允许禁止使用这些字符。 终端标识 在大多数UNIX系统版本中,控制终端名字一直是/dev/tty。 规范模式与非规范模式 规范模式:发送一个请求,当一行已经输入以后,终端程序立即返回。以下几个条件造成读返回: 所请求的字节数已经读到时,无需读一个完整的行。 当读到一个行界定符号 捕捉到信号,并且该函数不再自动重启 非规范模式:时输入数据不装配成行,不处理特殊字符。当读取指定量的数据后,或者超过指定量的时间后,通知系统返回。该模式下没有关闭对信号的处理,用户始终可以键入一个触发终端产生信号的字符。 终端窗口大小 大多数UNIX系统都提供了一种跟踪当前终端窗口大小的方法,当窗口大小变化的时候,使内核通知前台进程组。内核未每个终端和伪终端都维护了一个winsize结构。

二月 10, 2021