Linux kernel de hash Comentarios

1, la resolución de conflictos la tabla del núcleo de hash


hash de la mayoría lo importante es seleccionar la función hash adecuada, por lo que la posición distribuye uniformemente en las palabras clave cubo para la inserción tiempo de búsqueda y optimizar la eliminación utilizados. Sin embargo, cualquier función hash aparecerá conflicto. La solución de hash usos colisión del núcleo: la ley de la cremallera, cremallera método de enfoque de resolución de conflictos es: todas las palabras clave a los nodos de enlace sinónimos en la misma lista. Si el hash longitud de la tabla seleccionada m, la tabla hash puede ser definida como la matriz de punteros T [0..m-1] a m un puntero de cabeza (struct nombre hlist_head) del mismo. Cualquier dirección hash del nodo i, se insertan en T [i] es el puntero de lista de cabeza. T es el valor inicial de cada componente debería ser un puntero nulo. En el método de fijación, el factor de llenado de [alfa] (el número de elementos de carga / longitud de la matriz) puede ser mayor que 1, pero en general tomar α≤1. Por supuesto, el hash con un método de cremallera para resolver el conflicto es errónea, el puntero necesidad de espacio adicional.

2, definición de estructura


Qué código se incluir / Linux / list.h, la estructura de datos definida en el include / linux / types.h de:

struct hlist_head {
	struct hlist_node *first;
};
 
struct hlist_node {
	struct hlist_node *next, **pprev;
};
  • hlist_head representa la primera tabla de nodos hash. Cada entrada de la tabla de hash (list_entry) es una lista enlazada que corresponde a la estructura (hlist) .hlist_head de un solo dominio, es decir, primero. En primer puntero al primer nodo de la lista enlazada hlist.
  • hlist_node estructura tiene dos campos, a continuación, y pprev. (1) Punto de hlist_node siguiente siguiente nodo, si el nodo para cambiar la lista es el último nodo, próximos puntos a NULL. (2) pprev es una de dos punteros, siguiente puntero que apunta a un nodo frontal.
     

Pregunta 1: ¿Por qué necesitamos una cabeza tabla hash dedicado?

Debido a que la cadena de hash no necesita las habilidades de un ciclo de dos vías, que se aplica generalmente a hash unidireccional de la escena. Por lo tanto, con el fin de reducir la sobrecarga, no usando hlist_node struct {} para representar la cabeza de la tabla hash, pero hlist_head struct rediseñado {} esta estructura de datos. En este caso, una tabla hash sólo 4byte la cabecera, en comparación con el hlist_node struct {}, el espacio de almacenamiento se ha reducido a la mitad. Como resultado, la escena requiere una gran cantidad de uso de la cadena de hash, el ahorro de espacio de almacenamiento que es muy evidente, sobre todo en el campo de los dispositivos integrados.

Pregunta 2: Usar la importancia pprev dos punteros?

En hlist, la cabecera no es anterior, sólo un primer, con el fin de modificar el encabezado unificado primer puntero hlist en el diseño de pprev. nodo de nodo de la pprev realidad apunta a la dirección de su puntero del nodo anterior en el primer elemento. Para hlist_head, que sólo hay un elemento de puntero, el puntero es primero, pues hlist_node, el primer elemento es un puntero al siguiente.

Por lo tanto, cuando se ve en el código * es similar (hlist_node-> pprev) dicho código una, una tabla hash que muestra el funcionamiento en este momento es la dirección de memoria del nodo anterior en el puntero del nodo actual al primer elemento se dirige.

3, la inicialización

(A) de inicialización de cabecera

#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)

1.HLIST_HEAD_INIT macro solamente de inicialización;

如: struct hlist_head my_hlist = HLIST_HEAD_INIT   

HLIST_HEAD_INIT llamada para el nodo de cabecera de la tabla de hash my_hlist sólo se puede inicializar, el nodo de cabecera en blanco punto de puño. 

2.HLIST_HEAD (nombre) de macros de función declarar e inicializar.

如: HLIST_HEAD (my_hlist);

HLIST_HEAD función de macro llamada a la cabeza my_hlist tabla de nodos de hash es declarado e inicializado. El nodo de cabecera de puño a nulo.

3.INIT_HLIST_HEAD inicializado en tiempo de ejecución

如: INIT_HLIST_HEAD (y my_hlist);

