Una de las estructuras pasadas por parámetro es sem de tipo rw_semaphore. Esta estructura se define en Linux dentro del fighero ./include/asm-i386, así
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
};
Otra de las estructuras pasadas por parámetro es rwsem_waiter, donde se incluyen los campos necesarios para identificar al semáforo ya sea de lectura o escritura, el proceso que lo invoca y unos flags para opciones de control. Véase su implementación:
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
};
Las modificaciones que realiza openMosix sobre el fichero rwsem.c se centran en un
pequeño cambio a la funcion rw_semaphore
*rwsem_down_failed_common().
Esta función espera para que se conceda el bloqueo de un
semaforo6.5.
Se añade una línia que invoca a la función
adjust_task_mosix_context().
Esta función está definida en ./hpc/service.c e implementada como sigue:
void
adjust_task_mosix_context(struct task_struct **tp)
{
struct task_struct *t = *tp;
if(t->mosix.dflags & DINSCHED)
*tp = MOSIX_CONTEXT(t);
}
Esta implementación consigue modificar el task_struct que identifica al proceso en curso para que sea compatible con el entorno de operación de openMosix. MOSIX_CONTEXT se define en ./include/linux/wait.h de forma que aplica al task_struct pasado como parámetro la máscara KERNEL_ADDRESS_BIT de la manera que sigue:
#define KERNEL_ADDRESS_BIT 0x80000000
#define MOSIX_CONTEXT(p) ((struct task_struct *)\
(((unsigned long) (p)) & ~KERNEL_ADDRESS_BIT))
Véase la función:
static inline struct rw_semaphore *rwsem_down_failed_common()
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;
}
Las modificaciones se realizan en la función encargada de controlar el bloqueo exclusivo de escritura sobre el recurso que solicite el proceso. La implementación es muy parecida a la comentada anteriormente. Véase:
void __down_write()
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");
}