IPC : SEMÁFOROS. Carmelo Quintana Hernández, a3182@dis.ulpgc.es a3182@dis.ulpgc.es Miguel Ramírez...

Post on 24-Jan-2016

222 views 0 download

Transcript of IPC : SEMÁFOROS. Carmelo Quintana Hernández, a3182@dis.ulpgc.es a3182@dis.ulpgc.es Miguel Ramírez...

IPC : SEMÁFOROS.

Carmelo Quintana Hernández, a3182@dis.ulpgc.es

Miguel Ramírez Alemána3183@dis.ulpgc.es

Índice. Conceptos.

Semáforos Tabla de Semáforos.

Estructuras de Datos. Semid_ds Sembuf Semun Seminfo

Llamadas al Sistema. Semget Semop Semctl

Ejemplo Práctico.

Código Fuente.

CONCEPTOSSemáforo.

Tabla de Semáforos.

Semáforos.

Para la gente de la calle los semáforos no son mas que los postes indicadores que tienen luces verde, roja o naranja que regula el tránsito en las vías públicas.

En los S.O. son el mecanismo que se utiliza para prevenir la colisión que se produce cuando dos o más procesos solicitan simultáneamente el uso de un recurso que deben compartir Problema de exclusión mutua.

Tabla de Semáforos.

En algunos casos, un proceso necesita poseer varios recursos para proseguir su acción.

Primera Solución : Disponer de varios semáforos. Problema: Esos semáforos pueden estar siendo utilizados

por otros procesos por lo que se pueden producir interbloqueos.

Solución Final: Las operaciones P y V no se efectúan “atómicamente” con un solo semáforo sino con una tabla de semáforos (TS).

Ejemplo para T.S (1).

Dos procesos deben acceder a memoria intermedia de datos y a un segmento de memoria compartida para desplazar los datos de un lugar a otro.

Ejemplo para T.S (2).

Según la primera solución serán necesarios dos semáforos y ejecute dos operaciones P (una de la memoria intermedia y otra para la memoria) a fin de poder disponer de los dos recursos.

Ejemplo para T.S (3).

Problema: Puede provocarse un bloqueo cruzado en el caso de cada proceso posee el acceso exclusivo a uno de los recursos y ambos quieren acceder al otro recurso a la vez.

Ejemplo para T.S (4).

Solución: Las operaciones P y V se efectúan “atómicamente” con una tabla de semáforos.

ESTRUCTURAS DE DATOS

Semid_dsSembufSemun

Seminfo

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Permisos

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Fecha de

última operacion

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Fecha del

último cambio

por semctl

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Puntero al

primer semáforo del grupo

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Operaciones en

Espera de

realización

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Última Operaciónen espera

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Operaciones anuladas

en caso de terminación

Semid_ds.

struct semid_ds { struct ipc_perm sem_perm; __kernel_time_t sem_otime; __kernel_time_t sem_ctime; struct sem *sem_base; struct sem_queue *sem_pending; struct sem_queue **sem_pending_last; struct sem_undo *undo; unsigned short sem_nsems; };

Se trata de una estructura de control asociada a cada uno de los distintos conjuntos de semáforos existentes en el sistema. Contiene información del sistema, punteros a las operaciones a realizar sobre el grupo, y un puntero hacia las estructuras sem que se almacenan en el núcleo y contienen información de cada semáforo.

Númerode semáforos

del grupo

Sembuf.

struct sembuf { unsigned short sem_num; short sem_op; short sem_flg; };

Se trata de una estructura que se utiliza en semop, y cada dato de este tipo especifica una operación a realizar sobre un semáforo particular dentro del conjunto. Incrementar, decrementar o esperar un valor nulo y por lo tanto se usa en la llamada semop.

Sembuf.

struct sembuf { unsigned short sem_num; short sem_op; short sem_flg; };

Se trata de una estructura que se utiliza en semop, y cada dato de este tipo especifica una operación a realizar sobre un semáforo particular dentro del conjunto. Incrementar, decrementar o esperar un valor nulo y por lo tanto se usa en la llamada semop.

Númerode semáforosen el grupo

Sembuf.

struct sembuf { unsigned short sem_num; short sem_op; short sem_flg; };

Operacionessobre el

semáforo.

Se trata de una estructura que se utiliza en semop, y cada dato de este tipo especifica una operación a realizar sobre un semáforo particular dentro del conjunto. Incrementar, decrementar o esperar un valor nulo y por lo tanto se usa en la llamada semop.

Sembuf.

struct sembuf { unsigned short sem_num; short sem_op; short sem_flg; }; Opciones.

Se trata de una estructura que se utiliza en semop, y cada dato de este tipo especifica una operación a realizar sobre un semáforo particular dentro del conjunto. Incrementar, decrementar o esperar un valor nulo y por lo tanto se usa en la llamada semop.

Semun.

union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad;};

Es una unión, se utiliza en la llamada semctl para almacenar o recuperar informaciones sobre los semáforos.

Semun.

union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad;};

Es una unión, se utiliza en la llamada semctl para almacenar o recuperar informaciones sobre los semáforos.

Valor para SETVAL.

El signo del campo es quien define la acción.

val < 0 op P.val > 0 op V.

Semun.

union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad;};

Es una unión, se utiliza en la llamada semctl para almacenar o recuperar informaciones sobre los semáforos.

Memoria de datos para

IPC_STAT e IPC_SET.

Semun.

union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad;};

Es una unión, se utiliza en la llamada semctl para almacenar o recuperar informaciones sobre los semáforos.

Tabla para GETALL y

SETALL

Semun.

union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad;};

Es una unión, se utiliza en la llamada semctl para almacenar o recuperar informaciones sobre los semáforos.

Memoria de datos para

IPC_INFO

Semun.

union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad;};

Es una unión, se utiliza en la llamada semctl para almacenar o recuperar informaciones sobre los semáforos.

Puntero de alineación

de la estructura

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

No se usan.

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

Número máximo

de grupos de semáforos

(SEMMI = 128)(IPC_INFO)

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

Número máximo de semáforos

(SEMMNS=SEMMI * SEMMSL)(IPC_INFO)

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

Número máximo

de semáforos por grupo

(SEMMSL=32)(IPC_INFO)

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

Número de grupos de semáforos

actualmente Definidos

(SEMINFO)

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

Valor máximo del contador de semáforos

(SEMVMX=32767)(IPC_INFO)

Seminfo.struct seminfo { int semmap; int semmni; int semmns; int semmnu; int semmsl; int semopm; int semume; int semusz; int semvmx; int semaem;};

Almacena información sobre los semáforos, mas concretamente sobre el número de conjunto de semáforos, semáforos declarados, en uso, y los limites.

Número de semáforos

actualmente definidos

(SEMINFO)

LLAMADAS AL SISTEMA

Semget

Semop

Semctl

Semget (1).

Permite la creación de un grupo de semáforos, o bien la recuperación del identificador de un grupo ya existente.

El grupo de semáforos esta unificado bajo un identificador común.

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semget (key_t key, int nsems, int semflg);

Semget (2).

Parámetros:

key : identificador de los semáforos o “clave” para la creación de un nuego grupo de semáforos.

IPC_PRIVATE Key

nsem : cantidad de semáforos en el recurso. semflg: bandera de opciones

IPC_CREAT IPC_EXCL Permisos

Valor retornado:

Éxito identificador del semáforo creado

Error -1 y en errno.

Semget (3).

Descripción: semget devuelve el identificador del semáforo

correspondiente a la clave key. Puede ser un semáforo ya existente O bien semget crea uno nuevo si se da alguno de estos casos:

• key vale IPC_PRIVATE. Este valor especial obliga a semget a crear un nuevo y único identificador, nunca devuelto por ulteriores llamadas a semget hasta que sea liberado con semctl.

• key no está asociada a ningún semáforo existente, y se cumple que (semflg & IPC_CREAT) es cierto.

semflg es una máscara que puede contener IPC_CREAT, que ya hemos visto, o IPC_EXCL, que hace crear el semáforo, pero fracasando si ya existía.

En sus ultimos 9 bits residen los permisos estilo UNIX de acceso al semáforo (usuario, grupo, otros).

Semget (3).

Descripción: semget devuelve el identificador del semáforo

correspondiente a la clave key. Puede ser un semáforo ya existente O bien semget crea uno nuevo si se da alguno de estos casos:

• key vale IPC_PRIVATE. Este valor especial obliga a semget a crear un nuevo y único identificador, nunca devuelto por ulteriores llamadas a semget hasta que sea liberado con semctl.

• key no está asociada a ningún semáforo existente, y se cumple que (semflg & IPC_CREAT) es cierto.

semflg es una máscara que puede contener IPC_CREAT, que ya hemos visto, o IPC_EXCL, que hace crear el semáforo, pero fracasando si ya existía.

En sus ultimos 9 bits residen los permisos estilo UNIX de acceso al semáforo (usuario, grupo, otros).

Semget (4).

int semid = semget ( IPC_PRIVATE, 1, IPC_CREAT | 0744 );

Ejemplo:

Crea un único nuevo semáforo con identificador único con accesos de todos los permisos para el usuario y solo lectura para grupo y otros.

IPC_CREAT está únicamente para asegurar que no está asociada a ningún semáforo existente, aunque no hace falta porque ya IPC_PRIVATE se encarga de eso

Semop (1).

Para realizar las operaciones sobre los semáforos que hay asociados bajo un identificador.

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semop(int semid, struct sembuf *tsops,

unsigned nsops);

Semop (2).

Parámetros:

semid es el identificador del semáforo sops es un apuntador a un vector de operaciones de tipo

sembuf. nsops indica el número de operaciones solicitadas.

Valor retornado:

Éxito El valor del ultimo semáforo sobre el cual se realizó la ultima operación.

Error -1 y en errno el error.

Semop (3).

Descripción:

Si el campo semop de la estrcutura sembuf de una operación es: Semop > 0: Se suma sem_op al valor del semáforo invocado, y despierta a

todos los procesos que esperan a que este valor aumente a dicho valor. (V)