Llamada INIT_HLIST_HEAD tanto my_hlist inicializa su primera apunta dominio a vaciar.
 

(B) nodo initialize

1.static iniline INIT_HLIST_NODE vacío (struct hlist_node * h)

static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
	h->next = NULL;
	h->pprev = NULL;
}

Esta función en línea realiza la operación de inicialización nodo struct hlist_node realiza, dominio y su siguiente punto pprev vaciar, para lograr su inicialización.

4 operaciones básicas (insertar, eliminar, condenado vacío)

1, inserto

// 将结点n插在头结点h之后。
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h);
// 将结点n插在next结点的前面(next在哈希链表中)
static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next);
// 将结点next插在n之后(n在哈希链表中)
static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next);
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
	struct hlist_node *first = h->first;
	n->next = first; // 指向下一个节点或NULL
	if (first) // first指向非空,则后继节点的pprev指向前驱节点的next地址
		first->pprev = &n->next;
	h->first = n;
	n->pprev = &h->first;
}
/* next must be != NULL */
static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next)
{
	n->pprev = next->pprev;
	n->next = next;
	next->pprev = &n->next;
	*(n->pprev) = n;
}
static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next)
{
	next->next = n->next;
	n->next = next;
	next->pprev = &n->next;
 
	if(next->next)
		next->next->pprev  = &next->next;
}

2, eliminar

static inline void hlist_del(struct hlist_node *n);
/*
 * These are non-NULL pointers that will result in page faults
 * under normal circumstances, used to verify that nobody uses
 * non-initialized list entries.
 */
#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)
static inline void __hlist_del(struct hlist_node *n)
{
	struct hlist_node *next = n->next;
	struct hlist_node **pprev = n->pprev;
	*pprev = next;
	if (next)
		next->pprev = pprev;
}
static inline void hlist_del(struct hlist_node *n)
{
	__hlist_del(n);
	n->next = LIST_POISON1;
	n->pprev = LIST_POISON2;
}

LIST_POISON área es una sección de una dirección no válida, cuando los desarrolladores utilizan esta dirección, por error, se generará una página de error.

3, movimiento de la cadena de hash

// 将以个哈希聊表的头结点用new结点代替,将以前的头结点删除。
static inline void hlist_move_list(struct hlist_head *old,struct hlist_head *new);
/*
 * Move a list from one list head to another. Fixup the pprev
 * reference of the first entry if it exists.
 */
static inline void hlist_move_list(struct hlist_head *old,
				   struct hlist_head *new)
{
	new->first = old->first;
	if (new->first)
		new->first->pprev = &new->first;
	old->first = NULL;
}

4, la cadena de hash otras operaciones

// 判断结点是否已经存在hash表中。
static inline int hlist_unhashed(const struct hlist_node *h);
// 函数判断哈希链表是否为空
static inline int hlist_empty(const struct hlist_head *h);
static inline int hlist_unhashed(const struct hlist_node *h)
{
	return !h->pprev;
}
 
static inline int hlist_empty(const struct hlist_head *h)
{
	return !h->first; // 通过判断头结点中的first域来判断其是否为空。如果first为空则表示该哈希链表为空。
}

Mediante la determinación de si el nodo es pprev vacío determina si el nodo en la cadena de hash. h-> dominio pprev equivalente al siguiente nodo antes del nodo h. Si el siguiente nodo antes de que el campo está vacío, lo que indica que el nodo no está en la cadena de hash.

5, la cadena de hash ergódico

#define hlist_entry(ptr, type, member) container_of(ptr,type,member)

Y la función container_of como obtener un puntero a la estructura por un puntero miembro.

#define hlist_for_each(pos, head)
#define hlist_for_each_safe(pos, n, head)

Hash traversal cadena kernel proporciona dos interfaces, dos interfaces dentro de la lista de recorrido es justo abajo a lo largo de la cadena, sin ningún procesamiento de datos externa, y el uso de la unión hlist_entry general.

#define hlist_for_each(pos, head) \
	for (pos = (head)->first; pos ; pos = pos->next)
 
#define hlist_for_each_safe(pos, n, head) \
	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
	     pos = n)

POS: POS es un puntero auxiliar (es decir, tipo de lista hlist_node struct), una lista enlazada traversal
n: n es un puntero temporal nodo de hash (struct hlist_node), una lista vinculada para el siguiente nodo en el POS de almacenamiento temporal.
Cabeza: La lista de punteros de cabeza (es decir, la estructura de miembro struct hlist_head). 

