内核hlist使用之pidhash散列表使用分析
来源:互联网 发布:虚无世界用哪个java 编辑:程序博客网 时间:2024/06/01 08:23
对内核提供的散列表功能使用不是很熟悉,特分析进程pid管理对hlist的使用,进一步加深熟悉和理解。
先贴一下内核数据结构的定义
<span style="font-size:12px;"><list.h>struct hlist_head { struct hlist_node *first;};struct hlist_node { struct hlist_node *next, **pprev;};#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)</span>
静态定义可以使用HLIST_HEAD,动态初始化使用INIT_HLIST_HEAD
内核管理pid使用的散列表通过全局变量pid_hash定义,通过pidhash_init()分配
<kernel/pid.c>static struct hlist_head *pid_hash;static int pidhash_shift;/* * The pid hash table is scaled according to the amount of memory in the * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or * more. */void __init pidhash_init(void){ int i, pidhash_size; unsigned long megabytes = nr_kernel_pages >> (20 - PAGE_SHIFT); pidhash_shift = max(4, fls(megabytes * 4)); pidhash_shift = min(12, pidhash_shift); pidhash_size = 1 << pidhash_shift; printk("PID hash table entries: %d (order: %d, %Zd bytes)\n", pidhash_size, pidhash_shift, pidhash_size * sizeof(struct hlist_head)); pid_hash = alloc_bootmem(pidhash_size * sizeof(*(pid_hash))); if (!pid_hash) panic("Could not alloc pidhash!\n"); for (i = 0; i < pidhash_size; i++) INIT_HLIST_HEAD(&pid_hash[i]);}
根据内核能够管理的内存页数nr_kernel_pages来计算分配2^pidhash_shift个hlist_head结构体,最少2^4最多2^12个
接下来看散列函数这个是关键
#define pid_hashfn(nr, ns) \ hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift)/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */#define GOLDEN_RATIO_PRIME 0x9e370001ULstatic inline unsigned long hash_long(unsigned long val, unsigned int bits){ unsigned long hash = val; /* On some cpus multiply is faster, on others gcc will do shifts */ hash *= GOLDEN_RATIO_PRIME; /* High bits are more random, so use them. */ return hash >> (BITS_PER_LONG - bits);}本质就是将nr与ns的和乘上一个合适的值,然后取高pidhash_shift位,这个值做为表头数组的索引
插入和查找涉及的结构体定义如下
<pid.h> enum pid_type { PIDTYPE_PID, PIDTYPE_PGID, PIDTYPE_SID, PIDTYPE_MAX }; struct upid { /* Try to keep pid_chain in the same cacheline as nr for find_vpid */ int nr; struct pid_namespace *ns; struct hlist_node pid_chain; }; struct pid { atomic_t count; unsigned int level; /* lists of tasks that use this pid */ struct hlist_head tasks[PIDTYPE_MAX]; struct rcu_head rcu; struct upid numbers[1]; };
1. 插入操作
alloc_pid函数用于创建struct pid结构体实例
<pid.c>struct pid *alloc_pid(struct pid_namespace *ns){ struct pid *pid; enum pid_type type; int i, nr; struct pid_namespace *tmp; struct upid *upid; pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); if (!pid) goto out; tmp = ns; for (i = ns->level; i >= 0; i--) { nr = alloc_pidmap(tmp); if (nr < 0) goto out_free; pid->numbers[i].nr = nr; pid->numbers[i].ns = tmp; tmp = tmp->parent; } get_pid_ns(ns); pid->level = ns->level; atomic_set(&pid->count, 1); for (type = 0; type < PIDTYPE_MAX; ++type) INIT_HLIST_HEAD(&pid->tasks[type]); spin_lock_irq(&pidmap_lock); for (i = ns->level; i >= 0; i--) { upid = &pid->numbers[i]; hlist_add_head_rcu(&upid->pid_chain, &pid_hash[pid_hashfn(upid->nr, upid->ns)]); } spin_unlock_irq(&pidmap_lock);out: return pid;out_free: for (i++; i <= ns->level; i++) free_pidmap(pid->numbers[i].ns, pid->numbers[i].nr); kmem_cache_free(ns->pid_cachep, pid); pid = NULL; goto out;}
2.查找操作
<pid.c>struct pid * fastcall find_pid_ns(int nr, struct pid_namespace *ns){ struct hlist_node *elem; struct upid *pnr; hlist_for_each_entry_rcu(pnr, elem, &pid_hash[pid_hashfn(nr, ns)], pid_chain) if (pnr->nr == nr && pnr->ns == ns) return container_of(pnr, struct pid, numbers[ns->level]); return NULL;}
总结:hlist的使用需要(1)分配hlist_head数组 (2)定义散列函数,剩下的操作跟双向链表相同
0 0
- 内核hlist使用之pidhash散列表使用分析
- linux内核分析--内核中使用的数据结构之哈希表hlist(三)
- linux内核hlist分析
- linux内核hlist分析
- linux内核hlist分析
- Linux内核hlist数据结构分析
- 在用户空间编程使用linux内核链表list,hlist宏定义和操作
- 在用户空间编程使用linux内核链表list,hlist宏定义和操作
- 在用户空间编程使用linux内核链表list,hlist宏定义和操作
- linux内核分析之rbtree的使用
- linux内核分析之rbtree的使用
- 内核hlist链表
- 内核数据结构hlist哈希链表
- linux内核哈希表hlist
- linux内核 hlist 讲解
- Linux 内核 hlist 详解
- C内核-hlist
- Linux 内核 hlist 详解
- 线性规划与网络流24题の5 圆桌问题(二分图多重匹配)
- dancing links讲解
- 看来角度来看都说了看了看都是垃圾刚开始看了几个六级考试
- 互联网大会第三日看点:丁磊对话张朝阳
- HDU1250 Hat's Fibonacci 【大数】
- 内核hlist使用之pidhash散列表使用分析
- POJ--1159:Palindrome (DP求最长公共子序列)
- 组成原理复习
- 谷歌今年或发布两款大屏智能手机
- Lucene/Solr学习笔记(一)
- GitHub使用教程
- 黑马程序员—(iOS开发)OC开发技巧及核心语法---(九)
- QTableWidget翻译
- 伦敦明年将试用无线充电公交