Semop == null: Comprobación del valor del semáforo, si es nulo se bloquea el proceso.

Semp < 0: Disminuye |sem-op| el valor del semáforo, si no es posible entonces bloquea el proceso. Si el valor alcanzado es cero entonces despierta a los procesos correspondientes. (P)

Todas las operaciones deben efectuarse de manera atómica. En los casos en que esto no sea posible:

• El proceso se suspende hasta que sea posible,• Si IPC_NOWAIT está activado en el campo sem_flg de la estructura sembuf en alguna de

las operaciones, se interrumpe sin realizar ninguna operación.

Por cada operación efectuada, se controla si SEM_UNDO está posicionado. Si es así, crea una estructura para conservar el rastro de esa operación y poder

anularla y finalizar la ejecución del proceso.

Semop (3).

Descripción:

Si el campo semop de la estrcutura sembuf de una operación es: Semop > 0: Se suma sem_op al valor del semáforo invocado, y despierta a

todos los procesos que esperan a que este valor aumente a dicho valor. (V)

Semop == null: Comprobación del valor del semáforo, si es nulo se bloquea el proceso.

Semp < 0: Disminuye |sem-op| el valor del semáforo, si no es posible entonces bloquea el proceso. Si el valor alcanzado es cero entonces despierta a los procesos correspondientes. (P)

Todas las operaciones deben efectuarse de manera atómica. En los casos en que esto no sea posible:

• El proceso se suspende hasta que sea posible,• Si IPC_NOWAIT está activado en el campo sem_flg de la estructura sembuf en alguna de

las operaciones, se interrumpe sin realizar ninguna operación.

Por cada operación efectuada, se controla si SEM_UNDO está posicionado. Si es así, crea una estructura para conservar el rastro de esa operación y poder

anularla y finalizar la ejecución del proceso.

Semop (4).

struct sembuf sb = {0, -1, 0};

...

result = semop(semid, &sb, 1);

Realizando una operación P

struct sembuf sb = {0, 1, 0};

...

result = semop(semid, &sb, 1);

Realizando una operación V

Semctl (1).

Esta llamada al sistema permite la consulta, modificación o supresión de un grupo de semáforos.

También permite inicializar los semáforos y obtener información sobre el número de semáforos en espera de aumento.

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd,

union semun arg, unsigned nsops);

Semctl (2).

Parámetros:

semid: identificador resultado de semget()

semnum: semáforo sobre el cual voy a realizar la operación.

arg: parámetro requerido para realizar la operación indicada (parámetro sólo válido para algunas operaciones).

cmd: operación a realizar (ver a continuación)

Valor retornado:

Éxito 0.

Error -1 y en errno el error.

Semctl(3).

Operación a Realizar:

IPC_STAT: carga la estructura semid_ds asociada al recurso en arg

IPC_SET: define los permisos del recurso tomando los valores de arg

GETPID: retorna el identificador del proceso que realiza la última operación.

GETVAL : retorna el valor del semáforo número semnum. GETNCNT: cantidad de procesos esperando que se

incremente el semáforo. GETZCNT : cantidad de procesos esperando que el semáforo

alcance el valor cero. SETVAL: carga el valor del semáforo con arg.val. GETALL: carga el valor de todos los semáforos en arg.array SETALL: carga el valor de todos los semáforos con arg.array IPC_RMID: elimina el recurso compartido.

Semctl(3).

Operación a Realizar:

IPC_STAT: carga la estructura semid_ds asociada al recurso en arg

IPC_SET: define los permisos del recurso tomando los valores de arg

GETPID: retorna el identificador del proceso que realiza la última operación.

GETVAL : retorna el valor del semáforo número semnum. GETNCNT: cantidad de procesos esperando que se

incremente el semáforo. GETZCNT : cantidad de procesos esperando que el semáforo

alcance el valor cero. SETVAL: carga el valor del semáforo con arg.val. GETALL: carga el valor de todos los semáforos en arg.array SETALL: carga el valor de todos los semáforos con arg.array IPC_RMID: elimina el recurso compartido.

Semctl(4).

valor = semctl (semid,semnum,GETVAL);

Lee el valor del semáforo semnum perteneciente al grupo semid

semctl (semid,semnum,SETVAL,nuevo_valor);

Asigna nuevo_valor al semáforo semnum perteneciente al grupo semid

EJEMPLO PRÁCTICO

Ejemplo (1).

#include <sys/ipc.h>

#include <sys/sem.h>

#define PERMISOS 0644

/* crea_sem: abre o crea un semáforo */

int crea_sem (key_t clave, int valor_inicial){

int semid = semget(clave, 1, IPC_CREAT|PERMISOS);

if ( semid == -1 ) return -1;

/* Da el valor inicial al semáforo */

semctl (semid, 0, SETVAL, valor_inicial );

return semid;

}

Ejemplo (2). /* abre_sem: Abrir un semáforo que otro proceso ya creó */

int abre_sem (key_t clave){ return semget(clave,1,0); }

/* Operación P */

void sem_P (int semid){

struct sembuf op_P [] = {0, -1, 0};

/* Decrementa semval o bloquea si cero */

semop ( semid, op_P, 1 );

}

/* Operación V */

void sem_V (int semid) {

struct sembuf op_V [] = {0, 1, 0}

/* Incrementa en 1 el semáforo */

semop ( semid, op_V, 1 );

}

CÓDIGO FUENTEsem_init

findkeynewary

try_semopfreery

sys_semgetsys_semopsys_semctl

“ipc/sem.c//sem_init”

void __init sem_init (void)

{

int i;

sem_lock = NULL;

used_sems = used_semids = max_semid = sem_seq = 0;

for (i = 0; i < SEMMNI; i++)

semary[i] = (struct semid_ds *) IPC_UNUSED;

return;

}

“ipc/sem.c//sem_init”

void __init sem_init (void)

{

int i;

sem_lock = NULL;

used_sems = used_semids = max_semid = sem_seq = 0;

for (i = 0; i < SEMMNI; i++)

semary[i] = (struct semid_ds *) IPC_UNUSED;

return;

}

Valor especial para semary[id] que nos indica que el semáforo no esta siendo usado

“ipc/sem.c//findkey”

static int findkey (key_t key)

{

int id;

struct semid_ds sma;

for (id = 0; id <= max_semid; id++) {

while ((sma = semary[id]) == IPC_NOID)

interruptible_sleep_on (&sem_lock);

if (sma == IPC_UNUSED)

continue;

if (key == sma->sem_perm.key)

return id;

}

return -1;

}

“ipc/sem.c//findkey”

static int findkey (key_t key)

{

int id;

struct semid_ds sma;

for (id = 0; id <= max_semid; id++) {

while ((sma = semary[id]) == IPC_NOID)

interruptible_sleep_on (&sem_lock);

if (sma == IPC_UNUSED)

continue;

if (key == sma->sem_perm.key)

return id;

}

return -1;

}

Espera hasta que se

termine de destruir.

“ipc/sem.c//findkey”

static int findkey (key_t key)

{

int id;

struct semid_ds sma;

for (id = 0; id <= max_semid; id++) {

while ((sma = semary[id]) == IPC_NOID)

interruptible_sleep_on (&sem_lock);

if (sma == IPC_UNUSED)

continue;

if (key == sma->sem_perm.key)

return id;

}

return -1;

}

Si este semáforo no está siendo usado.

“ipc/sem.c//findkey”

static int findkey (key_t key)

{

int id;

struct semid_ds sma;

for (id = 0; id <= max_semid; id++) {

while ((sma = semary[id]) == IPC_NOID)

interruptible_sleep_on (&sem_lock);

if (sma == IPC_UNUSED)

continue;

if (key == sma->sem_perm.key)

return id;

}

return -1;

}

Si coincide con la clave retornamos

su posición.

“ipc/sem.c//findkey”

static int findkey (key_t key)

{

int id;

struct semid_ds sma;

for (id = 0; id <= max_semid; id++) {

while ((sma = semary[id]) == IPC_NOID)

interruptible_sleep_on (&sem_lock);

if (sma == IPC_UNUSED)

continue;

if (key == sma->sem_perm.key)

return id;

}

return -1;

} Si no está siendo usada devuelve un -1.

“ipc/sem.c//newary” (1)

static int newary (key_t key, int nsems, int semflg)

{

int id;

struct semid_ds *sma;

struct ipc_perm *ipcp;

int size;

if (!nsems)

return -EINVAL;

if (used_sems + nsems > SEMMNS)

return -ENOSPC;

for (id = 0; id < SEMMNI; id++)

if (semary[id] == IPC_UNUSED) {

semary[id] = (struct semid_ds *) IPC_NOID;

goto found;

}

return -ENOSPC;

found:

size = sizeof (*sma) + nsems * sizeof (struct sem);

used_sems += nsems;

sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);

“ipc/sem.c//newary” (1)

static int newary (key_t key, int nsems, int semflg)

{

int id;

struct semid_ds *sma;

struct ipc_perm *ipcp;

int size;

if (!nsems)

return -EINVAL;

if (used_sems + nsems > SEMMNS)

return -ENOSPC;

for (id = 0; id < SEMMNI; id++)

if (semary[id] == IPC_UNUSED) {

semary[id] = (struct semid_ds *) IPC_NOID;

goto found;

}

return -ENOSPC;

found:

size = sizeof (*sma) + nsems * sizeof (struct sem);

used_sems += nsems;

sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);

Sobrepasaría el numero de semáforos que puede tener el sistema.

“ipc/sem.c//newary” (1)

static int newary (key_t key, int nsems, int semflg)

{

int id;

struct semid_ds *sma;

struct ipc_perm *ipcp;

int size;

if (!nsems)

return -EINVAL;

if (used_sems + nsems > SEMMNS)

return -ENOSPC;

for (id = 0; id < SEMMNI; id++)

if (semary[id] == IPC_UNUSED) {

semary[id] = (struct semid_ds *) IPC_NOID;

goto found;

}

return -ENOSPC;

found:

size = sizeof (*sma) + nsems * sizeof (struct sem);

used_sems += nsems;

sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);