pos hlist_for_each moviendo el puntero para conseguir el objetivo de la poligonal. Sin embargo, si el nodo móvil comprende atravesar operación POS puntero apunta remove, puntero pos será interrumpido, porque hlist_del (POS) pos será el siguiente, anterior se establece en el LIST_POSITION2 valor especial y LIST_POSITION1. Por supuesto, la persona que llama puede hacer su próxima operación puntero caché coherente puede atravesar, pero con el fin de coherencia del programa, Linxu núcleo de la cadena de hash requiere la persona que llama para proporcionar además un puntero a los mismos pos de tipo n, se almacena temporalmente en una posición de bucle la siguiente dirección de nodo para evitar la escisión de la cadena debido pos para ser liberados nodo causados.
Este ciclo está determinada condición es pos && (n = {posi-> siguiente; 1;});
se determina si la primera posición de los estados está vacía, si no está vacío, se determina para continuar. Si la determinación es pos verdaderos ({n = posi-> siguiente; 1;}) - " declaración compuesto es un artículo declaración de la expresión, un valor de la última instrucción, es decir, el artículo declaración es siempre cierto, y el puesto un valor asignado al nodo n. Es decir, la condición de determinación del ciclo es cierto sólo pos que determinan si y, si es cierto, se continúa por el juicio.
 

6, la estructura de la cadena de hash de desplazamiento anfitrión

Linux proporciona para traversal de tres maneras, uno es desde el primer nodo de desplazamiento de cadena de hash de hash , la segunda es de la siguiente nodo nodo pos que atraviesa la cadena de hash , en tercer especies están empezando a atravesar desde el nodo actual en la cadena de hash .

(1) desde un primer nodo de hash aperturas de recorrido de la cadena de hash

#define hlist_for_each_entry(tpos, pos, head, member);
#define hlist_for_each_entry_safe(tpos, pos, n, head, member); 

Además, recorrido de lista y hlist han logrado versión segura, porque cuando se atraviesa, sin ningún tipo de cosas especiales para evitar una operación de eliminación en la lista. operación de eliminación no puede ser afectado por una función de recorrido de la versión de seguridad utilizando un método de almacenamiento temporal permite recuperar la lista.

TPOS es relevante para la estructura de acogida tipo de puntero hlist_node, tipo pos hlist_node es un puntero, el papel de las OPC y actuar como punto de venta de cursor. n es un puntero a otro tipo de hlist_node, el puntero al siguiente elemento en el que el elemento de POS, que se mantiene por hlist_for_each_entry_safe sí mismo, el usuario no modifique.
 

/**
 * hlist_for_each_entry	- iterate over list of given type
 * @tpos:	the type * to use as a loop cursor.
 * @pos:	the &struct hlist_node to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry(tpos, pos, head, member)			 \
	for (pos = (head)->first;					 \
	     pos &&							 \
		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
	     pos = pos->next)
/**
 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @tpos:	the type * to use as a loop cursor.
 * @pos:	the &struct hlist_node to use as a loop cursor.
 * @n:		another &struct hlist_node to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) 		 \
	for (pos = (head)->first;					 \
	     pos && ({ n = pos->next; 1; }) && 				 \
		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
	     pos = n)

(2) de la cadena de hash al siguiente nodo pos nodo de desplazamiento

/**
 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
 * @tpos:	the type * to use as a loop cursor.
 * @pos:	the &struct hlist_node to use as a loop cursor.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_continue(tpos, pos, member)		 \
	for (pos = (pos)->next;						 \
	     pos &&							 \
		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
	     pos = pos->next)

(3) de las pos nodo actual nodo que atraviesa la cadena de hash

/**
 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
 * @tpos:	the type * to use as a loop cursor.
 * @pos:	the &struct hlist_node to use as a loop cursor.
 * @member:	the name of the hlist_node within the struct.
 */
#define hlist_for_each_entry_from(tpos, pos, member)			 \
	for (; pos &&							 \
		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
	     pos = pos->next)

 

 

 

Publicado 14 artículos originales · ganado elogios 0 · Vistas 3867

Supongo que te gusta

Origin blog.csdn.net/weixin_39094034/article/details/104824121
Recomendado
Clasificación