Upload
esther-alarcon-ramos
View
220
Download
0
Embed Size (px)
Citation preview
IPC : SEMÁFOROS.
Carmelo Quintana Hernández, [email protected]
Miguel Ramírez Alemá[email protected]
Í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.