Localizamos el primero que este libre.

“ipc/sem.c//newary” (1)

static int newary (key_t key, int nsems, int semflg)

{

int id;

struct semid_ds *sma;

struct ipc_perm *ipcp;

int size;

if (!nsems)

return -EINVAL;

if (used_sems + nsems > SEMMNS)

return -ENOSPC;

for (id = 0; id < SEMMNI; id++)

if (semary[id] == IPC_UNUSED) {

semary[id] = (struct semid_ds *) IPC_NOID;

goto found;

}

return -ENOSPC;

found:

size = sizeof (*sma) + nsems * sizeof (struct sem);

used_sems += nsems;

sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);

No se puede crear una tabla nueva.

“ipc/sem.c//newary” (1)

static int newary (key_t key, int nsems, int semflg)

{

int id;

struct semid_ds *sma;

struct ipc_perm *ipcp;

int size;

if (!nsems)

return -EINVAL;

if (used_sems + nsems > SEMMNS)

return -ENOSPC;

for (id = 0; id < SEMMNI; id++)

if (semary[id] == IPC_UNUSED) {

semary[id] = (struct semid_ds *) IPC_NOID;

goto found;

}

return -ENOSPC;

found:

size = sizeof (*sma) + nsems * sizeof (struct sem);

used_sems += nsems;

sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);

Calcula cuanto va a tener de tamaño.

“ipc/sem.c//newary” (2)if (!sma) {

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_sems -= nsems;

wake_up (&sem_lock);

return -ENOMEM;

}

memset (sma, 0, size);

sma->sem_base = (struct sem *) &sma[1];

ipcp = &sma->sem_perm;

ipcp->mode = (semflg & S_IRWXUGO);

ipcp->key = key;

ipcp->cuid = ipcp->uid = current->euid;

ipcp->gid = ipcp->cgid = current->egid;

sma->sem_perm.seq = sem_seq;

sma->sem_pending_last = &sma->sem_pending;

sma->sem_nsems = nsems;

sma->sem_ctime = CURRENT_TIME;

if (id > max_semid)

max_semid = id;

used_semids++;

semary[id] = sma;

wake_up (&sem_lock);

return (unsigned int) sma->sem_perm.seq * SEMMNI + id;

}

“ipc/sem.c//newary” (2)if (!sma) {

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_sems -= nsems;

wake_up (&sem_lock);

return -ENOMEM;

}

memset (sma, 0, size);

sma->sem_base = (struct sem *) &sma[1];

ipcp = &sma->sem_perm;

ipcp->mode = (semflg & S_IRWXUGO);

ipcp->key = key;

ipcp->cuid = ipcp->uid = current->euid;

ipcp->gid = ipcp->cgid = current->egid;

sma->sem_perm.seq = sem_seq;

sma->sem_pending_last = &sma->sem_pending;

sma->sem_nsems = nsems;

sma->sem_ctime = CURRENT_TIME;

if (id > max_semid)

max_semid = id;

used_semids++;

semary[id] = sma;

wake_up (&sem_lock);

return (unsigned int) sma->sem_perm.seq * SEMMNI + id;

}

No hay memoria ¿Pq no se comprueba antes de actualizar variables?

“ipc/sem.c//newary” (2)if (!sma) {

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_sems -= nsems;

wake_up (&sem_lock);

return -ENOMEM;

}

memset (sma, 0, size);

sma->sem_base = (struct sem *) &sma[1];

ipcp = &sma->sem_perm;

ipcp->mode = (semflg & S_IRWXUGO);

ipcp->key = key;

ipcp->cuid = ipcp->uid = current->euid;

ipcp->gid = ipcp->cgid = current->egid;

sma->sem_perm.seq = sem_seq;

sma->sem_pending_last = &sma->sem_pending;

sma->sem_nsems = nsems;

sma->sem_ctime = CURRENT_TIME;

if (id > max_semid)

max_semid = id;

used_semids++;

semary[id] = sma;

wake_up (&sem_lock);

return (unsigned int) sma->sem_perm.seq * SEMMNI + id;

}

Puntero al primer semáforo del grupo.

“ipc/sem.c//newary” (2)if (!sma) {

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_sems -= nsems;

wake_up (&sem_lock);

return -ENOMEM;

}

memset (sma, 0, size);

sma->sem_base = (struct sem *) &sma[1];

ipcp = &sma->sem_perm;

ipcp->mode = (semflg & S_IRWXUGO);

ipcp->key = key;

ipcp->cuid = ipcp->uid = current->euid;

ipcp->gid = ipcp->cgid = current->egid;

sma->sem_perm.seq = sem_seq;

sma->sem_pending_last = &sma->sem_pending;

sma->sem_nsems = nsems;

sma->sem_ctime = CURRENT_TIME;

if (id > max_semid)

max_semid = id;

used_semids++;

semary[id] = sma;

wake_up (&sem_lock);

return (unsigned int) sma->sem_perm.seq * SEMMNI + id;

}

Fecha del ultimo cambio por semctl.

“ipc/sem.c//newary” (2)if (!sma) {

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_sems -= nsems;

wake_up (&sem_lock);

return -ENOMEM;

}

memset (sma, 0, size);

sma->sem_base = (struct sem *) &sma[1];

ipcp = &sma->sem_perm;

ipcp->mode = (semflg & S_IRWXUGO);

ipcp->key = key;

ipcp->cuid = ipcp->uid = current->euid;

ipcp->gid = ipcp->cgid = current->egid;

sma->sem_perm.seq = sem_seq;

sma->sem_pending_last = &sma->sem_pending;

sma->sem_nsems = nsems;

sma->sem_ctime = CURRENT_TIME;

if (id > max_semid)

max_semid = id;

used_semids++;

semary[id] = sma;

wake_up (&sem_lock);

return (unsigned int) sma->sem_perm.seq * SEMMNI + id;

}

Fecha del ultimo cambio por semctl.

“ipc/sem.c//try_semop” (1)static int try_atomic_semop (struct semid_ds * sma, struct sembuf * sops,

int nsops, struct sem_undo *un, int pid, int do_undo)

{

int result, sem_op;

struct sembuf *sop;

struct sem * curr;

for (sop = sops; sop < sops + nsops; sop++) {

curr = sma->sem_base + sop->sem_num;

sem_op = sop->sem_op;

if (!sem_op && curr->semval)

goto would_block;

curr->sempid = (curr->sempid << 16) | pid;

curr->semval += sem_op;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] -= sem_op;

if (curr->semval < 0)

goto would_block;

if (curr->semval > SEMVMX)

goto out_of_range;

}

“ipc/sem.c//try_semop” (1)static int try_atomic_semop (struct semid_ds * sma, struct sembuf * sops,

int nsops, struct sem_undo *un, int pid, int do_undo)

{

int result, sem_op;

struct sembuf *sop;

struct sem * curr;

for (sop = sops; sop < sops + nsops; sop++) {

curr = sma->sem_base + sop->sem_num;

sem_op = sop->sem_op;

if (!sem_op && curr->semval)

goto would_block;

curr->sempid = (curr->sempid << 16) | pid;

curr->semval += sem_op;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] -= sem_op;

if (curr->semval < 0)

goto would_block;

if (curr->semval > SEMVMX)

goto out_of_range;

}

Se inicializa sop y se itera tantas veces nsops

“ipc/sem.c//try_semop” (1)static int try_atomic_semop (struct semid_ds * sma, struct sembuf * sops,

int nsops, struct sem_undo *un, int pid, int do_undo)

{

int result, sem_op;

struct sembuf *sop;

struct sem * curr;

for (sop = sops; sop < sops + nsops; sop++) {

curr = sma->sem_base + sop->sem_num;

sem_op = sop->sem_op;

if (!sem_op && curr->semval)

goto would_block;

curr->sempid = (curr->sempid << 16) | pid;

curr->semval += sem_op;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] -= sem_op;

if (curr->semval < 0)

goto would_block;

if (curr->semval > SEMVMX)

goto out_of_range;

}

sem_op == 0 quiere esperar a que curr->semval llegue a cero por lo que si no éste ultimo no es cero

tendrá que bloquearse.

“ipc/sem.c//try_semop” (1)static int try_atomic_semop (struct semid_ds * sma, struct sembuf * sops,

int nsops, struct sem_undo *un, int pid, int do_undo)

{

int result, sem_op;

struct sembuf *sop;

struct sem * curr;

for (sop = sops; sop < sops + nsops; sop++) {

curr = sma->sem_base + sop->sem_num;

sem_op = sop->sem_op;

if (!sem_op && curr->semval)

goto would_block;

curr->sempid = (curr->sempid << 16) | pid;

curr->semval += sem_op;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] -= sem_op;

if (curr->semval < 0)

goto would_block;

if (curr->semval > SEMVMX)

goto out_of_range;

}

Si SEM_UNDO está seleccionada significa que la operación debe ser deshecha cuando el procesotermine por lo que se actualiza dicha estructura

“ipc/sem.c// try_semop” (2)if (do_undo){

sop--;

result = 0;

goto undo;

}

sma->sem_otime = CURRENT_TIME; /* Valor de tocado */

return 0;

out_of_range:

result = -ERANGE;

goto undo;

would_block:

if (sop->sem_flg & IPC_NOWAIT)

result = -EAGAIN;

else

result = 1;

undo:

while (sop >= sops) {

curr = sma->sem_base + sop->sem_num;

curr->semval -= sop->sem_op;

curr->sempid >>= 16;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] += sop->sem_op;

sop--;

}

return result;

}

“ipc/sem.c// try_semop” (2)if (do_undo){

sop--;

result = 0;

goto undo;

}

sma->sem_otime = CURRENT_TIME; /* Valor de tocado */

return 0;

out_of_range:

result = -ERANGE;

goto undo;

would_block:

if (sop->sem_flg & IPC_NOWAIT)

result = -EAGAIN;

else

result = 1;

undo:

while (sop >= sops) {

curr = sma->sem_base + sop->sem_num;

curr->semval -= sop->sem_op;

curr->sempid >>= 16;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] += sop->sem_op;

