dpdk

“dpdk” dpdk Intel DPDK全称Intel Data Plane Development Kit,是intel提供的数据平面开发工具集,为Intel architecture (IA) 处理器架构下用户空间高效的数据包处理提供库函数和驱动的支持,它不同于Linux系统以通用性设计为目的,而是专注于网络应用中数据包的高性能处理。DPDK应用程序是运行在用户空间上利用自身提供的数据平面库来收发数据包,绕过了Linux内核协议栈对数据包处理过程。Linux内核将DPDK应用程序看作是一个普通的用户态进程,包括它的编译、连接和加载方式和普通程序没有什么两样。DPDK程序启动后只能有一个主线程,然后创建一些子线程并绑定到指定CPU核心上运行。 https://cloud.tencent.com/developer/article/1198333 https://tonydeng.github.io/sdn-handbook/dpdk/ https://github.com/google/cpu_features

2021-06-30 · 1 min · 14 words · -

c, file, open, fopen

“c, file, open, fopen” "" fopen 是 C 标准库函数,用于处理作为流对象的文件的打开。与本质上是系统调用的 open 函数不同,fopen 将 FILE 指针对象与给定的文件相关联。它需要两个参数;第一个参数代表要打开的文件的路径名,第二个参数是打开文件的模式。 open 函数本质上是一个低级的系统服务,即使使用 fopen 也会被调用。需要注意的是,系统调用通常是用 C 库的封装函数提供给最终用户的,但其特点和性能用例与 C stio 库中的函数不同。如: open 在创建新文件时,第二个参数取类型为 int,第三个参数可选,指定文件模式位。 https://www.delftstack.com/zh/howto/c/open-vs-fopen-in-c/

2021-06-29 · 1 min · 27 words · -

win11

“win11” https://github.com/rcmaehl/WhyNotWin11

2021-06-29 · 1 min · 2 words · -

UDP

“UDP” UDP UDP 协议全称是用户数据报协议,在网络中它与 TCP 协议一样用于处理数据包,是一种无连接的协议.在 OSI 中,第四层传输层,处于 IP 协议的上一层 UDP 有不提供数据包分组,组装和不能对数据包进行排序的缺点,也就是说,当报文发送后,无法监控其是否完整安全到达的,就想一个坏掉了的水龙头,你不论怎么让他停止他都只会输出,也不管你的桶满没满,就像爱一样 文章相关视频讲解: C/C++ Linux 服务器开发高级架构师学习视频点击: C/C++Linux服务器开发高级架构/Linux后台架构师-学习视频 底层原理到徒手实现 TCP/IP网络协议栈 tcpip协议栈与网络API的关联,udp的并发性比tcp强? 2|1 特点 面向无连接: 首先 UDP 是不需要和 TCP 一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了.并且也只是主句报文的搬运工,不会对数据报文进行任何拆分和拼接操作 具体来说: 在发送端,应用层将数据传递给 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下 UDP,然后就传递给网络层了 在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报头就传递给应用层,不会任何拼接操作 有单播,多播,广播的功能 UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播和广播的功能. UDP 是面向报文的 发送方的 UDP 读应用程序交下来的报文,在添加首部后就向下交付 IP 层.UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界.因此,应用程序必须选择合适大小的报文 不可靠性 首先不可靠性体现在无连接上,通信不需要建立连接,想发就发,这样的情况肯定不可靠 并且受到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了 再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据,即使网络条件不好,也不会对发送数据进行调整.这样实现的弊端就是在网络条件不好的情况下会导致丢包,但是有点也很明显,比如电话会议等等最好就是 UDP 头部开销小,传输数据报文是很高效的. 因此 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的 Linux网络编程-UDP和TCP协议详解 原文链接: https://xie.infoq.cn/article/760f379a3e3f2694b5e994ffd?utm_source=rss&utm_medium=article

2021-06-22 · 1 min · 69 words · W10N

Ruckus R310, 优科

