\newpage
%===========================================================================
%       x.21 > LIB
%===========================================================================
\pagestyle{empty}
\begin{latexonly}
\hfill\line(1,0){400}
\end{latexonly}
\topmargin 1in
\section{\tt {./lib/*}}
\begin{latexonly}
\line(1,0){400}
\begin{verbatim}
This directory contains the kernel's library code. 

patching file lib/rwsem.c
patching file lib/rwsem-spinlock.c
\end{verbatim}
\newpage
\end{latexonly}
\topmargin 0in
\pagestyle{fancy}
%===========================================================================
\subsection{{\em rwsem.c}}
Este fichero contiene las funciones para la gesti\'on de los bloqueos de los
sem\'aforos de lectura y/o escritura -{\em contention handling functions for
  R/W semaphores}-.

Una de las estructuras pasadas por par\'ametro es {\tt sem} de tipo {\tt
  rw\_semaphore}. Esta estructura se define en Linux dentro del fighero {\em ./include/asm-i386}, as\'\i\:
\begin{verbatim}
struct rw_semaphore {
        signed long             count;
#define RWSEM_UNLOCKED_VALUE            0x00000000
#define RWSEM_ACTIVE_BIAS               0x00000001
#define RWSEM_ACTIVE_MASK               0x0000ffff
#define RWSEM_WAITING_BIAS              (-0x00010000)
#define RWSEM_ACTIVE_READ_BIAS          RWSEM_ACTIVE_BIAS
#define RWSEM_ACTIVE_WRITE_BIAS         (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
        spinlock_t              wait_lock;
        struct list_head        wait_list;
#if RWSEM_DEBUG /* to be removed shortly */ 
        int                     debug;
#endif
};
\end{verbatim}

Otra de las estructuras pasadas por par\'ametro es {\tt rwsem\_waiter}, donde se incluyen los campos
necesarios para identificar al sem\'aforo ya sea de lectura o escritura, el proceso que lo invoca y unos {\em flags} para
opciones de control. V\'ease su implementaci\'on:

\begin{verbatim}
struct rwsem_waiter {
        struct list_head        list;
        struct task_struct      *task;
        unsigned int            flags;
#define RWSEM_WAITING_FOR_READ  0x00000001
#define RWSEM_WAITING_FOR_WRITE 0x00000002
};
\end{verbatim}

Las modificaciones que realiza openMosix sobre el fichero {\em rwsem.c} se centran en un
peque\~{n}o cambio a la funcion {\tt rw\_semaphore
  *rwsem\_down\_failed\_common()}.
Esta funci\'on espera para que se conceda el bloqueo de un
semaforo\footnote{La pr\'actica demuestra como normalmente las peticiones de
  bloqueo nunca son servidas con inmediatez, por las propias operaciones que
  realizan lso procesos con los recursos de que se apropian.}.
Se a\~{n}ade una l\'\i nia que invoca a la funci\'on\\ {\tt adjust\_task\_mosix\_context()}.
Esta funci\'on est\'a definida en {\em ./hpc/service.c} e implementada como sigue:
\begin{verbatim}
void
adjust_task_mosix_context(struct task_struct **tp)
{
        struct task_struct *t = *tp;

        if(t->mosix.dflags & DINSCHED)
                *tp = MOSIX_CONTEXT(t);
}
\end{verbatim}

Esta implementaci\'on consigue modificar el {\tt task\_struct} que identifica
al proceso en curso para que sea compatible con el entorno de operaci\'on de
openMosix.
MOSIX\_CONTEXT se define en {\em ./include/linux/wait.h} de forma que aplica
al {\tt task\_struct} pasado como par\'ametro la m\'ascara
KERNEL\_ADDRESS\_BIT de la manera que sigue:
\begin{verbatim}
#define KERNEL_ADDRESS_BIT      0x80000000
#define MOSIX_CONTEXT(p)        ((struct task_struct *)\
                                (((unsigned long) (p)) & ~KERNEL_ADDRESS_BIT))
\end{verbatim}

V\'ease la funci\'on:

\vspace{.2in}
\psshadowbox{{\tt static inline struct rw\_semaphore *rwsem\_down\_failed\_common()}}

\vspace{.1in}
\begin{verbatim}
static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore *sem,
                                                                 struct rwsem_waiter *waiter,
                                                                 signed long adjustment)
{
        struct task_struct *tsk = current;  /* se apunta 'tsk' al proceso en curso */
        signed long count;

        set_task_state(tsk,TASK_UNINTERRUPTIBLE); 
                        /* se marca al proceso como ininterrumpible */
        spin_lock(&sem->wait_lock);   /* se pone la peticion en la lista de espera   */                       
        waiter->task = tsk;
#ifdef CONFIG_MOSIX
        adjust_task_mosix_context(&waiter->task);   /* se aplica la modificaion del contexto */
#endif /* CONFIG_MOSIX */

        list_add_tail(&waiter->list,&sem->wait_list);

        /* note that we're now waiting on the lock, but no longer actively read-locking */
        count = rwsem_atomic_update(adjustment,sem);

        /* if there are no longer active locks, wake the front queued process(es) up
         * - it might even be this process, since the waker takes a more active part
         */
        if (!(count & RWSEM_ACTIVE_MASK))
                sem = __rwsem_do_wake(sem);

        spin_unlock(&sem->wait_lock);
        
        for (;;) { /*bucle a la espera de la concesion de bloqueo */
                if (!waiter->flags)
                        break;
                schedule();
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
        }

        tsk->state = TASK_RUNNING;

        return sem;
}
\end{verbatim}
%===========================================================================
\subsection{{\em rwsem-spinlock.c}}
Este fichero sigue implementando {\em handlers} como los del fichero anterior,
pero para bloqueos implementados con las funciones spinlock.

Las modificaciones se realizan en la funci\'on encargada  de controlar el
bloqueo exclusivo de escritura sobre el recurso que solicite el
proceso. La implementaci\'on es muy parecida a la comentada anteriormente. V\'ease:

\vspace{.2in}
\psshadowbox{{\tt void \_\_down\_write()}}

\vspace{.1in}
\begin{verbatim}
void __down_write(struct rw_semaphore *sem)
{
        struct rwsem_waiter waiter;
        struct task_struct *tsk;

        rwsemtrace(sem,"Entering __down_write");

        spin_lock(&sem->wait_lock);

        if (sem->activity==0 && list_empty(&sem->wait_list)) {
                /* bloqueo concedido */
                sem->activity = -1;
                spin_unlock(&sem->wait_lock);
                goto out;
        }

        tsk = current;
        set_task_state(tsk,TASK_UNINTERRUPTIBLE);

        waiter.task = tsk;
#ifdef CONFIG_MOSIX
        adjust_task_mosix_context(&waiter.task);
#endif /* CONFIG_MOSIX */
        waiter.flags = RWSEM_WAITING_FOR_WRITE;

        list_add_tail(&waiter.list,&sem->wait_list);

        spin_unlock(&sem->wait_lock);

        for (;;) {
                if (!waiter.flags)
                        break;
                schedule();
                set_task_state(tsk, TASK_UNINTERRUPTIBLE);
        }

        tsk->state = TASK_RUNNING;

 out:
        rwsemtrace(sem,"Leaving __down_write");
}
\end{verbatim}