sop--;

}

return result;

}

El bucle terminó por lo que todas las operaciones fueron exitosas. Si el proceso llamante quiere saber si son exitosas pero no desarrollarlas

entonces las operaciones son deshechas.

“ipc/sem.c// try_semop” (2)if (do_undo){

sop--;

result = 0;

goto undo;

}

sma->sem_otime = CURRENT_TIME; /* Valor de tocado */

return 0;

out_of_range:

result = -ERANGE;

goto undo;

would_block:

if (sop->sem_flg & IPC_NOWAIT)

result = -EAGAIN;

else

result = 1;

undo:

while (sop >= sops) {

curr = sma->sem_base + sop->sem_num;

curr->semval -= sop->sem_op;

curr->sempid >>= 16;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] += sop->sem_op;

sop--;

}

return result;

}

Ocurre cuando una operación modificó el valor de semval

por encima de su valor máximo

“ipc/sem.c// try_semop” (2)if (do_undo){

sop--;

result = 0;

goto undo;

}

sma->sem_otime = CURRENT_TIME; /* Valor de tocado */

return 0;

out_of_range:

result = -ERANGE;

goto undo;

would_block:

if (sop->sem_flg & IPC_NOWAIT)

result = -EAGAIN;

else

result = 1;

undo:

while (sop >= sops) {

curr = sma->sem_base + sop->sem_num;

curr->semval -= sop->sem_op;

curr->sempid >>= 16;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] += sop->sem_op;

sop--;

}

return result;

}

El proceso debe esperar en un semáforo, o bien a que llegue a cero o bien porque lo requiere inmediatamente,

saliendo con un error en este ultimo caso.

“ipc/sem.c// try_semop” (2)if (do_undo){

sop--;

result = 0;

goto undo;

}

sma->sem_otime = CURRENT_TIME; /* Valor de tocado */

return 0;

out_of_range:

result = -ERANGE;

goto undo;

would_block:

if (sop->sem_flg & IPC_NOWAIT)

result = -EAGAIN;

else

result = 1;

undo:

while (sop >= sops) {

curr = sma->sem_base + sop->sem_num;

curr->semval -= sop->sem_op;

curr->sempid >>= 16;

if (sop->sem_flg & SEM_UNDO)

un->semadj[sop->sem_num] += sop->sem_op;

sop--;

}

return result;

}

Deshace todo el trabajo hecho en el primer bucle.

“ipc/sem.c//freery”static void freeary (int id)

{

struct semid_ds *sma = semary[id];

struct sem_undo *un;

struct sem_queue *q;

sma->sem_perm.seq++;

sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI);

used_sems -= sma->sem_nsems;

if (id == max_semid)

while (max_semid &&

(semary[--max_semid] == IPC_UNUSED));

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_semids--;

for (un = sma->undo; un; un = un->id_next)

un->semid = -1;

for (q = sma->sem_pending; q; q = q->next) {

q->status = -EIDRM;

q->prev = NULL;

wake_up_interruptible(&q->sleeper);

}

kfree(sma);

}

“ipc/sem.c//freery”static void freeary (int id)

{

struct semid_ds *sma = semary[id];

struct sem_undo *un;

struct sem_queue *q;

sma->sem_perm.seq++;

sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI);

used_sems -= sma->sem_nsems;

if (id == max_semid)

while (max_semid &&

(semary[--max_semid] == IPC_UNUSED));

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_semids--;

for (un = sma->undo; un; un = un->id_next)

un->semid = -1;

for (q = sma->sem_pending; q; q = q->next) {

q->status = -EIDRM;

q->prev = NULL;

wake_up_interruptible(&q->sleeper);

}

kfree(sma);

}

Invalida este grupo de semáforos.

“ipc/sem.c//freery”static void freeary (int id)

{

struct semid_ds *sma = semary[id];

struct sem_undo *un;

struct sem_queue *q;

sma->sem_perm.seq++;

sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI);

used_sems -= sma->sem_nsems;

if (id == max_semid)

while (max_semid &&

(semary[--max_semid] == IPC_UNUSED));

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_semids--;

for (un = sma->undo; un; un = un->id_next)

un->semid = -1;

for (q = sma->sem_pending; q; q = q->next) {

q->status = -EIDRM;

q->prev = NULL;

wake_up_interruptible(&q->sleeper);

}

kfree(sma);

}

Incrementa pero evita desbordamiento.

“ipc/sem.c//freery”static void freeary (int id)

{

struct semid_ds *sma = semary[id];

struct sem_undo *un;

struct sem_queue *q;

sma->sem_perm.seq++;

sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI);

used_sems -= sma->sem_nsems;

if (id == max_semid)

while (max_semid &&

(semary[--max_semid] == IPC_UNUSED));

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_semids--;

for (un = sma->undo; un; un = un->id_next)

un->semid = -1;

for (q = sma->sem_pending; q; q = q->next) {

q->status = -EIDRM;

q->prev = NULL;

wake_up_interruptible(&q->sleeper);

}

kfree(sma);

}

Indica que está libre.

“ipc/sem.c//freery”static void freeary (int id)

{

struct semid_ds *sma = semary[id];

struct sem_undo *un;

struct sem_queue *q;

sma->sem_perm.seq++;

sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI);

used_sems -= sma->sem_nsems;

if (id == max_semid)

while (max_semid &&

(semary[--max_semid] == IPC_UNUSED));

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_semids--;

for (un = sma->undo; un; un = un->id_next)

un->semid = -1;

for (q = sma->sem_pending; q; q = q->next) {

q->status = -EIDRM;

q->prev = NULL;

wake_up_interruptible(&q->sleeper);

}

kfree(sma);

}

Invalida la estructura undo asociada a este.

“ipc/sem.c//freery”static void freeary (int id)

{

struct semid_ds *sma = semary[id];

struct sem_undo *un;

struct sem_queue *q;

sma->sem_perm.seq++;

sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI);

used_sems -= sma->sem_nsems;

if (id == max_semid)

while (max_semid &&

(semary[--max_semid] == IPC_UNUSED));

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_semids--;

for (un = sma->undo; un; un = un->id_next)

un->semid = -1;

for (q = sma->sem_pending; q; q = q->next) {

q->status = -EIDRM;

q->prev = NULL;

wake_up_interruptible(&q->sleeper);

}

kfree(sma);

}

Despierta todos los procesos que están esperando

indicando además error EIDRM.

“ipc/sem.c//freery”static void freeary (int id)

{

struct semid_ds *sma = semary[id];

struct sem_undo *un;

struct sem_queue *q;

sma->sem_perm.seq++;

sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI);

used_sems -= sma->sem_nsems;

if (id == max_semid)

while (max_semid &&

(semary[--max_semid] == IPC_UNUSED));

semary[id] = (struct semid_ds *) IPC_UNUSED;

used_semids--;

for (un = sma->undo; un; un = un->id_next)

un->semid = -1;

for (q = sma->sem_pending; q; q = q->next) {

q->status = -EIDRM;

q->prev = NULL;

wake_up_interruptible(&q->sleeper);

}

kfree(sma);

} Libera la memoria asociada.

asmlinkage int sys_semget (key_t key, int nsems, int semflg)

{

int id, err = -EINVAL;

struct semid_ds *sma;

lock_kernel();

if (nsems < 0 || nsems > SEMMSL)

goto out;

if (key == IPC_PRIVATE) {

err = newary (key, nsems, semflg);

} else if ((id = findkey (key)) == -1) {

if (!(semflg & IPC_CREAT))

err = -ENOENT;

else

err = newary (key, nsems, semflg);

}

“ipc/sem.c//sys_semget” (1)

“ipc/sem.c//sys_semget” (1)

asmlinkage int sys_semget (key_t key, int nsems, int semflg)

{

int id, err = -EINVAL;

struct semid_ds *sma;

lock_kernel();

if (nsems < 0 || nsems > SEMMSL)

goto out;

if (key == IPC_PRIVATE) {

err = newary (key, nsems, semflg);

} else if ((id = findkey (key)) == -1) {

if (!(semflg & IPC_CREAT))

err = -ENOENT;

else

err = newary (key, nsems, semflg);

}

SEMMSL es el nº máximo de semáforos por grupo.

“ipc/sem.c//sys_semget” (1)

asmlinkage int sys_semget (key_t key, int nsems, int semflg)

{

int id, err = -EINVAL;

struct semid_ds *sma;

lock_kernel();

if (nsems < 0 || nsems > SEMMSL)

goto out;

if (key == IPC_PRIVATE) {

err = newary (key, nsems, semflg);

} else if ((id = findkey (key)) == -1) {

if (!(semflg & IPC_CREAT))

err = -ENOENT;

else

err = newary (key, nsems, semflg);

}

Se ocupa la primera entrada que se encuentre libre y ninguna llamada semget podrá

devolverla hasta que lo liberemos.

“ipc/sem.c//sys_semget” (1)

asmlinkage int sys_semget (key_t key, int nsems, int semflg)

{

int id, err = -EINVAL;

struct semid_ds *sma;

lock_kernel();

if (nsems < 0 || nsems > SEMMSL)

goto out;

if (key == IPC_PRIVATE) {

err = newary (key, nsems, semflg);

} else if ((id = findkey (key)) == -1) {

if (!(semflg & IPC_CREAT))

err = -ENOENT;

else

err = newary (key, nsems, semflg);

}

Si key tiene un valor no especial, entonces se comprueba que no existe un

grupo de semaforos con esa clave.

“ipc/sem.c//sys_semget” (1)

asmlinkage int sys_semget (key_t key, int nsems, int semflg)

{

int id, err = -EINVAL;

struct semid_ds *sma;

lock_kernel();

if (nsems < 0 || nsems > SEMMSL)

goto out;

if (key == IPC_PRIVATE) {

err = newary (key, nsems, semflg);

} else if ((id = findkey (key)) == -1) {

if (!(semflg & IPC_CREAT))

err = -ENOENT;

else

err = newary (key, nsems, semflg);

}

Se creará si otro proceso no la ha creado ya.

“ipc/sem.c//sys_semget” (2)

else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {

err = -EEXIST;

} else {

sma = semary[id];

if (nsems > sma->sem_nsems)

err = -EINVAL;

else if (ipcperms(&sma->sem_perm, semflg))

err = -EACCES;

else

err = (int) sma->sem_perm.seq * SEMMNI + id;

}

out:

unlock_kernel();

return err;

}

“ipc/sem.c//sys_semget” (2)

else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {

err = -EEXIST;

} else {

sma = semary[id];

if (nsems > sma->sem_nsems)

err = -EINVAL;

else if (ipcperms(&sma->sem_perm, semflg))

err = -EACCES;

else

err = (int) sma->sem_perm.seq * SEMMNI + id;

}

out:

unlock_kernel();

return err;

}

La llamada falla por que el grupo de semáforos ya fue creado.

“ipc/sem.c//sys_semget” (2)

else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {

err = -EEXIST;

} else {

sma = semary[id];

if (nsems > sma->sem_nsems)

err = -EINVAL;

else if (ipcperms(&sma->sem_perm, semflg))

err = -EACCES;

else

err = (int) sma->sem_perm.seq * SEMMNI + id;

}

out:

unlock_kernel();

return err;

}

Se coge el que devuelve find.

“ipc/sem.c//sys_semget” (2)

else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {

err = -EEXIST;

} else {

sma = semary[id];

if (nsems > sma->sem_nsems)

err = -EINVAL;

else if (ipcperms(&sma->sem_perm, semflg))

err = -EACCES;

else

err = (int) sma->sem_perm.seq * SEMMNI + id;

}

out:

unlock_kernel();

return err;

}

El nº de semáforos del grupo es > que el del existente.

“ipc/sem.c//sys_semget” (2)

else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {

err = -EEXIST;

} else {

sma = semary[id];

if (nsems > sma->sem_nsems)

err = -EINVAL;

else if (ipcperms(&sma->sem_perm, semflg))

err = -EACCES;

else

err = (int) sma->sem_perm.seq * SEMMNI + id;

}

out:

unlock_kernel();

return err;

}

