Descargar la presentación
La descarga está en progreso. Por favor, espere
Publicada porEsther Alarcón Ramos Modificado hace 10 años
1
IPC : SEMÁFOROS. Carmelo Quintana Hernández, a3182@dis.ulpgc.es a3182@dis.ulpgc.es Miguel Ramírez Alemán a3183@dis.ulpgc.es
2
Índice. Conceptos. Conceptos Semáforos Semáforos Tabla de Semáforos. Tabla de Semáforos. Estructuras de Datos. Semid_ds Semid_ds Sembuf Sembuf Semun Semun Seminfo Seminfo Llamadas al Sistema. Semget Semget Semop Semop Semctl Semctl Ejemplo Práctico. Código Fuente.
3
CONCEPTOS Semáforo. Tabla de Semáforos.
4
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.
5
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).
6
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.
7
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.
8
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.
9
Ejemplo para T.S (4). Solución: Las operaciones P y V se efectúan “atómicamente” con una tabla de semáforos.
10
ESTRUCTURAS DE DATOS Semid_ds Sembuf Semun Seminfo
11
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.
12
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
13
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
14
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
15
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
16
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
17
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ón en espera
18
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
19
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úmero de semáforos del grupo
20
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.
21
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úmero de semáforos en el grupo
22
Sembuf. struct sembuf { unsigned short sem_num; short sem_op; short sem_flg; }; Operaciones sobre 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.
23
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.
24
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.
25
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.
26
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.
27
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
28
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
29
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
30
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.
31
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.
32
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)
33
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)
34
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)
35
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)
36
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)
37
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)
38
LLAMADAS AL SISTEMA Semget Semop Semctl
39
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 int semget (key_t key, int nsems, int semflg);
40
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.
41
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).
42
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).
43
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
44
Semop (1). Para realizar las operaciones sobre los semáforos que hay asociados bajo un identificador. #include int semop(int semid, struct sembuf *tsops, unsigned nsops);
45
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.
46
Semop (3). Descripción: Si el campo semop de la estrcutura sembuf de una operación es:sembuf 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.
47
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.
48
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
49
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 int semctl(int semid, int semnum, int cmd, union semun arg, unsigned nsops);
50
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.
51
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.
52
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.
53
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
54
EJEMPLO PRÁCTICO
55
Ejemplo (1). #include #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; }
56
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 ); }
57
CÓDIGO FUENTE sem_init findkey newary try_semop freery sys_semget sys_semop sys_semctl
58
“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; }
59
“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;return } Valor especial para semary[id] que nos indica que el semáforo no esta siendo usado
60
“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; }
61
“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.
62
“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.
63
“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.
64
“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.
65
“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);
66
“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.
67
“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) {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.
68
“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.
69
“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.
70
“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; }
71
“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?
72
“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.
73
“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.
74
“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.
75
“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; }
76
“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
77
“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.
78
“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 proceso termine por lo que se actualiza dicha estructura
79
“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; }
80
“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.
81
“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
82
“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.
83
“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;return } Deshace todo el trabajo hecho en el primer bucle.
84
“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); }
85
“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.
86
“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.
87
“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.
88
“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.
89
“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.
90
“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.
91
asmlinkage int sys_semget (key_t key, int nsems, int semflg) { int id, err = -EINVAL; struct semid_ds *sma; lock_kernel(); if (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)
92
asmlinkage int sys_semget (key_t key, int nsems, int semflg) { int id, err = -EINVAL; struct semid_ds *sma; lock_kernel(); if (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.
93
“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 SEMMSL) goto out; if (key == IPC_PRIVATE) { err = newary (key, nsems, semflg);newary } 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.
94
“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 SEMMSL) goto out; if (key == IPC_PRIVATE) { err = newary (key, nsems, semflg); } else if ((id = findkey (key)) == -1) {findkey 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.
95
“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 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.
96
“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; }
97
“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.
98
“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.
99
“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.
100
“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.
101
“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.
102
“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;
103
“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.
104
“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
105
“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
106
“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.
107
“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.
108
“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;
109
“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.
110
“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.
111
“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, rechazando en caso contrario, dando un error de EFBIG en lugar de EINVAL que es lo que en teoría debería ser.
112
“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 valor del semáforo y alter si alguna lo incrementará.
113
“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; }
114
“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.
115
“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
116
“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.
117
“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.
118
“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);
119
“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.
120
“ipc/sem.c//sys_semop” (4) } else un = NULL; error = try_atomic_semop(sma, sops, nsops, un, current->pid, 0);try_atomic_semop 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.
121
“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.
122
“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
123
} 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)
124
“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; }
125
“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.
126
“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.
127
“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.
128
“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.
129
“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.
130
“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.
131
“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:
132
“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.
133
“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; }
134
“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.
135
“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.
136
“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; }
137
“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.
138
“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.
139
“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.
140
“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; }
141
“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 por lo que primero se chequea semnum y si está en rango curr apunta al semáforo correspondiente.
142
“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;
143
“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.
144
“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.
145
“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.
146
“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;
147
“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.
148
“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.
149
“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);freeary 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.
150
“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.
151
“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.
152
“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;
153
“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.
154
“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;
155
“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.
156
“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.
157
“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;
158
“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.
159
“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.
160
“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.
161
“ipc/sem.c//sys_semctl” (10) default: err = -EINVAL; goto out; } err = 0; out: unlock_kernel(); return err; }
162
“ipc/sem.c//sys_semctl” (10) default: err = -EINVAL; goto out; } err = 0; out: unlock_kernel(); return err; } Operación no reconocida.
163
“ipc/sem.c//sys_semctl” (10) default: err = -EINVAL; goto out; } err = 0; out: unlock_kernel(); return err; } Operación no reconocida.
164
FIN.
Presentaciones similares
© 2025 SlidePlayer.es Inc.
All rights reserved.