“Ruckus R310, 优科” 默认用户名密码 super/sp-admin 软件升级 [https://support.ruckuswireless.com/software?filter=88#sort=relevancy&f:@source=Software%20Downloads]&f:@commonproducts=[R310] https://support.ruckuswireless.com/software/2791-ruckus-solo-access-point-110-0-0-0-2014-ga-refresh2-software-release-r310 Ruckus Solo Access Point 110.0.0.0.2014 (GA Refresh2) Software Release (R310) 操作前的准备 认识硬件 LED状态灯 我们拿一台 Ruckus 2942 AP 来讲解。这个型号已经停产,而且是单频 2.4GHz AP,但是 LED 灯的状态和含义都是相同的。真正的原因是我不想重新做图,懒。 OPT- 没用,永远不亮。有些新的型号已经取消了OPT灯 WLAN- 现在基本上都是双频AP,所以不再有WLAN灯,取而代之的是2.4G和5G灯。有以下几种状态 (胖AP只会出现前3种) : 灭- 表示WLAN服务没有启用 (默认情况下WLAN服务是关闭的) 橙色长亮- 表示WLAN服务已经开启,但是没有客户端连接到Radio 绿色长亮- 表示WLAN服务已经开启,并且已经有客户端连接到Radio 绿色慢闪- 表示AP是Mesh AP,WLAN服务已经开启,但是没有客户端连接到Radio 绿色快闪- 表示AP是Mesh AP,WLAN服务已经开启,并且已经有客户端连接到Radio DIR- 控制器管理状态灯,有以下几种状态: 灭- AP是胖AP,没有被控制器管理 绿色长亮- AP是瘦AP,并且已经和控制器同步 绿色快闪 AP是瘦AP,正在和控制器同步,或者正在更新固件 绿色慢闪 AP是瘦AP,正在寻找控制器 (如果一直处于这种状态, 就要检查网络连通性) AIR- Mesh上行链路状态灯,有些型号的双频AP没有AIR灯,用5G灯来充当AIR灯的功能: 灭- AP是Root AP,或者Mesh被禁用 绿色长亮- Mesh上行链路良好 绿色快闪- Mesh上行链路不佳 (此时需要检查干扰情况,或者调整AP的位置和间距) 绿色慢闪- Mesh上行链路不存在,AP没有找到Root AP 红色 AP硬件损坏 NOTE1: Mesh技术介绍 http://baike.baidu.com/view/1215700.htm NOTE2: AP都会有一个Reset按键,是一个凹陷的孔。先把AP加电,2-3秒钟之后,用曲别针之类的东西按住Reset键 6 秒钟再松手,AP就可以恢复出厂设置。为了避免Reset失败,最好按8秒再松手。 NOTE3: 有些型号的AP还会有一个soft reset,作用是重启AP。 ...

2021-06-20 · 2 min · 335 words · -

Redis Replication, sentinel

“Redis Replication, sentinel” Redis 主从 Replication 的配置 beanlam 发布于 2015-04-20 本专栏与Redis相关的文章 Redis Sentinel机制与用法 (一) Redis Sentinel机制与用法 (二) Jedis的JedisSentinelPool源代码分析 Jedis的Sharded源代码分析 Redis 主从 Replication 的配置 详解Redis SORT命令 JedisCommand接口说明 本文参考翻译自《Redis Replication documentation》 概述 Redis的replication机制允许slave从master那里通过网络传输拷贝到完整的数据备份。具有以下特点: 异步复制。从2.8版本开始,slave能不时地从master那里获取到数据。 允许单个master配置多个slave slave允许其它slave连接到自己。一个slave除了可以连接master外,它还可以连接其它的slave。形成一个图状的架构。 master在进行replication时是非阻塞的,这意味着在replication期间,master依然能够处理客户端的请求。 slave在replication期间也是非阻塞的,也可以接受来自客户端的请求,但是它用的是之前的旧数据。可以通过配置来决定slave是否在进行replication时用旧数据响应客户端的请求,如果配置为否,那么slave将会返回一个错误消息给客户端。不过当新的数据接收完全后,必须将新数据与旧数据替换,即删除旧数据,在替换数据的这个时间窗口内,slave将会拒绝客户端的请求和连接。 一般使用replication来可以实现扩展性,例如说,可以将多个slave配置为“只读”,或者是纯粹的数据冗余备份。 能够通过replication来避免master每次持久化时都将整个数据集持久化到硬盘中。只需把master配置为不进行save操作(把配置文件中save相关的配置项注释掉即可),然后连接上一个slave,这个slave则被配置为不时地进行save操作的。不过需要注意的是,在这个用例中,必须确保master不会自动启动。更多详情请继续往下读。 Master持久化功能关闭时Replication的安全性 当有需要使用到replication机制时,一般都会强烈建议把master的持久化开关打开。即使为了避免持久化带来的延迟影响,不把持久化开关打开,那么也应该把master配置为不会自动启动的。 为了更好地理解当一个不进行持久化的master如果允许自动启动所带来的危险性。可以看看下面这种失败情形: 假设我们有一个redis节点A,设置为master,并且关闭持久化功能,另外两个节点B和C是它的slave,并从A复制数据。 如果A节点崩溃了导致所有的数据都丢失了,它会有重启系统来重启进程。但是由于持久化功能被关闭了,所以即使它重启了,它的数据集是空的。 而B和C依然会通过replication机制从A复制数据,所以B和C会从A那里复制到一份空的数据集,并用这份空的数据集将自己本身的非空的数据集替换掉。于是就相当于丢失了所有的数据。 即使使用一些HA工具,比如说sentinel来监控master-slaves集群,也会发生上述的情形,因为master可能崩溃后迅速恢复。速度太快而导致sentinel无法察觉到一个failure的发生。 当数据的安全很重要、持久化开关被关闭并且有replication发生的时候,那么应该禁止实例的自启动。 replication工作原理 如果你为master配置了一个slave,不管这个slave是否是第一次连接上Master,它都会发送一个SYNC命令给master请求复制数据。 master收到SYNC命令后,会在后台进行数据持久化,持久化期间,master会继续接收客户端的请求,它会把这些可能修改数据集的请求缓存在内存中。当持久化进行完毕以后,master会把这份数据集发送给slave,slave会把接收到的数据进行持久化,然后再加载到内存中。然后,master再将之前缓存在内存中的命令发送给slave。 当master与slave之间的连接由于某些原因而断开时,slave能够自动重连Master,如果master收到了多个slave并发连接请求,它只会进行一次持久化,而不是一个连接一次,然后再把这一份持久化的数据发送给多个并发连接的slave。 当master和slave断开重连后,一般都会对整份数据进行复制。但从redis2.8版本开始,支持部分复制。 数据部分复制 从2.8版本开始,slave与master能够在网络连接断开重连后只进行部分数据复制。 master会在其内存中创建一个复制流的等待队列,master和它所有的slave都维护了复制的数据下标和master的进程id,因此,当网络连接断开后,slave会请求master继续进行未完成的复制,从所记录的数据下标开始。如果进程id变化了,或者数据下标不可用,那么将会进行一次全部数据的复制。 支持部分数据复制的命令是PSYNC 不需硬盘参与的Replication 一般情况下,一次复制需要将内存的数据写到硬盘中,再将数据从硬盘读进内存,再发送给slave。 对于速度比较慢的硬盘,这个操作会给master带来性能上的损失。Redis2.8版本开始,实验性地加上了无硬盘复制的功能。这个功能能将数据从内存中直接发送到slave,而不用经过硬盘的存储。 不过这个功能目前处于实验阶段,还未正式发布。 相关配置 与replication相关的配置比较简单,只需要把下面一行加到slave的配置文件中: slaveof 192.168.1.1 6379 你只需要把ip地址和端口号改一下。当然,你也可以通过客户端发送SLAVEOF命令给slave。 部分数据复制有一些可调的配置参数,请参考redis.conf文件。 无硬盘复制功能可以通过repl-diskless-sync来配置,另外一个配置项repl-diskless-sync-delay用来配置当收到第一个请求时,等待多个slave一起来请求之间的间隔时间。 只读的slave 从redis2.6版本开始,slave支持只读模式,而且是默认的。可以通过配置项slave-read-only来进行配置,并且支持客户端使用CONFIG SET命令来动态修改配置。 ...

2021-06-18 · 1 min · 111 words · -

pve + openwrt

pve + openwrt 局域网网段: 192.168.50.0/24 pve 宿主机 ip: 192.168.50.6 软路由 ip: 192.168.50.1 download openwrt image 下载 “ext4-combined-efi” curl -O https://downloads.openwrt.org/releases/19.07.7/targets/x86/64/openwrt-19.07.7-x86-64-combined-ext4.img.gz curl -O https://downloads.openwrt.org/releases/21.02.3/targets/x86/64/openwrt-21.02.3-x86-64-generic-ext4-combined-efi.img.gz curl -O https://downloads.openwrt.org/releases/24.10.0/targets/x86/64/openwrt-24.10.0-x86-64-generic-ext4-combined-efi.img.gz upload image to pve # 解压出 .img 文件 gunzip openwrt-19.07.7-x86-64-combined-ext4.img.gz 把 openwrt-24.10.0-x86-64-generic-ext4-combined-efi.img 上传到 pve local pve>local(xxx)>ISO Images>upload 创建虚拟机 点击 “创建虚拟机(Create VM)”, 填写虚拟机名称 (例如 openwrt-24-10), 选"高级",勾选"开机自启动" (软路由必须开机启动) ,点击"下一步"。 OS: CD/DVD 选择 “Do not use any media”(不要去选择刚才上传的镜像),点击"下一步"。 System: 系统选项卡全部默认,点击"下一步"。 Disk: 硬盘不用改,之后会删除,会用上一步下载的 .img 镜像创建虚拟磁盘。 CPU 核心数量按需添加,一般双核足够了 内存 256MB 以上都是够的,系统有富余就多加一点,一般不用超过 2GB,点击"下一步" Network: PVE 虚拟机可选网卡模型 (虚拟网卡) 有 Intel E1000、VirtIO (半虚拟化) 、Realtek RTL8139和VMware vmxnet3四种。建议选用默认的 VirtIO (半虚拟化) ,其性能和效率最高。 分离不用的硬盘: 选择刚刚创建的虚拟机 > 硬件(Hardware) > Hard Disk(scsi0) > 点击"分离(Detach)", 然后它会变成 unused disk。 删除不用的硬盘和光驱: 选中"Unused disk 0",点击"删除";再用同样的方法删除不用的光驱。 添加启动盘 上传 Openwrt 镜像: 选择"pve"节点 > local存储空间 > 内容 > 点击上传 > 选择"openwrt-24.10.0-x86-64-generic-ext4-combined-efi.img"镜像 > 点击"上传"。 ...

2021-06-17 · 2 min · 358 words · -

macos apps

macos apps CleanMyMac X Bob, 词典 Monosnap, 截图 Stats, https://github.com/exelban/stats, 监控 Itsycal, 在任务栏显示日历周 RealVNC® Viewer golang iterm2, another terminal wechat brew brew 是 Mac 下的一个包管理工具, 作用类似于 centos 下的 yum # brew install package_0 nodejs obsidian go fping other Tunnelblick, openvpn gui client Sketch, 矢量绘图

2021-06-16 · 1 min · 44 words · -

valgrind

“valgrind” Valgrind是用于构建动态分析工具的探测框架。它包括一个工具集,每个工具执行某种类型的调试、分析或类似的任务,以帮助完善你的程序。Valgrind的架构是模块化的,所以可以容易地创建新的工具而又不会扰乱现有的结构。 Valgrind中许多有用的工具被作为标准而提供。 Memcheck是一个内存错误检测器。它有助于使你的程序,尤其是那些用C和C++写的程序,更加准确。 Cachegrind是一个缓存和分支预测分析器。它有助于使你的程序运行更快。 Callgrind是一个调用图缓存生成分析器。它与Cachegrind的功能有重叠,但也收集Cachegrind不收集的一些信息。 Helgrind是一个线程错误检测器。它有助于使你的多线程程序更加准确。 DRD也是一个线程错误检测器。它和Helgrind相似,但使用不同的分析技术,所以可能找到不同的问题。 Massif是一个堆分析器。它有助于使你的程序使用更少的内存。 DHAT是另一种不同的堆分析器。它有助于理解块的生命期、块的使用和布局的低效等问题。 SGcheck是一个实验工具,用来检测堆和全局数组的溢出。它的功能和Memcheck互补: SGcheck找到Memcheck无法找到的问题,反之亦然。 BBV是个实验性质的SimPoint基本块矢量生成器。它对于进行计算机架构的研究和开发很有用处。 也有一些对大多数用户没有用的小工具: Lackey是演示仪器基础的示例工具;Nulgrind是一个最小化的Valgrind工具,不做分析或者操作,仅用于测试目的。 https://yuanfentiank789.github.io/2018/11/01/%E7%94%A8Valgrind%E6%A3%80%E6%B5%8B%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/

2021-06-15 · 1 min · 16 words · -

进程状态

“进程状态” 进程的状态 linux (本文使用linux4.8.4) 下,进程状态大致有7种。 进程状态 说明 TASK_RUNNING 可运行状态。未必正在使用CPU,也许是在等待调度 TASK_INTERRUPTIBLE 可中断的睡眠状态。正在等待某个条件满足 TASK_UNINTERRUPTIBLE 不可中断的睡眠状态。不会被信号中断 __TASK_STOPPED 暂停状态。收到某种信号,运行被停止 __TASK_TRACED 被跟踪状态。进程停止,被另一个进程跟踪 EXIT_ZOMBIE 僵尸状态。进程已经退出,但尚未被父进程或者init进程收尸 EXIT_DEAD 真正的死亡状态 在include/linux/sched.h中,进程状态的定义并没有那么少: /* Task state bitmask. NOTE! These bits are also encoded in fs/proc/array.c: get_task_state(). We have two separate sets of flags: task->state is about runnability, while task->exit_state are about the task exiting. Confusing, but this way modifying one set can’t modify the other one by mistake. / #define TASK_RUNNING 0 #define TASK_INTERRUPTIBLE 1 #define TASK_UNINTERRUPTIBLE 2 #define __TASK_STOPPED 4 #define __TASK_TRACED 8 / in tsk->exit_state / #define EXIT_DEAD 16 #define EXIT_ZOMBIE 32 #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD) / in tsk->state again */ #define TASK_DEAD 64 #define TASK_WAKEKILL 128 #define TASK_WAKING 256 #define TASK_PARKED 512 #define TASK_NOLOAD 1024 #define TASK_NEW 2048 #define TASK_STATE_MAX 4096 #define TASK_STATE_TO_CHAR_STR “RSDTtXZxKWPNn” ...

2021-06-14 · 5 min · 880 words · -

用户栈和内核栈

“用户栈和内核栈” 进程是程序的一次执行过程。用剧本和演出来类比,程序相当于剧本,而进程则相当于剧本的一次演出,舞台、灯光则相当于进程的运行环境。 进程的堆栈 每个进程都有自己的堆栈,内核在创建一个新的进程时,在创建进程控制块 task_struct 的同时,也为进程创建自己堆栈。一个进程有2个堆栈,用户堆栈和内核堆栈;用户堆栈的空间指向用户地址空间,内核堆栈的空间指向内核地址空间。当进程在用户态运行时,CPU 堆栈指针寄存器指向用户堆栈地址,使用用户堆栈,当进程运行在内核态时,CPU 堆栈指针寄存器指向的是内核栈空间地址,使用的是内核栈; 进程用户栈和内核栈之间的切换 当进程由于中断或系统调用从用户态转换到内核态时,进程所使用的栈也要从用户栈切换到内核栈。系统调用实质就是通过指令产生中断,称为软中断。进程因为中断 (软中断或硬件产生中断) ,使得CPU切换到特权工作模式,此时进程陷入内核态,进程进入内核态后,首先把用户态的堆栈地址保存在内核堆栈中,然后设置堆栈指针寄存器的地址为内核栈地址,这样就完成了用户栈向内核栈的切换。 当进程从内核态切换到用户态时,最后把保存在内核栈中的用户栈地址恢复到CPU栈指针寄存器即可,这样就完成了内核栈向用户栈的切换。 这里要理解一下内核堆栈。前面我们讲到,进程从用户态进入内核态时,需要在内核栈中保存用户栈的地址。那么进入内核态时,从哪里获得内核栈的栈指针呢? 要解决这个问题,先要理解从用户态刚切换到内核态以后,进程的内核栈总是空的。这点很好理解,当进程在用户空间运行时,使用的是用户栈;当进程在内核态运行时,内核栈中保存进程在内核态运行的相关信息,但是当进程完成了内核态的运行,重新回到用户态时,此时内核栈中保存的信息全部恢复,也就是说,进程在内核态中的代码执行完成回到用户态时,内核栈是空的。 理解了从用户态刚切换到内核态以后,进程的内核栈总是空的,那刚才这个问题就很好理解了,因为内核栈是空的,那当进程从用户态切换到内核态后,把内核栈的栈顶地址设置给CPU的栈指针寄存器就可以了。 X86 Linux内核栈定义如下 (可能现在的版本有所改变,但不妨碍我们对内核栈的理解) : 在/include/linux/sched.h中定义了如下一个联合结构: union task_union { struct task_struct task; unsigned long stack[2408]; }; 从这个结构可以看出,内核栈占8kb的内存区。实际上,进程的task_struct结构所占的内存是由内核动态分配的,更确切地说,内核根本不给task_struct分配内存,而仅仅给内核栈分配8K的内存,并把其中的一部分给task_struct使用。 这样内核栈的起始地址就是union task_union变量的地址+8K 字节的长度。例如: 我们动态分配一个union task_union类型的变量如下: unsigned char *gtaskkernelstack gtaskkernelstack = kmalloc(sizeof(union task_union)); 那么该进程每次进入内核态时,内核栈的起始地址均为: (unsigned char *) gtaskkernelstack + 8096 进程上下文 进程切换现场称为进程上下文(context),包含了一个进程所具有的全部信息,一般包括: 进程控制块 (Process Control Block,PCB) 、有关程序段和相应的数据集。 进程控制块PCB (任务控制块) 进程控制块是进程在内存中的静态存在方式,Linux内核中用task_struct表示一个进程 (相当于进程的人事档案) 。进程的静态描述必须保证一个进程在获得CPU并重新进入运行态时,能够精确的接着上次运行的位置继续进行,相关的程序段,数据以及CPU现场信息必须保存。处理机 现场信息主要包括处理机内部寄存器和堆栈等基本数据。 进程控制块一般可以分为进程描述信息、进程控制信息,进程相关的资源信息和CPU现场保护机构。 进程的切换 当一个进程的时间片到时,进程需要让出CPU给其他进程运行,内核需要进行进程切换。 Linux 的进程切换是通过调用函数进程切换函数schedule来实现的。进程切换主要分为2个步骤: ...

2021-06-10 · 2 min · 380 words · -

chrome 为什么多进程而不是多线程

chrome 为什么多进程而不是多线程 https://www.zhihu.com/question/368712837 多进程有四点好处。1,chromium项目创建初期,webkit不属于谷歌。他们对苹果的东西不信任,而且各种页面渲染时候的崩溃也很大。那时候webkit在chromium里的地位就是个小小第三方库。所以需要把渲染放到另外个进程防止崩溃了影响主进程。2,同样的,webkit那时候很多内存泄露。多进程能很大程度避免。一个进程关了,所有内存就回收了。当时谷歌还写文章鄙视了下那些说多进程占用内存多的人。3,多进程安全性更好。如果blink被发现什么提权漏洞,例如写一段js就能控制整个chromium进程做任何事情,显然多进程可以把损失限制在渲染线程。渲染线程拿不到主进程的各种私密信息,例如别的域名下的密码4,另外有个点大家没说的地方就是,webkit内部很多全局变量。如果要做到一个页面一个线程,理论上很难搞。谷歌其实考虑过想搞一个单进程多线程模式,后来发现不好搞就放弃了。。这个模式在移动平台还是有优势的。以前的手机性能和内存还很差。多进程很消耗内存。chromium刚移植到安卓上时,还是30几版本。性能和稳定性远不如webkit单进程。那时候安卓版chromium就是单进程模式。 作者: 龙泉寺扫地僧 链接: https://www.zhihu.com/question/368712837/answer/994040540 来源: 知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 Chromium里有三种进程——浏览器、渲染器和插件。浏览器进程只有一个,管理窗口和tab,也处理所有的与磁盘,网络,用户输入和显示的工作。这就是我们看到的“Chrome界面”。渲染器开多个。每个渲染器负责处理HTML、CSS、js、图片等,将其转换成用户可见的数据。当时Chrome使用开源的webkit实现这个功能。顺便说一句,webkit是由Apple开发的,当时有很多坑,也被长期吐槽;现在Chrome已经转成使用自家的Blink引擎了。插件会开很多。每个类型的插件在第一次使用时会启动一个相应的进程。 作者: 大宽宽 链接: https://www.zhihu.com/question/368712837/answer/999401453 来源: 知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 Blink不再是WebKit: http://www.chromium.org/blink BLINK内核就是谷歌公司,针对WEBKIT内核,做的修订和精简。 去掉了几十万行的没用的复杂代码,让效率更高。然后针对未来的网页格式,做了进一步优化,和效率提升的处理。 所以BLINK内核可以看成是WEBKIT的精简高效强化版。 https://blog.chromium.org/2008/09/multi-process-architecture.html

2021-06-09 · 1 min · 25 words · -

寄存器, Register

“寄存器, Register” 寄存器 自1946年冯·诺伊曼领导下诞生的世界上第一台通用电子计算机ENIAC至今,计算机技术已经发展了七十多载。 从当初专用于数学计算的庞然大物,到后来大型机服务器时代,从个人微机技术蓬勃发展,到互联网浪潮席卷全球,再到移动互联网、云计算日新月异的当下,计算机变的形态各异,无处不在。 这七十多年中,出现了数不清的编程语言,通过这些编程语言,又开发了无数的应用程序。 可无论什么样的应用程序,什么样的编程语言,最终的程序逻辑都是要交付给CPU去执行实现的 (当然这里有些不严谨,除了CPU,还有协处理器、GPU等等) 。所以了解和学习CPU的原理都是对计算机基础知识的夯实大有裨益。 在七十多年的漫长历程中,也涌现了不少架构的CPU。 MIPS PowerPC x86/x64 IA64 ARM 这篇文章就以市场应用最为广泛的x86-x64架构为目标,通过学习了解它内部的100个寄存器功能作用,来串联阐述CPU底层工作原理。 通过这篇文章,你将了解到: CPU指令执行原理 内存寻址技术 软件调试技术原理 中断与异常处理 系统调用 CPU多任务技术 什么是寄存器 寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果以及一些CPU运行需要的信息。 x86架构CPU走的是复杂指令集 (CISC) 路线,提供了丰富的指令来实现强大的功能,与此同时也提供了大量寄存器来辅助功能实现。这篇文章将覆盖下面这些寄存器: 通用寄存器 标志寄存器 指令寄存器 段寄存器 控制寄存器 调试寄存器 描述符寄存器 任务寄存器 MSR寄存器 通用寄存器 首当其冲的是通用寄存器,这些的寄存器是程序执行代码最最常用,也最最基础的寄存器,程序执行过程中,绝大部分时间都是在操作这些寄存器来实现指令功能。 所谓通用,即这些寄存器CPU没有特殊的用途,交给应用程序"随意"使用。注意,这个随意,我打了引号,对于有些寄存器,CPU有一些潜规则,用的时候要注意。 eax: 通常用来执行加法,函数调用的返回值一般也放在这里面 ebx: 数据存取 ecx: 通常用来作为计数器,比如for循环 edx: 读写I/O端口时,edx用来存放端口号 esp: 栈顶指针,指向栈的顶部, Stack Pointer, SP, 堆栈指针 ebp: 栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量 esi: 字符串操作时,用于存放数据源的地址 edi: 字符串操作时,用于存放目的地址的,和esi两个经常搭配一起使用,执行字符串的复制等操作 在x64架构中,上面的通用寄存器都扩展成为64位版本,名字也进行了升级。当然,为了兼容32位模式程序,使用上面的名字仍然是可以访问的,相当于访问64位寄存器的低32位。 rax rbx rcx rdx rsp rbp rsi rdi 除了扩展原来存在的通用寄存器,x64架构还引入了8个新的通用寄存器: ...

2021-05-08 · 2 min · 282 words · -

redis basic

redis basic commands redis-cli -h 127.0.0.1 -p 6379 # -a 使用认证密码登录 redis-cli -h 127.0.0.1 -p 6379 -a password0 # -n 指定 db redis-cli -h 127.0.0.1 -p 6379 -a password0 -n 10 # OBJECT ENCODING 命令可以查看一个数据库键的值对象的编码 OBJECT ENCODING key0 # 分析 redis key 大小 debug object key0 # Value at:0x7f6bffc22a00 refcount:1 encoding:raw serializedlength:7164 lru:12841785 lru_seconds_idle:95 # 查看各个库的 key 数量 info keyspace # 不进入交互模式, 直接执行命令 redis-cli -h 127.0.0.1 -p 6379 hget key0 field0 延迟时间 redis-cli --latency -h 192.168.50.100 -p 6379 sort https://segmentfault.com/a/1190000002806846 ...

2021-05-07 · 5 min · 1057 words · -

fork vfork clone pthread_create

“fork vfork clone pthread_create” Linux通过clone系统调用实现fork.调用通过一系列的参数标志来指明父、子进程需要共享的资源。fork、vfork、和__clone的库函数都根据各自需要的参数标志去调用clone,然后由clone()去调用do_fork()。 arch(X86)架构的是: fork、vfork、和__clone的库函数最终调用的都是clone系统调用。 至于其它的架构的,可能是通过fork和vfork系统调用。这和本身的实现有关。当然在现在的大多数Linux内核中,就算调用的是fork,在底层基本上传递给do_fork的参数都带有能实现写时复制的一些标志。 fork和 pthread_create,然后利用strace跟踪两者的调用过程, 都是调用的clone。 在Linux中主要提供了fork、vfork、clone三个进程创建方法。 在linux源码中这三个调用的执行过程是执行fork(),vfork(),clone()时,通过一个系统调用表映射到sys_fork(),sys_vfork(),sys_clone(),再在这三个函数中去调用do_fork()去做具体的创建进程工作。 fork fork创建一个进程时,子进程只是完全复制父进程的资源,复制出来的子进程有自己的task_struct结构和pid,但却复制父进程其它所有的资源。例如,要是父进程打开了五个文件,那么子进程也有五个打开的文件,而且这些文件的当前读写指针也停在相同的地方。所以,这一步所做的是复制。这样得到的子进程独立于父进程, 具有良好的并发性,但是二者之间的通讯需要通过专门的通讯机制,如: pipe,共享内存等机制, 另外通过fork创建子进程,需要将上面描述的每种资源都复制一个副本。这样看来,fork是一个开销十分大的系统调用,这些开销并不是所有的情况下都是必须的,比如某进程fork出一个子进程后,其子进程仅仅是为了调用exec执行另一个可执行文件,那么在fork过程中对于虚存空间的复制将是一个多余的过程。但由于现在Linux中是采取了copy-on-write(COW写时复制)技术,为了降低开销,fork最初并不会真的产生两个不同的拷贝,因为在那个时候,大量的数据其实完全是一样的。写时复制是在推迟真正的数据拷贝。若后来确实发生了写入,那意味着parent和child的数据不一致了,于是产生复制动作,每个进程拿到属于自己的那一份,这样就可以降低系统调用的开销。所以有了写时复制后呢,vfork其实现意义就不大了。 fork()调用执行一次返回两个值,对于父进程,fork函数返回子程序的进程号,而对于子程序,fork函数则返回零,这就是一个函数返回两次的本质。 在fork之后,子进程和父进程都会继续执行fork调用之后的指令。子进程是父进程的副本。它将获得父进程的数据空间,堆和栈的副本,这些都是副本,父子进程并不共享这部分的内存。也就是说,子进程对父进程中的同名变量进行修改并不会影响其在父进程中的值。但是父子进程又共享一些东西,简单说来就是程序的正文段。正文段存放着由cpu执行的机器指令,通常是read-only的。下面是一个验证的例子: //例1: fork.c #include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> int main() { int a = 5; int b = 2; pid_t pid; pid = fork(); if(pid == 0) { a = a-4; printf("I'm a child process with PID [%d],the value of a: %d,the value of b:%d.\n",pid,a,b); }else if(pid < 0) { perror("fork"); }else { printf("I'm a parent process, with PID [%d], the value of a: %d, the value of b:%d.\n", pid, a, b); } return 0; } #gcc –o fork fork.c #./fork //运行结果: I’m a child process with PID[0],the value of a:1,the value of b:2. I’m a parent process with PID[19824],the value of a:5,the value of b:2. //例1: fork.c #include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<errno.h> int main() { int a = 5; int b = 2; pid_t pid; pid = fork(); if(pid == 0) { a = a-4; printf("I'm a child process with PID [%d],the value of a: %d,the value of b:%d.\n",pid,a,b); }else if(pid < 0) { perror("fork"); }else { printf("I'm a parent process, with PID [%d], the value of a: %d, the value of b:%d.\n", pid, a, b); } return 0; } #gcc –o fork fork.c #./fork ...

2021-05-06 · 12 min · 2459 words · -

workqueue

“workqueue” 转自: http://bgutech.blog.163.com/blog/static/18261124320116181119889/ 什么是workqueue Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个 数创建线程的数量,使得线程处理的事务能够并行化。workqueue是内核中实现简单而有效的机制,他显然简化了内核daemon的创建,方便了用户的 编程. 工作队列 (workqueue) 是另外一种将工作推后执行的形式.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。最重要的就是工作队列允许被重新调度甚至是睡眠。 那么,什么情况下使用工作队列,什么情况下使用tasklet。如果推后执行的任务需要睡眠,那么就选择工作队列。如果推后执行的任务不需要睡眠,那么就 选择tasklet。另外,如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上下文运行的下半部实现的机 制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,它都会非常有用。如果不需要用一个内核 线程来推后执行工作,那么就考虑使用tasklet。

2021-05-05 · 1 min · 14 words · -

上下文切换

“上下文切换” 操作系统上线程的切换也不是免费的,线程切换其实会带来额外的开销,其中包括: 保存线程 1 的执行上下文; 加载线程 2 的执行上下文; 频繁的对线程的上下文进行切换可能还会导致性能地急剧下降,这可能会导致我们不仅没有提升请求处理的平均速度,反而进行了负优化,所以这也是为什么 Redis 对于使用多线程技术非常谨慎。 我们都知道,Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行。当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将 CPU 轮流分配给它们,造成多任务同时运行的错觉。 而在每个任务运行前,CPU 都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好CPU 寄存器和程序计数器 什么是 CPU 上下文 CPU 寄存器和程序计数器就是 CPU 上下文,因为它们都是 CPU 在运行任何任务前,必须的依赖环境。 CPU 寄存器是 CPU 内置的容量小、但速度极快的内存。 程序计数器则是用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置。 什么是 CPU 上下文切换 就是先把前一个任务的 CPU 上下文 (也就是 CPU 寄存器和程序计数器) 保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。 而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。 CPU 上下文切换的类型 根据任务的不同,可以分为以下三种类型 - 进程上下文切换 - 线程上下文切换 - 中断上下文切换 进程上下文切换 Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应着下图中, CPU 特权等级的 Ring 0 和 Ring 3。 内核空间 (Ring 0) 具有最高权限,可以直接访问所有资源; 用户空间 (Ring 3) 只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源。 ...

2021-05-05 · 1 min · 178 words · -

kernel thread, 内核线程, KTL

kernel thread, 内核线程, KTL 内核线程, ktl 为什么需要内核线程 Linux 内核可以看作一个服务进程(管理软硬件资源,响应用户进程的种种合理以及不合理的请求). 内核需要多个执行流并行,为了防止可能的阻塞,支持多线程是必要的. 内核线程就是内核的分身,一个分身可以处理一件特定事情。内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位。 这与用户线程是不一样的。因为内核线程只运行在内核态 因此,它只能使用大于P AGE_OFFSET (传统的x86_32上是3G) 的地址空间。 内核线程概述 内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托给独立的进程,它与内核中的其他进程"并行"执行。内核线程经常被称之为内核守护进程。 他们执行下列任务 周期性地将修改的内存页与页来源块设备同步 如果内存页很少使用,则写入交换区 管理延时任务 (Deferred work),如:中断的下半部 实现文件系统的事务日志 内核线程主要有两种类型 线程启动后一直等待,直至内核请求线程执行某一特定操作。 线程启动后按周期性间隔运行,检测特定资源的使用,在用量超出或低于预置的限制时采取行动。 它们在CPU的管态执行,而不是用户态。 它们只可以访问虚拟地址空间的内核部分 (高于TASK_SIZE的所有地址) ,但不能访问用户空间 内核线程的进程描述符 task_struct task_struct 进程描述符中包含两个跟 进程地址空间 相关的字段 mm, active_mm struct task_struct { // ... struct mm_struct *mm; struct mm_struct *avtive_mm; //... }; 大多数计算机上系统的全部虚拟地址空间分为两个部分: 供用户态程序访问的虚拟地址空间和供内核访问的内核空间。每当内核执行上下文切换时, 虚拟地址空间的用户层部分都会切换, 以便当前运行的进程匹配, 而内核空间不会放生切换。 mm 对于普通用户进程来说,mm 指向虚拟地址空间的用户空间部分,而对于内核线程,mm 为NULL。这为优化提供了一些余地, 可遵循所谓的惰性 TLB 处理(lazy TLB handing)。 active_mm active_mm 主要用于优化,由于内核线程不与任何特定的用户层进程相关,内核并不需要倒换虚拟地址空间的用户层部分,保留旧设置即可。由于内核线程之前可能是任何用户层进程在执行,故用户空间部分的内容本质上是随机的,内核线程决不能修改其内容,故将mm设置为NULL,同时如果切换出去的是用户进程,内核将原来进程的 mm 存放在新内核线程的 active_mm 中,因为某些时候内核必须知道用户空间当前包含了什么。 惰性 TLB 进程 为什么没有 mm 指针的进程称为惰性 TLB 进程? ...

2021-05-05 · 3 min · 596 words · -

neofetch, linux logo ascii

“neofetch, linux logo ascii” neofetch, linux logo ascii neofetch 是一个跨平台的易于使用的 系统信息显示命令行脚本,它收集你的系统信息,并在终端中和图像一起显示出来,这个图像可能是你的发行版的 logo 也可能是你选择的一幅 ascii 艺术字。 Neofetch 和 ScreenFetch 或者 Linux_Logo 很像,但是它可以高度定制,并且还有一些额外的我们要在下面讨论的特点。 它的主要特点有: 运行速度快,可以显示全色图像 —— 用 ASCII 字符显示的发行版 logo ,旁边显示系统信息,可以高度定制,可以随时随地显示系统信息,并且在脚本结束的时候还可以通过一个特殊的参数来启用桌面截图。 系统要求: Bash 3.0+ 带 ncurses 支持。 w3m-img (有时候会打包成 w3m) 或者 iTerm2 或者 Terminology,用于显示图像。 imagemagick,用于创建缩略图。 支持 [\033[14t 的 Linux 终端模拟器 或者 xdotool 或者 xwininfo + xprop 或者 xwininfo + xdpyinfo 。 Linux 系统中还需要 feh、nitrogen 或者 gsettings 来提供对墙纸的支持。 注意: 你可以从 Neofetch 的 Github 页面了解更多关于可选依赖的信息,以检查你的 Linux 终端模拟器 是不是真的支持 \033[14t 或者是否需要一些额外的依赖来使这个脚本在你的发行版上工作得更好。 ...

2021-04-30 · 1 min · 166 words · -

signal, 信号

signal, 信号 信号(signal)机制 信号(Signal)是Linux, 类Unix和其它POSIX兼容的操作系统中用来进程间通讯的一种方式。一个信号就是一个异步的通知,发送给某个进程,或者同进程的某个线程,告诉它们某个事件发生了。 当信号发送到某个进程中时,操作系统会中断该进程的正常流程,并进入相应的信号处理函数执行操作,完成后再回到中断的地方继续执行。 如果目标进程先前注册了某个信号的处理程序(signal handler),则此处理程序会被调用,否则缺省的处理程序被调用。 发送信号 kill 系统调用 (system call) 可以用来发送一个特定的信号给进程。 kill 命令允许用户发送一个特定的信号给进程。 raise 库函数可以发送特定的信号给当前进程。 在Linux下运行 man kill 可以查看此命令的介绍和用法。 The command kill sends the specified signal to the specified process or process group. If no signal is specified, the TERM signal is sent. The TERM signal will kill processes which do not catch this signal. For other processes, it may be necessary to use the KILL (9) signal, since this signal cannot be caught. ...

2021-04-30 · 4 min · 807 words · -