Se comprueba que tiene permiso de acceso.

“ipc/sem.c//sys_semget” (2)

else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {

err = -EEXIST;

} else {

sma = semary[id];

if (nsems > sma->sem_nsems)

err = -EINVAL;

else if (ipcperms(&sma->sem_perm, semflg))

err = -EACCES;

else

err = (int) sma->sem_perm.seq * SEMMNI + id;

}

out:

unlock_kernel();

return err;

}

Se comprueba que tiene permiso de acceso.

“ipc/sem.c//sys_semop” (1)

asmlinkage int sys_semop(int semid, struct sembuf *tsops, unsigned nsops)

{

int id, size, error = -EINVAL;

struct semid_ds *sma;

struct sembuf sops[SEMOPM], *sop;

struct sem_undo *un;

int undos = 0, decrease = 0, alter = 0;

struct sem_queue queue;

lock_kernel();

if (nsops < 1 || semid < 0)

goto out;

error = -E2BIG;

if (nsops > SEMOPM)

goto out;

error = -EFAULT;

if(copy_from_user(sops, tsops, nsops * sizeof(*tsops)))

goto out;

id = (unsigned int) semid % SEMMNI;

error = -EINVAL;

if((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)

goto out;

“ipc/sem.c//sys_semop” (1)

asmlinkage int sys_semop(int semid, struct sembuf *tsops, unsigned nsops)

{

int id, size, error = -EINVAL;

struct semid_ds *sma;

struct sembuf sops[SEMOPM], *sop;

struct sem_undo *un;

int undos = 0, decrease = 0, alter = 0;

struct sem_queue queue;

lock_kernel();

if (nsops < 1 || semid < 0)

goto out;

error = -E2BIG;

if (nsops > SEMOPM)

goto out;

error = -EFAULT;

if(copy_from_user(sops, tsops, nsops * sizeof(*tsops)))

goto out;

id = (unsigned int) semid % SEMMNI;

error = -EINVAL;

if((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)

goto out;

Comprueba que los argumentos son validos.

“ipc/sem.c//sys_semop” (1)

asmlinkage int sys_semop(int semid, struct sembuf *tsops,

unsigned nsops)

{

int id, size, error = -EINVAL;

struct semid_ds *sma;

struct sembuf sops[SEMOPM], *sop;

struct sem_undo *un;

int undos = 0, decrease = 0, alter = 0;

struct sem_queue queue;

lock_kernel();

if (nsops < 1 || semid < 0)

goto out;

error = -E2BIG;

if (nsops > SEMOPM)

goto out;

error = -EFAULT;

if(copy_from_user(sops, tsops, nsops * sizeof(*tsops)))

goto out;

id = (unsigned int) semid % SEMMNI;

error = -EINVAL;

if((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)

goto out;

nsop no debe ser superior a SEMOPM, es decir el nº máximo de operaciones permitidas

“ipc/sem.c//sys_semop” (1)

asmlinkage int sys_semop(int semid, struct sembuf *tsops,

unsigned nsops)

{

int id, size, error = -EINVAL;

struct semid_ds *sma;

struct sembuf sops[SEMOPM], *sop;

struct sem_undo *un;

int undos = 0, decrease = 0, alter = 0;

struct sem_queue queue;

lock_kernel();

if (nsops < 1 || semid < 0)

goto out;

error = -E2BIG;

if (nsops > SEMOPM)

goto out;

error = -EFAULT;

if(copy_from_user(sops, tsops, nsops * sizeof(*tsops)))

goto out;

id = (unsigned int) semid % SEMMNI;

error = -EINVAL;

if((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)

goto out;

Copia la descripción de la operación requerida desde el espacio de usuario a un búfer temporal

“ipc/sem.c//sys_semop” (1)

asmlinkage int sys_semop(int semid, struct sembuf *tsops,

unsigned nsops)

{

int id, size, error = -EINVAL;

struct semid_ds *sma;

struct sembuf sops[SEMOPM], *sop;

struct sem_undo *un;

int undos = 0, decrease = 0, alter = 0;

struct sem_queue queue;

lock_kernel();

if (nsops < 1 || semid < 0)

goto out;

error = -E2BIG;

if (nsops > SEMOPM)

goto out;

error = -EFAULT;

if(copy_from_user(sops, tsops, nsops * sizeof(*tsops)))

goto out;

id = (unsigned int) semid % SEMMNI;

error = -EINVAL;

if((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)

goto out;

Índice en el vector y comprueba que está en uso.

“ipc/sem.c//sys_semop” (1)

asmlinkage int sys_semop(int semid, struct sembuf *tsops,

unsigned nsops)

{

int id, size, error = -EINVAL;

struct semid_ds *sma;

struct sembuf sops[SEMOPM], *sop;

struct sem_undo *un;

int undos = 0, decrease = 0, alter = 0;

struct sem_queue queue;

lock_kernel();

if (nsops < 1 || semid < 0)

goto out;

error = -E2BIG;

if (nsops > SEMOPM)

goto out;

error = -EFAULT;

if(copy_from_user(sops, tsops, nsops * sizeof(*tsops)))

goto out;

id = (unsigned int) semid % SEMMNI;

error = -EINVAL;

if((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)

goto out;

Se asegura que la entrada exista en el indicado array de posiciones.

“ipc/sem.c//sys_semop” (2)

error = -EIDRM;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

error = -EFBIG;

for (sop = sops; sop < sops + nsops; sop++) {

if (sop->sem_num >= sma->sem_nsems)

goto out;

if (sop->sem_flg & SEM_UNDO)

undos++;

if (sop->sem_op < 0)

decrease = 1;

if (sop->sem_op > 0)

alter = 1;

}

alter |= decrease;

error = -EACCES;

if(ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out;

“ipc/sem.c//sys_semop” (2)

error = -EIDRM;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

error = -EFBIG;

for (sop = sops; sop < sops + nsops; sop++) {

if (sop->sem_num >= sma->sem_nsems)

goto out;

if (sop->sem_flg & SEM_UNDO)

undos++;

if (sop->sem_op < 0)

decrease = 1;

if (sop->sem_op > 0)

alter = 1;

}

alter |= decrease;

error = -EACCES;

if(ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out;

Se asegura que tiene permiso sobre el semáforo.

“ipc/sem.c//sys_semop” (2)

error = -EIDRM;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

error = -EFBIG;

for (sop = sops; sop < sops + nsops; sop++) {

if (sop->sem_num >= sma->sem_nsems)

goto out;

if (sop->sem_flg & SEM_UNDO)

undos++;

if (sop->sem_op < 0)

decrease = 1;

if (sop->sem_op > 0)

alter = 1;

}

alter |= decrease;

error = -EACCES;

if(ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out;

Cuenta el nº de operaciones cuyo sem_flag

está seleccionado.

“ipc/sem.c//sys_semop” (2)

error = -EIDRM;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

error = -EFBIG;

for (sop = sops; sop < sops + nsops; sop++) {

if (sop->sem_num >= sma->sem_nsems)

goto out;

if (sop->sem_flg & SEM_UNDO)

undos++;

if (sop->sem_op < 0)

decrease = 1;

if (sop->sem_op > 0)

alter = 1;

}

alter |= decrease;

error = -EACCES;

if(ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out;

Bucle para todas las operaciones donde primero chequea que el número de semáforo no esta fuera de rango, rechazandoen caso contrario, dando un error de EFBIG en lugar de EINVAL

que es lo que en teoría debería ser.

“ipc/sem.c//sys_semop” (2)

error = -EIDRM;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

error = -EFBIG;

for (sop = sops; sop < sops + nsops; sop++) {

if (sop->sem_num >= sma->sem_nsems)

goto out;

if (sop->sem_flg & SEM_UNDO)

undos++;

if (sop->sem_op < 0)

decrease = 1;

if (sop->sem_op > 0)

alter = 1;

}

alter |= decrease;

error = -EACCES;

if(ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out;

Decrease indica si alguna operación decrementará el valordel semáforo y alter si alguna lo incrementará.

“ipc/sem.c//sys_semop” (3)

if (undos) {

for (un = current->semundo; un; un = un->proc_next)

if (un->semid == semid)

break;

if (!un) {

size = sizeof(struct sem_undo) +

sizeof(short) * sma->sem_nsems;

un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);

if (!un) {

error = -ENOMEM;

goto out;

}

memset(un, 0, size);

un->semadj = (short *) &un[1];

un->semid = semid;

un->proc_next = current->semundo;

current->semundo = un;

un->id_next = sma->undo;

sma->undo = un;

}

“ipc/sem.c//sys_semop” (3)

if (undos) {

for (un = current->semundo; un; un = un->proc_next)

if (un->semid == semid)

break;

if (!un) {

size = sizeof(struct sem_undo) +

sizeof(short) * sma->sem_nsems;

un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);

if (!un) {

error = -ENOMEM;

goto out;

}

memset(un, 0, size);

un->semadj = (short *) &un[1];

un->semid = semid;

un->proc_next = current->semundo;

current->semundo = un;

un->id_next = sma->undo;

sma->undo = un;

}

Bucle encuentra el conjunto actual de operaciones dejando un puntero.

“ipc/sem.c//sys_semop” (3)

if (undos) {

for (un = current->semundo; un; un = un->proc_next)

if (un->semid == semid)

break;

if (!un) {

size = sizeof(struct sem_undo) +

sizeof(short) * sma->sem_nsems;

un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);

if (!un) {

error = -ENOMEM;

goto out;

}

memset(un, 0, size);

un->semadj = (short *) &un[1];

un->semid = semid;

un->proc_next = current->semundo;

current->semundo = un;

un->id_next = sma->undo;

sma->undo = un;

}

Aun no tiene listo un conjunto para este grupo de

semáforos, entonces uno nuevo es asignado

“ipc/sem.c//sys_semop” (3)

if (undos) {

for (un = current->semundo; un; un = un->proc_next)

if (un->semid == semid)

break;

if (!un) {

size = sizeof(struct sem_undo) +

sizeof(short) * sma->sem_nsems;

un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);

if (!un) {

error = -ENOMEM;

goto out;

}

memset(un, 0, size);

un->semadj = (short *) &un[1];

un->semid = semid;

un->proc_next = current->semundo;

current->semundo = un;

un->id_next = sma->undo;

sma->undo = un;

}

Si no encuentra ninguno, sale.

“ipc/sem.c//sys_semop” (3)

if (undos) {

for (un = current->semundo; un; un = un->proc_next)

if (un->semid == semid)

break;

if (!un) {

size = sizeof(struct sem_undo) +

sizeof(short) * sma->sem_nsems;

un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);

if (!un) {

error = -ENOMEM;

goto out;

}

memset(un, 0, size);

un->semadj = (short *) &un[1];

un->semid = semid;

un->proc_next = current->semundo;

current->semundo = un;

un->id_next = sma->undo;

sma->undo = un;

}

En caso de encontrar uno, indica que es el actual, y que el actual es

el siguiente.

“ipc/sem.c//sys_semop” (4)

} else un = NULL;

error = try_atomic_semop(sma, sops, nsops, un, current->pid, 0);

if (error <= 0)

goto update;

queue.sma = sma;

queue.sops = sops;

queue.nsops = nsops;

queue.undo = un;

queue.pid = current->pid;

queue.alter = decrease;

current->semsleeping = &queue;

if (alter)

append_to_queue(sma ,&queue);

else

prepend_to_queue(sma ,&queue);

“ipc/sem.c//sys_semop” (4)

} else un = NULL;

error = try_atomic_semop(sma, sops, nsops, un, current->pid, 0);

if (error <= 0)

goto update;

queue.sma = sma;

queue.sops = sops;

queue.nsops = nsops;

queue.undo = un;

queue.pid = current->pid;

queue.alter = decrease;

current->semsleeping = &queue;

if (alter)

append_to_queue(sma ,&queue);

else

prepend_to_queue(sma ,&queue);

No hay ningún conjunto de operaciones, entonces se pone a nulo.

“ipc/sem.c//sys_semop” (4)

} else un = NULL;

error = try_atomic_semop(sma, sops, nsops, un, current->pid, 0);

if (error <= 0)

goto update;

queue.sma = sma;

queue.sops = sops;

queue.nsops = nsops;

queue.undo = un;

queue.pid = current->pid;

queue.alter = decrease;

current->semsleeping = &queue;

if (alter)

append_to_queue(sma ,&queue);

else

prepend_to_queue(sma ,&queue);

Llama a try_atomic_semop para que desarrolle todas las operaciones en un solo paso.

“ipc/sem.c//sys_semop” (4)

} else un = NULL;

error = try_atomic_semop(sma, sops, nsops, un, current->pid, 0);

if (error <= 0)

goto update;

queue.sma = sma;

queue.sops = sops;

queue.nsops = nsops;

queue.undo = un;

queue.pid = current->pid;

queue.alter = decrease;

current->semsleeping = &queue;

if (alter)

append_to_queue(sma ,&queue);

else

prepend_to_queue(sma ,&queue);

Si concluye con éxito devuelve un cero y en caso contrario un numero negativo.

“ipc/sem.c//sys_semop” (4)

} else un = NULL;

error = try_atomic_semop(sma, sops, nsops, un, current->pid, 0);

if (error <= 0)

goto update;

queue.sma = sma;

queue.sops = sops;

queue.nsops = nsops;

queue.undo = un;

queue.pid = current->pid;

queue.alter = decrease;

current->semsleeping = &queue;

if (alter)

append_to_queue(sma ,&queue);

else

prepend_to_queue(sma ,&queue);

Si valor positivo, entonces las operaciones no pudieron se realizadas, pero el proceso quiere esperer y

tratarlo después por lo que se encola

rellenando para ello una sem_queued

} else un = NULL;

error = try_atomic_semop(sma, sops, nsops, un, current->pid, 0);

if (error <= 0)

goto update;

queue.sma = sma;

queue.sops = sops;

queue.nsops = nsops;

queue.undo = un;

queue.pid = current->pid;

queue.alter = decrease;

current->semsleeping = &queue;

if (alter)

append_to_queue(sma ,&queue);

else

prepend_to_queue(sma ,&queue);

Los nodos que representan operaciones que modificarán el semáforo son situados al final de la cola, y los nodos que están esperando

a que el valor del semáforo llegue a cero son puestos al principio.

“ipc/sem.c//sys_semop” (4)

“ipc/sem.c//sys_semop” (5) for (;;) { queue.status = -EINTR;

queue.sleeper = NULL;

interruptible_sleep_on(&queue.sleeper);

if (queue.status == 1){

error = try_atomic_semop (sma, sops, nsops, un, current->pid,0);

if (error <= 0)

break;

} else {

error = queue.status;;

if (queue.prev) /* got Interrupt */

break;

current->semsleeping = NULL;

goto out;

}

}

current->semsleeping = NULL;

remove_from_queue(sma,&queue);

update:

if (alter)

update_queue (sma);

out:

unlock_kernel();

return error;

}

“ipc/sem.c//sys_semop” (5) for (;;) { queue.status = -EINTR;

queue.sleeper = NULL;

interruptible_sleep_on(&queue.sleeper);

if (queue.status == 1){

error = try_atomic_semop (sma, sops, nsops, un, current->pid,0);

if (error <= 0)

break;

} else {

error = queue.status;;

if (queue.prev) /* got Interrupt */

break;

current->semsleeping = NULL;

goto out;

}

}

current->semsleeping = NULL;

remove_from_queue(sma,&queue);

update:

if (alter)

update_queue (sma);

out:

unlock_kernel();

return error;

}

Empieza un bucle que repetidamente intenta desarrollar las operaciones, saliendo sólo cuando la requerida operación se haya desarrollado con

éxito o cuando se produzca un error.

“ipc/sem.c//sys_semop” (5) for (;;) { queue.status = -EINTR;

queue.sleeper = NULL;

interruptible_sleep_on(&queue.sleeper);

if (queue.status == 1){

error = try_atomic_semop (sma, sops, nsops, un, current->pid,0);

if (error <= 0)

break;

} else {

error = queue.status;;

if (queue.prev) /* got Interrupt */

break;

current->semsleeping = NULL;

goto out;

}

}

current->semsleeping = NULL;

remove_from_queue(sma,&queue);

update:

if (alter)

update_queue (sma);

out:

unlock_kernel();

return error;

}

Duerme hasta lo despierte un signal o haya algún momento para intentarlo de nuevo.

“ipc/sem.c//sys_semop” (5) for (;;) { queue.status = -EINTR;

queue.sleeper = NULL;

interruptible_sleep_on(&queue.sleeper);

if (queue.status == 1){

error = try_atomic_semop (sma, sops, nsops, un, current->pid,0);

if (error <= 0)

break;

} else {

error = queue.status;;

if (queue.prev) /* got Interrupt */

break;

current->semsleeping = NULL;

goto out;

}

}

current->semsleeping = NULL;

remove_from_queue(sma,&queue);

update:

if (alter)

update_queue (sma);

out:

unlock_kernel();

return error;

}

Si el proceso es despertado ahora tiene una oportunidad

para intentarlo de nuevo.

“ipc/sem.c//sys_semop” (5) for (;;) { queue.status = -EINTR;

queue.sleeper = NULL;

interruptible_sleep_on(&queue.sleeper);

if (queue.status == 1){

error = try_atomic_semop (sma, sops, nsops, un, current->pid,0);

if (error <= 0)

break;

} else {

error = queue.status;;

if (queue.prev) /* got Interrupt */

break;

current->semsleeping = NULL;

goto out;

}

}

current->semsleeping = NULL;

remove_from_queue(sma,&queue);

update:

if (alter)

update_queue (sma);

out:

unlock_kernel();

return error;

}

Quita al proceso de la cola de procesos que están.

“ipc/sem.c//sys_semop” (5) for (;;) { queue.status = -EINTR;

queue.sleeper = NULL;

interruptible_sleep_on(&queue.sleeper);

if (queue.status == 1){

error = try_atomic_semop (sma, sops, nsops, un, current->pid,0);

if (error <= 0)

break;

} else {

error = queue.status;;

if (queue.prev) /* got Interrupt */

break;

current->semsleeping = NULL;

goto out;

}

}

