4.7. Protegiendo Una Colecci�n de Objetos: Cuentas de Referencia

Bloqueando una colecci�n de objetos es bastante f�cil: coges un spinlock simple, y te aseguras de obtenerlo antes de buscar, a�adir o borrar un objeto.

El prop�sito de este bloqueo no es proteger los objetos individuales: quiz�s tengas un bloqueo separado dentro de cada uno de ellos. Es para proteger la estructura de datos conteniendo el objeto de las condiciones de carrera. Frecuentemente el mismo bloqueo es usado tambi�n para proteger los contenidos de todos los objetos, por simplicidad, pero ellos son inherentemente ortogonales (y muchas otras grandes palabras dise�adas para confundir).

Cambiando esto a un bloqueo de lectura-escritura frecuentemente ayudar� notablemente si las lecturas son m�s frecuentes que las escrituras. Si no, hay otra aproximaci�n que puedes usar para reducir el tiempo que es mantenido el bloqueo: las cuentas de referencia.

En esta aproximaci�n, un objeto tiene un due�o, quien establece la cuenta de referencia a uno. Cuando obtienes un puntero al objeto, incrementas la cuenta de referencia (una operaci�n 'obtener'). Cuando abandonas un puntero, decrementas la cuenta de referencia (una operaci�n 'poner'). Cuando el due�o quiere destruirlo, lo marca como muerto y hace una operaci�n poner.

Cualquiera que ponga la cuenta de referencia a cero (usualmente implementado con atomic_dec_and_test()) limpia y libera el objeto.

Esto significa que se garantiza que el objeto no se desvanecer� debajo de ti, incluso aunque no tengas m�s un bloqueo para la colecci�n.

Aqu� hay alg�n c�digo esqueleto:


        void create_foo(struct foo *x)
        {
                atomic_set(&x->use, 1);
                spin_lock_bh(&list_lock);
                ... inserta en la lista ...
                spin_unlock_bh(&list_lock);
        }

        struct foo *get_foo(int desc)
        {
                struct foo *ret;

                spin_lock_bh(&list_lock);
                ... encuentra en la lista ...
                if (ret) atomic_inc(&ret->use);
                spin_unlock_bh(&list_lock);

                return ret;
        }

        void put_foo(struct foo *x)
        {
                if (atomic_dec_and_test(&x->use))
                        kfree(foo);
        }

        void destroy_foo(struct foo *x)
        {
                spin_lock_bh(&list_lock);
                ... borra de la lista ...
                spin_unlock_bh(&list_lock);

                put_foo(x);
        }
    

4.7.1. Macros Para Ayudarte

Hay un conjunto de macros de depuraci�n recogidas dentro de include/linux/netfilter_ipv4/lockhelp.h y listhelp.h: estas son muy �tiles para asegurarnos de que los bloqueos son mantenidos en los sitios correctos para proteger la infraestructura.