go移植linux内核书名叫啥,Go语言移植Linux内核数据结构hlist
hlist(哈希链表)可以通过相应的Hash算法,迅速找到相关的链表Head及节点.
在有些应用场景,比Go标准库提供的list(一种双向链表)更合适。
依照list.h中的源码,我实现了一个Go语言版本的hlist例子。
首先说下hlist的构成:
在hlist(哈希链表)中,
头结点使用struct hlist_head来表示,hlist_head仅一个first指针.
普通节点使用struct hlist_node来表示。
源码中有几个特别的地方:
1. 在struct hlist_node中有一个**pprev中的二级指针,
pprev指向的是当前hlist_node变量中的前一个变量的next的地址,
如果是第一个元素的话,这个值指向的是first的地址,
如果是最后一个节点的话,指向的是NULL。
2.container_of
源码里面有个宏定义:
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
利用一些技巧,可通过结构体内部成员member(即链表node)得到所在结构体的首地址
所以C/C++应用中调用时,常用如下定义方式:
struct MYST {
int data;
struct list_head head;
struct hlist_node node;
} *myst;
在Go中,我将其变更为:
type HLElement struct {
Next *HLElement
PPrev **HLElement
Value interface{}
}
利用interface{}的特性,可将自定义struct之类对应设置给Value.在使用时,通过interface{}
转换回原本对象即可
3.在hlist_del()中使用LIST_POISON而不是(== NULL)的形式
n->next = LIST_POISON1;
n->pprev = LIST_POISON2;
原因可能是,通过这个标记删除node,如果在其它地方用到这种node,
可以用来区分是否引用了已被删除的node。
在我这是个可有可无的特性,只需在应用时,注意一下即可。
所以在Go版中,我直接去掉了LIST_POISON,直接将其设为nil。
4.在遍历链表时,提供了safe版本,防止因为节点被删除而引起的中断
在Go版中我也提供了相关实现。
具体的实现及测试代码:
package main
//hlist (仿Linux内核数据结构hlist, 可参考内核源码list.h)
//author: Xiong Chuan Liang
//date: 2015-2-12
import (
"fmt"
)
func main() {
/*
Hash桶
HLHead[0]
HLHead[1]-> HLElement[0] ->HLElement[1]
HLHead[2]-> HLElement[0]
HLHead[3]-> HLElement[0] ->HLElement[1]-> HLElement[2] ->HLElement[3]
HLHead[4]-> HLElement[0]
*/
fmt.Println(" \n ")
fmt.Println(" hlist用法演示 : ")
lst := [20]HLHead{}
for i := 0; i < 20; i++ {
hash := getHash(i)
elem1 := &HLElement{Value: i}
AddHead(elem1, &lst[hash])
fmt.Println("i:", i, " Hash:", hash)
}
fmt.Println(" \n 遍历其中一个Head(lst[1])所对应的链表: ")
f := func(e *HLElement) bool {
fmt.Println("HLElement.Value =", e.Value)
return true
}
For_each_safe(&lst[1], f)
fmt.Println(" \n ")
fmt.Println(" 演示InsertAfter/InsertBefore : ")
hHead := &HLHead{}
elem1 := &HLElement{Value: 1}
elem2 := &HLElement{Value: 2}
elem3 := &HLElement{Value: 300}
elem4 := &HLElement{Value: 400}
AddHead(elem1, hHead)
InsertAfter(elem1, elem2)
InsertAfter(elem2, elem3)
InsertBefore(elem4, elem3)
fmt.Println(" \n 遍历链表看效果: ")
For_each(hHead, f)
fmt.Println(" \n ")
fmt.Println(" \n 测试MoveList: lst[1] => MoveList(0->1) ")
MoveList(&lst[0], &lst[1])
For_each_safe(&lst[1], f)
fmt.Println(" \n ")
fmt.Println(" 从指定element开始遍历链表: ")
For_each_safe_from(elem2, f)
fmt.Println(" \n ")
fmt.Println(" 将自定义结构体放入链表: ")
elemA := &HLElement{Value: &Demo{"a"}}
elemB := &HLElement{Value: &Demo{"b"}}
elemC := &HLElement{Value: &Demo{"c"}}
AddHead(elemA, hHead)
AddHead(elemB, hHead)
AddHead(elemC, hHead)
fs := func(e *HLElement) bool {
m, ok := e.Value.(*Demo)
if ok {
fmt.Println("struct =", m.Data)
} else {
fmt.Println("int =", e.Value)
}
return true
}
For_each_safe(hHead, fs)
fmt.Println(" \n ")
fmt.Println(" Remove(elemB): ")
Remove(elemB)
For_each_safe(hHead, fs)
fmt.Println(" \n ")
fmt.Println(" Empty()/Unhashed(): ")
if Empty(hHead) {
fmt.Println(" Empty(hHead) = true: hHead对应的链表为空! ")
} else {
fmt.Println(" Empty(hHead) = false: hHead对应的链表不为空! ")
}
hHeadEmpty := &HLHead{}
if Empty(hHeadEmpty) {
fmt.Println(" Empty(hHeadEmpty) = true: hHeadEmpty对应的链表为空! ")
} else {
fmt.Println(" Empty(hHeadEmpty) = false : hHeadEmpty对应的链表不为空! ")
}
if Unhashed(elem1) {
fmt.Println(" Unhashed(elem1) = true: elem1不在链表中! ")
} else {
fmt.Println(" Unhashed(elem1) = false: elem1在链表中! ")
}
}
//演示用的Struct
type Demo struct {
Data string
}
//演示用的Hash算法
func getHash(c int) int {
return (c % 16)
}
///
type HLHead struct {
First *HLElement
}
type HLElement struct {
Next *HLElement
PPrev **HLElement
Value interface{}
}
type ElemFunc func(e *HLElement) bool
func For_each(h *HLHead, f ElemFunc) {
pos := h.First
for pos != nil {
if !f(pos) {
break
}
pos = pos.Next
}
}
func For_each_safe(h *HLHead, f ElemFunc) {
pos := h.First
for pos != nil {
n := pos.Next
if !f(pos) {
break
}
pos = n
}
}
func For_each_safe_from(h *HLElement, f ElemFunc) {
pos := h.Next
for pos != nil {
n := pos.Next
if !f(pos) {
break
}
pos = n
}
}
//将普通结点n插入到头结点h对应的hash桶的第一个结点的位置
func AddHead(n *HLElement, h *HLHead) {
first := h.First
n.Next = first
if first != nil {
first.PPrev = &n.Next
}
h.First = n
n.PPrev = &h.First
}
//n: 新节点, next:链表
func InsertBefore(n *HLElement, next *HLElement) {
pprev := next.PPrev
n.PPrev = pprev
n.Next = next
next.PPrev = &n.Next
if pprev != nil {
//将原来上一个结点的next的值,指向新节点n
*pprev = n
}
}
//n: 链表, next:新节点
func InsertAfter(n *HLElement, next *HLElement) {
next.Next = n.Next
n.Next = next
next.PPrev = &n.Next
if next.Next != nil {
next.Next.PPrev = &next.Next
}
}
//移动list
func MoveList(old, new *HLHead) {
new.First = old.First
if new.First != nil {
//链表所指定向的第一个元素不为空,更改其pprev指向到New
new.First.PPrev = &new.First
}
old.First = nil
}
//判断结点是否已经在链表中,如返回true,表示不在其中
func Unhashed(h *HLElement) bool {
return (h.PPrev == nil)
}
//判断链表是否为空
func Empty(h *HLHead) bool {
return (h.First == nil)
}
//删除节点
func Remove(n *HLElement) {
next := n.Next
pprev := n.PPrev
if pprev != nil {
*pprev = next
}
if next != nil {
next.PPrev = pprev
}
n.Next = nil
n.PPrev = nil
}
///
/*
hlist用法演示 :
i: 0 Hash: 0
i: 1 Hash: 1
i: 2 Hash: 2
i: 3 Hash: 3
i: 4 Hash: 4
i: 5 Hash: 5
i: 6 Hash: 6
i: 7 Hash: 7
i: 8 Hash: 8
i: 9 Hash: 9
i: 10 Hash: 10
i: 11 Hash: 11
i: 12 Hash: 12
i: 13 Hash: 13
i: 14 Hash: 14
i: 15 Hash: 15
i: 16 Hash: 0
i: 17 Hash: 1
i: 18 Hash: 2
i: 19 Hash: 3
遍历其中一个Head(lst[1])所对应的链表:
HLElement.Value = 17
HLElement.Value = 1
演示InsertAfter/InsertBefore :
遍历链表看效果:
HLElement.Value = 1
HLElement.Value = 2
HLElement.Value = 400
HLElement.Value = 300
测试MoveList: lst[1] => MoveList(0->1)
HLElement.Value = 16
HLElement.Value = 0
从指定element开始遍历链表:
HLElement.Value = 400
HLElement.Value = 300
将自定义结构体放入链表:
struct = c
struct = b
struct = a
int = 1
int = 2
int = 400
int = 300
Remove(elemB):
struct = c
struct = a
int = 1
int = 2
int = 400
int = 300
Empty()/Unhashed():
Empty(hHead) = false: hHead对应的链表不为空!
Empty(hHeadEmpty) = true: hHeadEmpty对应的链表为空!
Unhashed(elem1) = false: elem1在链表中!
*/
例子基本实现了常用的东西,实现时主要是要注意下Golang的特性及与C的一些差异。
部份参考资料:
BLOG: http://blog.csdn.net/xcl168
原文:http://blog.csdn.net/xcl168/article/details/43760173
go移植linux内核书名叫啥,Go语言移植Linux内核数据结构hlist相关推荐
- go移植linux内核书名叫啥,嵌入式 Linux根文件系统移植之Linux文件系统简介-Go语言中文社区...
学号:16020311003 姓名:杨虎成 [嵌牛导读]Linux支持多种文件系统,文件系统接口实现为分层的体系结构,将用户接口层.文件系统实现和操作存储设备的驱动程序分隔开 [嵌牛鼻子]Lin ...
- linux添加音乐的代码,C语言实现linux系统下的MP3播放器源代码
[实例简介] 能识别本地的MP3歌曲文件,能根据路径添加入播放器中. 能识别本地的播放列表信息. 具有播放列表功能,能根据用户的需求随意创建.删除播放列表. 用户能往指定的播放列表中添加.删除 ...
- linux c实现函数回调,c语言实现linux抓包
验证安装libpca 引用pcap.h,确认是否能正常用libpcap开发 #include #include int main(int argc, char *argv[]) { char *dev ...
- linux终端输出c语言程序,Linux终端程序用c语言实现改变输出的字的颜色
颜色代码: 格式: echo "\033[字背景颜色;字体颜色m字符串\033[0m" 例如: echo "\033[41;36m something here \033 ...
- vss2010c语言怎么运行,在Linux下使用gcc运行C语言程序
Linux下使用最广泛的C/C++编译器是GCC,大多数的Linux发行版本都默认安装,不管是开发人员还是初学者,一般都将GCC作为Linux下首选的编译工具.本教程毫不犹豫地使用GCC来编译C程序. ...
- linux内核深度解析_十年磨一剑,第一本龙芯平台的Linux内核书来了
<用"芯"探核:基于龙芯的Linux内核探索解析>是一本基于龙芯平台,结合源代码来探索和解析Linux-5.x内核的书. 市面上解析Linux 内核的经典书籍已有不少, ...
- 为信息产业自主化而奋斗,第一本龙芯平台的Linux内核书来了!
十年磨一剑,第一本龙芯平台的Linux内核书来了! 这就是<用"芯"探核:基于龙芯的Linux内核探索解析>--一本基于龙芯平台,结合源代码来探索和解析Linux-5. ...
- Linux内核移植漫谈——你不是第一个想移植Linux内核的人
Jack:在读大学的时候我想过移植Linux操作系统. 我:现在呢? Jack:我还是想移植Linux操作系统.你教我移植吧. 我:你知道什么是"Linux内核移植"吗? Jack ...
- 【正点原子Linux连载】第三十七章 Linux内核移植 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...
最新文章
- canvas——橡皮筋式线条绘图应用
- android c 电话联系人,Android 联系人按中文拼音排序
- 北斗导航 | 基于卡尔曼滤波的IMU+GNSS的组合导航(附Matlab源代码)
- 运维常说的 5个9、4个9、3个9 的可靠性,到底是什么???
- 云计算相关资料/博客/网上收集的关于OpenStack的一些资源
- 杭州企业“被参与”互联网攻击致半个美国网络瘫痪
- 程序员过关斩将--应对高并发系统有没有通用的解决方案呢?
- 飞行模式的开启和关闭
- 计算机网络之物理层:6、传输介质
- 笨办法学 Linux 中文版 翻译完成
- Java杂记3—流程控制之条件 1
- 部署git服务器(Windows Server 2008)
- 图解安装simsun字体后OO乱码的摸黑解决办法【转贴自http://linux.hiweed.com】
- 高尚品质_心理学家:品德高尚的人一定具有这6点特征
- 小学计算机教师应聘简历,应聘小学教师的个人简历模板
- CAD之设置坐标原点
- 智能垃圾桶语音芯片应用设计方案介绍,WT588F02B-8S
- [hitroad杂货铺]KaTeX使用
- 【Angular】angular环境搭建
- oracle数据库恢复aul_AUL/MyDUL 非常规灾难恢复ORACLE数据
热门文章
- 2017年8月Science肠道菌群研究
- pandas使用isna函数和any函数检查dataframe是否包含缺失值、整体是否有缺失值,不区分行列(check if dataframe contains any missing values
- R语言ggplot2可视化强制所有的X数值都显示在X轴标签上:x-axis labels with all x-axis values
- R语言广义加性模型(generalized additive models,GAMs):使用广义线性加性模型GAMs构建logistic回归
- Python以表格、可视化图像的形式输出模型特征重要度(feature importances)并进行重要度归一化及排序
- R语言读取excel文件实战(read.xlsx函数、read_excel函数、read.xlsx函数、Write函数)
- 使用python包faker生成仿真数据
- pdb+ipdb 调试 Python代码
- sklearn MLP(多层感知机、Multi-layer Perceptron)模型使用RandomSearchCV获取最优参数及可视化
- 阿里云 mysql主从_阿里云MySQL主从_Mater Slave_主备同步_MySQL主从_MySQL延迟-云栖社区-阿里云...