current->semsleeping = NULL;

remove_from_queue(sma,&queue);

update:

if (alter)

update_queue (sma);

out:

unlock_kernel();

return error;

}

Si el conjunto de operaciones alteró la cola es posible que haya modificado las condiciones de otros proceso que estuvieran

esperando, por lo que intenta despertar alguna proceso.

“ipc/sem.c//sys_semop” (5) for (;;) { queue.status = -EINTR;

queue.sleeper = NULL;

interruptible_sleep_on(&queue.sleeper);

if (queue.status == 1){

error = try_atomic_semop (sma, sops, nsops, un, current->pid,0);

if (error <= 0)

break;

} else {

error = queue.status;;

if (queue.prev) /* got Interrupt */

break;

current->semsleeping = NULL;

goto out;

}

}

current->semsleeping = NULL;

remove_from_queue(sma,&queue);

update:

if (alter)

update_queue (sma);

out:

unlock_kernel();

return error;

}

Si el conjunto de operaciones alteró la cola es posible que haya modificado las condiciones de otros proceso que estuvieran

esperando, por lo que intenta despertar alguna proceso.

“ipc/sem.c//sys_semctl” (1)

asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)

{

struct semid_ds *buf = NULL;

struct semid_ds tbuf;

int i, id, val = 0;

struct semid_ds *sma;

struct ipc_perm *ipcp;

struct sem *curr = NULL;

struct sem_undo *un;

unsigned int nsems;

ushort *array = NULL;

ushort sem_io[SEMMSL];

int err = -EINVAL;

lock_kernel();

if (semid < 0 || semnum < 0 || cmd < 0)

goto out;

switch (cmd) {

case IPC_INFO:

“ipc/sem.c//sys_semctl” (1)

asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)

{

struct semid_ds *buf = NULL;

struct semid_ds tbuf;

int i, id, val = 0;

struct semid_ds *sma;

struct ipc_perm *ipcp;

struct sem *curr = NULL;

struct sem_undo *un;

unsigned int nsems;

ushort *array = NULL;

ushort sem_io[SEMMSL];

int err = -EINVAL;

lock_kernel();

if (semid < 0 || semnum < 0 || cmd < 0)

goto out;

switch (cmd) {

case IPC_INFO:

Si hay algún error de parámetro de entrada se sale.

“ipc/sem.c//sys_semctl” (2)

case SEM_INFO:

{

struct seminfo seminfo, *tmp = arg.__buf;

seminfo.semmni = SEMMNI;

seminfo.semmns = SEMMNS;

seminfo.semmsl = SEMMSL;

seminfo.semopm = SEMOPM;

seminfo.semvmx = SEMVMX;

seminfo.semmnu = SEMMNU;

seminfo.semmap = SEMMAP;

seminfo.semume = SEMUME;

seminfo.semusz = SEMUSZ;

seminfo.semaem = SEMAEM;

if (cmd == SEM_INFO) {

seminfo.semusz = used_semids;

seminfo.semaem = used_sems;

}

err = -EFAULT;

if (copy_to_user (tmp, &seminfo, sizeof(struct seminfo)))

goto out;

err = max_semid;

goto out;

}

“ipc/sem.c//sys_semctl” (2)

case SEM_INFO:

{

struct seminfo seminfo, *tmp = arg.__buf;

seminfo.semmni = SEMMNI;

seminfo.semmns = SEMMNS;

seminfo.semmsl = SEMMSL;

seminfo.semopm = SEMOPM;

seminfo.semvmx = SEMVMX;

seminfo.semmnu = SEMMNU;

seminfo.semmap = SEMMAP;

seminfo.semume = SEMUME;

seminfo.semusz = SEMUSZ;

seminfo.semaem = SEMAEM;

if (cmd == SEM_INFO) {

seminfo.semusz = used_semids;

seminfo.semaem = used_sems;

}

err = -EFAULT;

if (copy_to_user (tmp, &seminfo, sizeof(struct seminfo)))

goto out;

err = max_semid;

goto out;

}

Información actual de los semáforos.

“ipc/sem.c//sys_semctl” (2)

case SEM_INFO:

{

struct seminfo seminfo, *tmp = arg.__buf;

seminfo.semmni = SEMMNI;

seminfo.semmns = SEMMNS;

seminfo.semmsl = SEMMSL;

seminfo.semopm = SEMOPM;

seminfo.semvmx = SEMVMX;

seminfo.semmnu = SEMMNU;

seminfo.semmap = SEMMAP;

seminfo.semume = SEMUME;

seminfo.semusz = SEMUSZ;

seminfo.semaem = SEMAEM;

if (cmd == SEM_INFO) {

seminfo.semusz = used_semids;

seminfo.semaem = used_sems;

}

err = -EFAULT;

if (copy_to_user (tmp, &seminfo, sizeof(struct seminfo)))

goto out;

err = max_semid;

goto out;

}

Copia la estructura recién copiada en la memoria de usuario.

“ipc/sem.c//sys_semctl” (3)

case SEM_STAT: buf = arg.buf;

err = -EINVAL;

if (semid > max_semid)

goto out;

sma = semary[semid];

if (sma == IPC_UNUSED || sma == IPC_NOID)

goto out;

err = -EACCES;

if (ipcperms (&sma->sem_perm, S_IRUGO))

goto out;

id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

err = -EFAULT;

if (copy_to_user (buf, &tbuf, sizeof(*buf)) == 0)

err = id;

goto out;

}

“ipc/sem.c//sys_semctl” (3)

case SEM_STAT: buf = arg.buf;

err = -EINVAL;

if (semid > max_semid)

goto out;

sma = semary[semid];

if (sma == IPC_UNUSED || sma == IPC_NOID)

goto out;

err = -EACCES;

if (ipcperms (&sma->sem_perm, S_IRUGO))

goto out;

id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

err = -EFAULT;

if (copy_to_user (buf, &tbuf, sizeof(*buf)) == 0)

err = id;

goto out;

}

Información del semáforo semid.

“ipc/sem.c//sys_semctl” (3)

case SEM_STAT: buf = arg.buf;

err = -EINVAL;

if (semid > max_semid)

goto out;

sma = semary[semid];

if (sma == IPC_UNUSED || sma == IPC_NOID)

goto out;

err = -EACCES;

if (ipcperms (&sma->sem_perm, S_IRUGO))

goto out;

id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

err = -EFAULT;

if (copy_to_user (buf, &tbuf, sizeof(*buf)) == 0)

err = id;

goto out;

}

