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"); }