Comprueba que tiene acceso de lectura.

“ipc/sem.c//sys_semctl” (3)

case SEM_STAT: buf = arg.buf;

err = -EINVAL;

if (semid > max_semid)

goto out;

sma = semary[semid];

if (sma == IPC_UNUSED || sma == IPC_NOID)

goto out;

err = -EACCES;

if (ipcperms (&sma->sem_perm, S_IRUGO))

goto out;

id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

err = -EFAULT;

if (copy_to_user (buf, &tbuf, sizeof(*buf)) == 0)

err = id;

goto out;

}

Copia la estructura recién copiada a la memoria de usuario.

“ipc/sem.c//sys_semctl” (4)

id = (unsigned int) semid % SEMMNI; sma = semary [id];

err = -EINVAL;

if (sma == IPC_UNUSED || sma == IPC_NOID)

goto out;

ipcp = &sma->sem_perm;

nsems = sma->sem_nsems;

err = -EIDRM;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

switch (cmd) {

case GETVAL:

case GETPID:

case GETNCNT:

case GETZCNT:

case SETVAL:

err = -EINVAL;

if (semnum >= nsems)

goto out;

curr = &sma->sem_base[semnum];

break;

}

“ipc/sem.c//sys_semctl” (4)

id = (unsigned int) semid % SEMMNI; sma = semary [id];

err = -EINVAL;

if (sma == IPC_UNUSED || sma == IPC_NOID)

goto out;

ipcp = &sma->sem_perm;

nsems = sma->sem_nsems;

err = -EIDRM;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

switch (cmd) {

case GETVAL:

case GETPID:

case GETNCNT:

case GETZCNT:

case SETVAL:

err = -EINVAL;

if (semnum >= nsems)

goto out;

curr = &sma->sem_base[semnum];

break;

}

Operan en semáforos individuales porlo que primero se chequea semnum y

si está en rango curr apunta al semáforo correspondiente.

“ipc/sem.c//sys_semctl” (5)

switch (cmd) { case GETVAL:

case GETPID:

case GETNCNT:

case GETZCNT:

case GETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

switch (cmd) {

case GETVAL : err = curr->semval; goto out;

case GETPID : err = curr->sempid & 0xffff; goto out;

case GETNCNT: err = count_semncnt(sma,semnum); goto out;

case GETZCNT: err = count_semzcnt(sma,semnum); goto out;

case GETALL:

array = arg.array;

break;

}

break;

“ipc/sem.c//sys_semctl” (5)

switch (cmd) { case GETVAL:

case GETPID:

case GETNCNT:

case GETZCNT:

case GETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

switch (cmd) {

case GETVAL : err = curr->semval; goto out;

case GETPID : err = curr->sempid & 0xffff; goto out;

case GETNCNT: err = count_semncnt(sma,semnum); goto out;

case GETZCNT: err = count_semzcnt(sma,semnum); goto out;

case GETALL:

array = arg.array;

break;

}

break;

Obtiene el valor del semáforo.

“ipc/sem.c//sys_semctl” (5)

switch (cmd) { case GETVAL:

case GETPID:

case GETNCNT:

case GETZCNT:

case GETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

switch (cmd) {

case GETVAL : err = curr->semval; goto out;

case GETPID : err = curr->sempid & 0xffff; goto out;

case GETNCNT: err = count_semncnt(sma,semnum); goto out;

case GETZCNT: err = count_semzcnt(sma,semnum); goto out;

case GETALL:

array = arg.array;

break;

}

break;

El pid.

“ipc/sem.c//sys_semctl” (5)

switch (cmd) { case GETVAL:

case GETPID:

case GETNCNT:

case GETZCNT:

case GETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

switch (cmd) {

case GETVAL : err = curr->semval; goto out;

case GETPID : err = curr->sempid & 0xffff; goto out;

case GETNCNT: err = count_semncnt(sma,semnum); goto out;

case GETZCNT: err = count_semzcnt(sma,semnum); goto out;

case GETALL:

array = arg.array;

break;

}

break;

Número de procesos que esperan valor nulo.

“ipc/sem.c//sys_semctl” (6)

case SETVAL: val = arg.val;

err = -ERANGE;

if (val > SEMVMX || val < 0)

goto out;

break;

case IPC_RMID:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

freeary (id);

err = 0;

goto out;

}

err = -EPERM;

goto out;

case SETALL:

array = arg.array;

err = -EFAULT;

if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))

goto out;

err = 0;

“ipc/sem.c//sys_semctl” (6)

case SETVAL: val = arg.val;

err = -ERANGE;

if (val > SEMVMX || val < 0)

goto out;

break;

case IPC_RMID:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

freeary (id);

err = 0;

goto out;

}

err = -EPERM;

goto out;

case SETALL:

array = arg.array;

err = -EFAULT;

if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))

goto out;

err = 0;

Permite inicializar un semáforo a un valor

determinado que se especifica en arg.

“ipc/sem.c//sys_semctl” (6)

case SETVAL: val = arg.val;

err = -ERANGE;

if (val > SEMVMX || val < 0)

goto out;

break;

case IPC_RMID:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

freeary (id);

err = 0;

goto out;

}

err = -EPERM;

goto out;

case SETALL:

array = arg.array;

err = -EFAULT;

if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))

goto out;

err = 0;

Comprueba que el valor está dentro de los valores posibles.

“ipc/sem.c//sys_semctl” (6)

case SETVAL: val = arg.val;

err = -ERANGE;

if (val > SEMVMX || val < 0)

goto out;

break;

case IPC_RMID:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

freeary (id);

err = 0;

goto out;

}

err = -EPERM;

goto out;

case SETALL:

array = arg.array;

err = -EFAULT;

if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))

goto out;

err = 0;

Liberas el semáforo.

“ipc/sem.c//sys_semctl” (6)

case SETVAL: val = arg.val;

err = -ERANGE;

if (val > SEMVMX || val < 0)

goto out;

break;

case IPC_RMID:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

freeary (id);

err = 0;

goto out;

}

err = -EPERM;

goto out;

case SETALL:

array = arg.array;

err = -EFAULT;

if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))

goto out;

err = 0;

Inicializas todos los semáforos a un valor.

“ipc/sem.c//sys_semctl” (6)

case SETVAL: val = arg.val;

err = -ERANGE;

if (val > SEMVMX || val < 0)

goto out;

break;

case IPC_RMID:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

freeary (id);

err = 0;

goto out;

}

err = -EPERM;

goto out;

case SETALL:

array = arg.array;

err = -EFAULT;

if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))

goto out;

err = 0;

Copia los semáforos al espacio de memoria del usuario y comprueba

que ningún valor supere el máximo.

“ipc/sem.c//sys_semctl” (7)

for (i = 0; i < nsems; i++) if (sem_io[i] > SEMVMX) {

err = -ERANGE;

goto out;

}

break;

case IPC_STAT:

buf = arg.buf;

break;

case IPC_SET:

buf = arg.buf;

err = copy_from_user (&tbuf, buf, sizeof (*buf));

if (err)

err = -EFAULT;

break;

}

err = -EIDRM;

if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)

goto out;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

“ipc/sem.c//sys_semctl” (7)

for (i = 0; i < nsems; i++) if (sem_io[i] > SEMVMX) {

err = -ERANGE;

goto out;

}

break;

case IPC_STAT:

buf = arg.buf;

break;

case IPC_SET:

buf = arg.buf;

err = copy_from_user (&tbuf, buf, sizeof (*buf));

if (err)

err = -EFAULT;

break;

}

err = -EIDRM;

if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)

goto out;

if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)

goto out;

Modificar ciertos valores de la estructura.

“ipc/sem.c//sys_semctl” (8)

case SETVAL: err = -EACCES;

if (ipcperms (ipcp, S_IWUGO))

goto out;

for (un = sma->undo; un; un = un->id_next)

un->semadj[semnum] = 0;

curr->semval = val;

sma->sem_ctime = CURRENT_TIME;

update_queue(sma);

break;

case IPC_SET:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

ipcp->uid = tbuf.sem_perm.uid;

ipcp->gid = tbuf.sem_perm.gid;

ipcp->mode = (ipcp->mode & ~S_IRWXUGO)

| (tbuf.sem_perm.mode & S_IRWXUGO);

sma->sem_ctime = CURRENT_TIME;

err = 0;

goto out;

}

err = -EPERM;

goto out;

“ipc/sem.c//sys_semctl” (8)

case SETVAL: err = -EACCES;

if (ipcperms (ipcp, S_IWUGO))

goto out;

for (un = sma->undo; un; un = un->id_next)

un->semadj[semnum] = 0;

curr->semval = val;

sma->sem_ctime = CURRENT_TIME;

update_queue(sma);

break;

case IPC_SET:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

ipcp->uid = tbuf.sem_perm.uid;

ipcp->gid = tbuf.sem_perm.gid;

ipcp->mode = (ipcp->mode & ~S_IRWXUGO)

| (tbuf.sem_perm.mode & S_IRWXUGO);

sma->sem_ctime = CURRENT_TIME;

err = 0;

goto out;

}

err = -EPERM;

goto out;

Debido a que se le está asignando un nuevo valor,cualquier semnum semáforo es invalidado , para

lo cual el bucle lo pone a cero no tendrán efecto.

“ipc/sem.c//sys_semctl” (8)

case SETVAL: err = -EACCES;

if (ipcperms (ipcp, S_IWUGO))

goto out;

for (un = sma->undo; un; un = un->id_next)

un->semadj[semnum] = 0;

curr->semval = val;

sma->sem_ctime = CURRENT_TIME;

update_queue(sma);

break;

case IPC_SET:

if (current->euid == ipcp->cuid ||

current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {

ipcp->uid = tbuf.sem_perm.uid;

ipcp->gid = tbuf.sem_perm.gid;

ipcp->mode = (ipcp->mode & ~S_IRWXUGO)

| (tbuf.sem_perm.mode & S_IRWXUGO);

sma->sem_ctime = CURRENT_TIME;

err = 0;

goto out;

}

err = -EPERM;

goto out;

Esto solo puede ser ejecutado por un proceso cuyo euid

es igual al del sem_perm.cuid o sem_perm.uid.

“ipc/sem.c//sys_semctl” (9)

case IPC_STAT: err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

if (copy_to_user (buf, &tbuf, sizeof(*buf)))

err = -EFAULT;

break;

case SETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IWUGO))

goto out;

for (i = 0; i < nsems; i++)

sma->sem_base[i].semval = sem_io[i];

for (un = sma->undo; un; un = un->id_next)

for (i = 0; i < nsems; i++)

un->semadj[i] = 0;

sma->sem_ctime = CURRENT_TIME;

update_queue(sma);

break;

“ipc/sem.c//sys_semctl” (9)

case IPC_STAT: err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

if (copy_to_user (buf, &tbuf, sizeof(*buf)))

err = -EFAULT;

break;

case SETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IWUGO))

goto out;

for (i = 0; i < nsems; i++)

sma->sem_base[i].semval = sem_io[i];

for (un = sma->undo; un; un = un->id_next)

for (i = 0; i < nsems; i++)

un->semadj[i] = 0;

sma->sem_ctime = CURRENT_TIME;

update_queue(sma);

break;

Copia la estructura asociada a semid.

“ipc/sem.c//sys_semctl” (9)

case IPC_STAT: err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

if (copy_to_user (buf, &tbuf, sizeof(*buf)))

err = -EFAULT;

break;

case SETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IWUGO))

goto out;

for (i = 0; i < nsems; i++)

sma->sem_base[i].semval = sem_io[i];

for (un = sma->undo; un; un = un->id_next)

for (i = 0; i < nsems; i++)

un->semadj[i] = 0;

sma->sem_ctime = CURRENT_TIME;

update_queue(sma);

break;

Todos los valores de los semáforos son puestos

con el valor del llamante.

“ipc/sem.c//sys_semctl” (9)

case IPC_STAT: err = -EACCES;

if (ipcperms (ipcp, S_IRUGO))

goto out;

tbuf.sem_perm = sma->sem_perm;

tbuf.sem_otime = sma->sem_otime;

tbuf.sem_ctime = sma->sem_ctime;

tbuf.sem_nsems = sma->sem_nsems;

if (copy_to_user (buf, &tbuf, sizeof(*buf)))

err = -EFAULT;

break;

case SETALL:

err = -EACCES;

if (ipcperms (ipcp, S_IWUGO))

goto out;

for (i = 0; i < nsems; i++)

sma->sem_base[i].semval = sem_io[i];

for (un = sma->undo; un; un = un->id_next)

for (i = 0; i < nsems; i++)

un->semadj[i] = 0;

sma->sem_ctime = CURRENT_TIME;

update_queue(sma);

break;Para todo ajuste undo relacionado al semáforo es puesto a cero.

“ipc/sem.c//sys_semctl” (10)

default:

err = -EINVAL;

goto out;

}

err = 0;

out:

unlock_kernel();

return err;

}

“ipc/sem.c//sys_semctl” (10)

default:

err = -EINVAL;

goto out;

}

err = 0;

out:

unlock_kernel();

return err;

}

Operación no reconocida.

“ipc/sem.c//sys_semctl” (10)

default:

err = -EINVAL;

goto out;

}

err = 0;

out:

unlock_kernel();

return err;

}

Operación no reconocida.

FIN.